-/* File: save.c */
-
-/* Purpose: interact with savefiles */
-
-#include "angband.h"
-
-
-#ifdef FUTURE_SAVEFILES
-
-/*
- * XXX XXX XXX Ignore this for now...
- *
- * The basic format of Angband 2.8.0 (and later) savefiles is simple.
- *
- * The savefile itself is a "header" (4 bytes) plus a series of "blocks",
- * plus, perhaps, some form of "footer" at the end.
- *
- * The "header" contains information about the "version" of the savefile.
- * Conveniently, pre-2.8.0 savefiles also use a 4 byte header, though the
- * interpretation of the "sf_extra" byte is very different. Unfortunately,
- * savefiles from Angband 2.5.X reverse the sf_major and sf_minor fields,
- * and must be handled specially, until we decide to start ignoring them.
- *
- * Each "block" is a "type" (2 bytes), plus a "size" (2 bytes), plus "data",
- * plus a "check" (2 bytes), plus a "stamp" (2 bytes). The format of the
- * "check" and "stamp" bytes is still being contemplated, but it would be
- * nice for one to be a simple byte-checksum, and the other to be a complex
- * additive checksum of some kind. Both should be zero if the block is empty.
- *
- * Standard types:
- * TYPE_BIRTH --> creation info
- * TYPE_OPTIONS --> option settings
- * TYPE_MESSAGES --> message recall
- * TYPE_PLAYER --> player information
- * TYPE_SPELLS --> spell information
- * TYPE_INVEN --> player inven/equip
- * TYPE_STORES --> store information
- * TYPE_RACES --> monster race data
- * TYPE_KINDS --> object kind data
- * TYPE_UNIQUES --> unique info
- * TYPE_ARTIFACTS --> artifact info
- * TYPE_QUESTS --> quest info
- *
- * Dungeon information:
- * TYPE_DUNGEON --> dungeon info
- * TYPE_FEATURES --> dungeon features
- * TYPE_OBJECTS --> dungeon objects
- * TYPE_MONSTERS --> dungeon monsters
- *
- * Conversions:
- * Break old "races" into normals/uniques
- * Extract info about the "unique" monsters
- *
- * Question:
- * Should there be a single "block" for info about all the stores, or one
- * "block" for each store? Or one "block", which contains "sub-blocks" of
- * some kind? Should we dump every "sub-block", or just the "useful" ones?
- *
- * Question:
- * Should the normals/uniques be broken for 2.8.0, or should 2.8.0 simply
- * be a "fixed point" into which older savefiles are converted, and then
- * future versions could ignore older savefiles, and the "conversions"
- * would be much simpler.
- */
-
-
-/*
- * XXX XXX XXX
- */
-#define TYPE_OPTIONS 17362
-
-
-/*
- * Hack -- current savefile
- */
-static int data_fd = -1;
-
-
-/*
- * Hack -- current block type
- */
-static u16b data_type;
-
-/*
- * Hack -- current block size
- */
-static u16b data_size;
-
-/*
- * Hack -- pointer to the data buffer
+/*!
+ * @file save.c
+ * @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
+ * @date 2014/07/12
+ * @author
+ * <pre>
+ * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
+ * This software may be copied and distributed for educational, research,
+ * and not for profit purposes provided that this copyright and statement
+ * are included in all such copies. Other copyrights may also apply.
+ * </pre>
*/
-static byte *data_head;
-
-/*
- * Hack -- pointer into the data buffer
- */
-static byte *data_next;
-
-
-
-/*
- * Hack -- write the current "block" to the savefile
- */
-static errr wr_block(void)
-{
- errr err;
-
- byte fake[4];
-
- /* Save the type and size */
- fake[0] = (byte)(data_type);
- fake[1] = (byte)(data_type >> 8);
- fake[2] = (byte)(data_size);
- fake[3] = (byte)(data_size >> 8);
-
- /* Dump the head */
- err = fd_write(data_fd, (char*)&fake, 4);
-
- /* Dump the actual data */
- err = fd_write(data_fd, (char*)data_head, data_size);
-
- /* XXX XXX XXX */
- fake[0] = 0;
- fake[1] = 0;
- fake[2] = 0;
- fake[3] = 0;
-
- /* Dump the tail */
- err = fd_write(data_fd, (char*)&fake, 4);
-
- /* Hack -- reset */
- data_next = data_head;
-
- /* Wipe the data block */
- C_WIPE(data_head, 65535, byte);
-
- /* Success */
- return (0);
-}
-
-
-
-/*
- * Hack -- add data to the current block
- */
-static void put_byte(byte v)
-{
- *data_next++ = v;
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_char(char v)
-{
- put_byte((byte)(v));
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_u16b(u16b v)
-{
- *data_next++ = (byte)(v);
- *data_next++ = (byte)(v >> 8);
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_s16b(s16b v)
-{
- put_u16b((u16b)(v));
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_u32b(u32b v)
-{
- *data_next++ = (byte)(v);
- *data_next++ = (byte)(v >> 8);
- *data_next++ = (byte)(v >> 16);
- *data_next++ = (byte)(v >> 24);
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_s32b(s32b v)
-{
- put_u32b((u32b)(v));
-}
-
-/*
- * Hack -- add data to the current block
- */
-static void put_string(char *str)
-{
- while ((*data_next++ = *str++) != '\0');
-}
-
-
-
-/*
- * Write a savefile for Angband 2.8.0
- */
-static errr wr_savefile(void)
-{
- int i;
-
- u32b now;
-
- byte tmp8u;
- u16b tmp16u;
-
- errr err;
-
- byte fake[4];
-
-
- /*** Hack -- extract some data ***/
-
- /* Hack -- Acquire the current time */
- now = time((time_t*)(NULL));
-
- /* Note the operating system */
- sf_xtra = 0L;
-
- /* Note when the file was saved */
- sf_when = now;
-
- /* Note the number of saves */
- sf_saves++;
-
-
- /*** Actually write the file ***/
-
- /* Open the file XXX XXX XXX */
- data_fd = -1;
-
- /* Dump the version */
- fake[0] = (byte)(FAKE_VER_MAJOR);
- fake[1] = (byte)(FAKE_VER_MINOR);
- fake[2] = (byte)(FAKE_VER_PATCH);
- fake[3] = (byte)(VERSION_EXTRA);
-
-
- /* Dump the data */
- err = fd_write(data_fd, (char*)&fake, 4);
-
-
- /* Make array XXX XXX XXX */
- C_MAKE(data_head, 65535, byte);
-
- /* Hack -- reset */
- data_next = data_head;
-
- /* Dump the "options" */
- put_options();
-
- /* Set the type */
- data_type = TYPE_OPTIONS;
-
- /* Set the "options" size */
- data_size = (data_next - data_head);
-
- /* Write the block */
- wr_block();
-
- /* XXX XXX XXX */
-
- /* Dump the "final" marker XXX XXX XXX */
- /* Type zero, Size zero, Contents zero, etc */
-
-
- /* XXX XXX XXX Check for errors */
-
-
- /* Kill array XXX XXX XXX */
- C_KILL(data_head, 65535, byte);
-
-
- /* Success */
- return (0);
-}
-
-
-
-
-
-/*
- * Hack -- read the next "block" from the savefile
- */
-static errr rd_block(void)
-{
- errr err;
-
- byte fake[4];
-
- /* Read the head data */
- err = fd_read(data_fd, (char*)&fake, 4);
-
- /* Extract the type and size */
- data_type = (fake[0] | ((u16b)fake[1] << 8));
- data_size = (fake[2] | ((u16b)fake[3] << 8));
-
- /* Wipe the data block */
- C_WIPE(data_head, 65535, byte);
-
- /* Read the actual data */
- err = fd_read(data_fd, (char*)data_head, data_size);
-
- /* Read the tail data */
- err = fd_read(data_fd, (char*)&fake, 4);
-
- /* XXX XXX XXX Verify */
-
- /* Hack -- reset */
- data_next = data_head;
-
- /* Success */
- return (0);
-}
-
-
-/*
- * Hack -- get data from the current block
- */
-static void get_byte(byte *ip)
-{
- byte d1;
- d1 = (*data_next++);
- (*ip) = (d1);
-}
-
-/*
- * Hack -- get data from the current block
- */
-static void get_char(char *ip)
-{
- get_byte((byte*)ip);
-}
-
-/*
- * Hack -- get data from the current block
- */
-static void get_u16b(u16b *ip)
-{
- u16b d0, d1;
- d0 = (*data_next++);
- d1 = (*data_next++);
- (*ip) = (d0 | (d1 << 8));
-}
-
-/*
- * Hack -- get data from the current block
- */
-static void get_s16b(s16b *ip)
-{
- get_u16b((u16b*)ip);
-}
-
-/*
- * Hack -- get data from the current block
- */
-static void get_u32b(u32b *ip)
-{
- u32b d0, d1, d2, d3;
- d0 = (*data_next++);
- d1 = (*data_next++);
- d2 = (*data_next++);
- d3 = (*data_next++);
- (*ip) = (d0 | (d1 << 8) | (d2 << 16) | (d3 << 24));
-}
-
-/*
- * Hack -- get data from the current block
- */
-static void get_s32b(s32b *ip)
-{
- get_u32b((u32b*)ip);
-}
-
-
-
-/*
- * Read a savefile for Angband 2.8.0
- */
-static errr rd_savefile(void)
-{
- bool done = FALSE;
-
- byte fake[4];
-
-
- /* Open the savefile */
- data_fd = fd_open(savefile, O_RDONLY);
-
- /* No file */
- if (data_fd < 0) return (1);
-
- /* Strip the first four bytes (see below) */
- if (fd_read(data_fd, (char*)(fake), 4)) return (1);
-
-
- /* Make array XXX XXX XXX */
- C_MAKE(data_head, 65535, byte);
-
- /* Hack -- reset */
- data_next = data_head;
-
-
- /* Read blocks */
- while (!done)
- {
- /* Read the block */
- if (rd_block()) break;
-
- /* Analyze the type */
- switch (data_type)
- {
- /* Done XXX XXX XXX */
- case 0:
- {
- done = TRUE;
- break;
- }
-
- /* Grab the options */
- case TYPE_OPTIONS:
- {
- if (get_options()) err = -1;
- break;
- }
- }
-
- /* XXX XXX XXX verify "data_next" */
- if (data_next - data_head > data_size) break;
- }
-
-
- /* XXX XXX XXX Check for errors */
-
-
- /* Kill array XXX XXX XXX */
- C_KILL(data_head, 65535, byte);
-
-
- /* Success */
- return (0);
-}
-
-
-#endif /* FUTURE_SAVEFILES */
+#include "angband.h"
-/*
- * These functions place information into a savefile a byte at a time
+/*!
+ * @brief 1バイトをファイルに書き込む / These functions place information into a savefile a byte at a time
+ * @param v 書き込むバイト値
+ * @return なし
*/
-
static void sf_put(byte v)
{
/* Encode the value, write a character */
x_stamp += xor_byte;
}
+/*!
+ * @brief 1バイトをファイルに書き込む(sf_put()の糖衣)
+ * @param v 書き込むバイト
+ * @return なし
+ */
static void wr_byte(byte v)
{
sf_put(v);
}
+/*!
+ * @brief 符号なし16ビットをファイルに書き込む
+ * @param v 書き込む符号なし16bit値
+ * @return なし
+ */
static void wr_u16b(u16b v)
{
sf_put((byte)(v & 0xFF));
sf_put((byte)((v >> 8) & 0xFF));
}
+/*!
+ * @brief 符号あり16ビットをファイルに書き込む
+ * @param v 書き込む符号あり16bit値
+ * @return なし
+ */
static void wr_s16b(s16b v)
{
wr_u16b((u16b)v);
}
+/*!
+ * @brief 符号なし32ビットをファイルに書き込む
+ * @param v 書き込む符号なし32bit値
+ * @return なし
+ */
static void wr_u32b(u32b v)
{
sf_put((byte)(v & 0xFF));
sf_put((byte)((v >> 24) & 0xFF));
}
+/*!
+ * @brief 符号あり32ビットをファイルに書き込む
+ * @param v 書き込む符号あり32bit値
+ * @return なし
+ */
static void wr_s32b(s32b v)
{
wr_u32b((u32b)v);
}
+/*!
+ * @brief 文字列をファイルに書き込む
+ * @param str 書き込む文字列
+ * @return なし
+ */
static void wr_string(cptr str)
{
while (*str)
*/
-/*
- * Write an "item" record
+/*!
+ * @brief アイテムオブジェクトを書き込む / Write an "item" record
+ * @param o_ptr アイテムオブジェクト保存元ポインタ
+ * @return なし
*/
static void wr_item(object_type *o_ptr)
{
+ u32b flags = 0x00000000;
+
+ if (o_ptr->pval) flags |= SAVE_ITEM_PVAL;
+ if (o_ptr->discount) flags |= SAVE_ITEM_DISCOUNT;
+ if (o_ptr->number != 1) flags |= SAVE_ITEM_NUMBER;
+ if (o_ptr->name1) flags |= SAVE_ITEM_NAME1;
+ if (o_ptr->name2) flags |= SAVE_ITEM_NAME2;
+ if (o_ptr->timeout) flags |= SAVE_ITEM_TIMEOUT;
+ if (o_ptr->to_h) flags |= SAVE_ITEM_TO_H;
+ if (o_ptr->to_d) flags |= SAVE_ITEM_TO_D;
+ if (o_ptr->to_a) flags |= SAVE_ITEM_TO_A;
+ if (o_ptr->ac) flags |= SAVE_ITEM_AC;
+ if (o_ptr->dd) flags |= SAVE_ITEM_DD;
+ if (o_ptr->ds) flags |= SAVE_ITEM_DS;
+ if (o_ptr->ident) flags |= SAVE_ITEM_IDENT;
+ if (o_ptr->marked) flags |= SAVE_ITEM_MARKED;
+ if (o_ptr->art_flags[0]) flags |= SAVE_ITEM_ART_FLAGS0;
+ if (o_ptr->art_flags[1]) flags |= SAVE_ITEM_ART_FLAGS1;
+ if (o_ptr->art_flags[2]) flags |= SAVE_ITEM_ART_FLAGS2;
+ if (o_ptr->art_flags[3]) flags |= SAVE_ITEM_ART_FLAGS3;
+ if (o_ptr->art_flags[4]) flags |= SAVE_ITEM_ART_FLAGS4;
+ if (o_ptr->curse_flags) flags |= SAVE_ITEM_CURSE_FLAGS;
+ if (o_ptr->held_m_idx) flags |= SAVE_ITEM_HELD_M_IDX;
+ if (o_ptr->xtra1) flags |= SAVE_ITEM_XTRA1;
+ if (o_ptr->xtra2) flags |= SAVE_ITEM_XTRA2;
+ if (o_ptr->xtra3) flags |= SAVE_ITEM_XTRA3;
+ if (o_ptr->xtra4) flags |= SAVE_ITEM_XTRA4;
+ if (o_ptr->xtra5) flags |= SAVE_ITEM_XTRA5;
+ if (o_ptr->feeling) flags |= SAVE_ITEM_FEELING;
+ if (o_ptr->inscription) flags |= SAVE_ITEM_INSCRIPTION;
+ if (o_ptr->art_name) flags |= SAVE_ITEM_ART_NAME;
+
+ /*** Item save flags ***/
+ wr_u32b(flags);
+
+ /*** Write only un-obvious elements ***/
wr_s16b(o_ptr->k_idx);
/* Location */
- wr_byte(o_ptr->iy);
- wr_byte(o_ptr->ix);
+ wr_byte((byte_hack)o_ptr->iy);
+ wr_byte((byte_hack)o_ptr->ix);
- wr_byte(o_ptr->tval);
- wr_byte(o_ptr->sval);
- wr_s16b(o_ptr->pval);
+ if (flags & SAVE_ITEM_PVAL) wr_s16b(o_ptr->pval);
- wr_byte(o_ptr->discount);
- wr_byte(o_ptr->number);
- wr_s16b(o_ptr->weight);
+ if (flags & SAVE_ITEM_DISCOUNT) wr_byte(o_ptr->discount);
+ if (flags & SAVE_ITEM_NUMBER) wr_byte((byte_hack)o_ptr->number);
- wr_byte(o_ptr->name1);
- wr_byte(o_ptr->name2);
- wr_s16b(o_ptr->timeout);
+ wr_s16b((s16b)o_ptr->weight);
- wr_s16b(o_ptr->to_h);
- wr_s16b(o_ptr->to_d);
- wr_s16b(o_ptr->to_a);
- wr_s16b(o_ptr->ac);
- wr_byte(o_ptr->dd);
- wr_byte(o_ptr->ds);
+ if (flags & SAVE_ITEM_NAME1) wr_byte((byte_hack)o_ptr->name1);
+ if (flags & SAVE_ITEM_NAME2) wr_byte((byte_hack)o_ptr->name2);
+ if (flags & SAVE_ITEM_TIMEOUT) wr_s16b(o_ptr->timeout);
- wr_byte(o_ptr->ident);
+ if (flags & SAVE_ITEM_TO_H) wr_s16b(o_ptr->to_h);
+ if (flags & SAVE_ITEM_TO_D) wr_s16b((s16b)o_ptr->to_d);
+ if (flags & SAVE_ITEM_TO_A) wr_s16b(o_ptr->to_a);
+ if (flags & SAVE_ITEM_AC) wr_s16b(o_ptr->ac);
+ if (flags & SAVE_ITEM_DD) wr_byte((byte_hack)o_ptr->dd);
+ if (flags & SAVE_ITEM_DS) wr_byte((byte_hack)o_ptr->ds);
- wr_byte(o_ptr->marked);
+ if (flags & SAVE_ITEM_IDENT) wr_byte(o_ptr->ident);
- wr_u32b(o_ptr->art_flags1);
- wr_u32b(o_ptr->art_flags2);
- wr_u32b(o_ptr->art_flags3);
+ if (flags & SAVE_ITEM_MARKED) wr_byte(o_ptr->marked);
- wr_u32b(o_ptr->curse_flags);
+ if (flags & SAVE_ITEM_ART_FLAGS0) wr_u32b(o_ptr->art_flags[0]);
+ if (flags & SAVE_ITEM_ART_FLAGS1) wr_u32b(o_ptr->art_flags[1]);
+ if (flags & SAVE_ITEM_ART_FLAGS2) wr_u32b(o_ptr->art_flags[2]);
+ if (flags & SAVE_ITEM_ART_FLAGS3) wr_u32b(o_ptr->art_flags[3]);
+ if (flags & SAVE_ITEM_ART_FLAGS4) wr_u32b(o_ptr->art_flags[4]);
+
+ if (flags & SAVE_ITEM_CURSE_FLAGS) wr_u32b(o_ptr->curse_flags);
/* Held by monster index */
- wr_s16b(o_ptr->held_m_idx);
+ if (flags & SAVE_ITEM_HELD_M_IDX) wr_s16b(o_ptr->held_m_idx);
/* Extra information */
- wr_byte(o_ptr->xtra1);
- wr_byte(o_ptr->xtra2);
- wr_byte(o_ptr->xtra3);
- wr_s16b(o_ptr->xtra4);
- wr_s16b(o_ptr->xtra5);
+ if (flags & SAVE_ITEM_XTRA1) wr_byte(o_ptr->xtra1);
+ if (flags & SAVE_ITEM_XTRA2) wr_byte(o_ptr->xtra2);
+ if (flags & SAVE_ITEM_XTRA3) wr_byte(o_ptr->xtra3);
+ if (flags & SAVE_ITEM_XTRA4) wr_s16b(o_ptr->xtra4);
+ if (flags & SAVE_ITEM_XTRA5) wr_s16b(o_ptr->xtra5);
/* Feelings */
- wr_byte(o_ptr->feeling);
-
- /* Save the inscription (if any) */
- if (o_ptr->inscription)
- {
- wr_string(quark_str(o_ptr->inscription));
- }
- else
- {
- wr_string("");
- }
-
- /* If it is a "new" named artifact, save the name */
- if (o_ptr->art_name)
- {
- wr_string(quark_str(o_ptr->art_name));
- }
- else
- {
- wr_string("");
- }
+ if (flags & SAVE_ITEM_FEELING) wr_byte(o_ptr->feeling);
- /* No Python object */
- wr_s32b(0);
+ if (flags & SAVE_ITEM_INSCRIPTION) wr_string(quark_str(o_ptr->inscription));
+ if (flags & SAVE_ITEM_ART_NAME) wr_string(quark_str(o_ptr->art_name));
}
-/*
- * Write a "monster" record
+/*!
+ * @brief モンスター情報を書き込む / Write a "monster" record
+ * @param m_ptr モンスター情報保存元ポインタ
+ * @return なし
*/
static void wr_monster(monster_type *m_ptr)
{
+ u32b flags = 0x00000000;
+ byte tmp8u;
+
+ if (!is_original_ap(m_ptr)) flags |= SAVE_MON_AP_R_IDX;
+ if (m_ptr->sub_align) flags |= SAVE_MON_SUB_ALIGN;
+ if (MON_CSLEEP(m_ptr)) flags |= SAVE_MON_CSLEEP;
+ if (MON_FAST(m_ptr)) flags |= SAVE_MON_FAST;
+ if (MON_SLOW(m_ptr)) flags |= SAVE_MON_SLOW;
+ if (MON_STUNNED(m_ptr)) flags |= SAVE_MON_STUNNED;
+ if (MON_CONFUSED(m_ptr)) flags |= SAVE_MON_CONFUSED;
+ if (MON_MONFEAR(m_ptr)) flags |= SAVE_MON_MONFEAR;
+ if (m_ptr->target_y) flags |= SAVE_MON_TARGET_Y;
+ if (m_ptr->target_x) flags |= SAVE_MON_TARGET_X;
+ if (MON_INVULNER(m_ptr)) flags |= SAVE_MON_INVULNER;
+ if (m_ptr->smart) flags |= SAVE_MON_SMART;
+ if (m_ptr->exp) flags |= SAVE_MON_EXP;
+ if (m_ptr->mflag2) flags |= SAVE_MON_MFLAG2;
+ if (m_ptr->nickname) flags |= SAVE_MON_NICKNAME;
+ if (m_ptr->parent_m_idx) flags |= SAVE_MON_PARENT;
+
+ /*** Monster save flags ***/
+ wr_u32b(flags);
+
+ /*** Write only un-obvious elements ***/
wr_s16b(m_ptr->r_idx);
- wr_s16b(m_ptr->ap_r_idx);
- wr_byte(m_ptr->sub_align);
- wr_byte(m_ptr->fy);
- wr_byte(m_ptr->fx);
- wr_s16b(m_ptr->hp);
- wr_s16b(m_ptr->maxhp);
- wr_s16b(m_ptr->max_maxhp);
- wr_s16b(m_ptr->csleep);
+ wr_byte((byte_hack)m_ptr->fy);
+ wr_byte((byte_hack)m_ptr->fx);
+ wr_s16b((s16b)m_ptr->hp);
+ wr_s16b((s16b)m_ptr->maxhp);
+ wr_s16b((s16b)m_ptr->max_maxhp);
+ wr_u32b(m_ptr->dealt_damage);
+
+
+ /* Monster race index of its appearance */
+ if (flags & SAVE_MON_AP_R_IDX) wr_s16b(m_ptr->ap_r_idx);
+
+ if (flags & SAVE_MON_SUB_ALIGN) wr_byte(m_ptr->sub_align);
+ if (flags & SAVE_MON_CSLEEP) wr_s16b(m_ptr->mtimed[MTIMED_CSLEEP]);
+
wr_byte(m_ptr->mspeed);
wr_s16b(m_ptr->energy_need);
- wr_byte(m_ptr->fast);
- wr_byte(m_ptr->slow);
- wr_byte(m_ptr->stunned);
- wr_byte(m_ptr->confused);
- wr_byte(m_ptr->monfear);
- wr_s16b(m_ptr->target_y);
- wr_s16b(m_ptr->target_x);
- wr_byte(m_ptr->invulner);
- wr_u32b(m_ptr->smart);
- wr_u32b(m_ptr->exp);
- wr_byte(m_ptr->mflag2);
- if (m_ptr->nickname)
+
+ if (flags & SAVE_MON_FAST)
{
- wr_string(quark_str(m_ptr->nickname));
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_FAST];
+ wr_byte(tmp8u);
}
- else
+ if (flags & SAVE_MON_SLOW)
{
- wr_string("");
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_SLOW];
+ wr_byte(tmp8u);
}
- wr_byte(0);
+ if (flags & SAVE_MON_STUNNED)
+ {
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_STUNNED];
+ wr_byte(tmp8u);
+ }
+ if (flags & SAVE_MON_CONFUSED)
+ {
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_CONFUSED];
+ wr_byte(tmp8u);
+ }
+ if (flags & SAVE_MON_MONFEAR)
+ {
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_MONFEAR];
+ wr_byte(tmp8u);
+ }
+ if (flags & SAVE_MON_TARGET_Y) wr_s16b((s16b)m_ptr->target_y);
+ if (flags & SAVE_MON_TARGET_X) wr_s16b((s16b)m_ptr->target_x);
+ if (flags & SAVE_MON_INVULNER)
+ {
+ tmp8u = (byte)m_ptr->mtimed[MTIMED_INVULNER];
+ wr_byte(tmp8u);
+ }
+ if (flags & SAVE_MON_SMART) wr_u32b(m_ptr->smart);
+ if (flags & SAVE_MON_EXP) wr_u32b(m_ptr->exp);
+ if (flags & SAVE_MON_MFLAG2) wr_byte(m_ptr->mflag2);
+ if (flags & SAVE_MON_NICKNAME) wr_string(quark_str(m_ptr->nickname));
+ if (flags & SAVE_MON_PARENT) wr_s16b(m_ptr->parent_m_idx);
}
-/*
- * Write a "lore" record
+/*!
+ * @brief モンスターの思い出を書き込む / Write a "lore" record
+ * @param r_idx モンスター種族ID
+ * @return なし
*/
-static void wr_lore(int r_idx)
+static void wr_lore(MONRACE_IDX r_idx)
{
monster_race *r_ptr = &r_info[r_idx];
/* Count sights/deaths/kills */
- wr_s16b(r_ptr->r_sights);
- wr_s16b(r_ptr->r_deaths);
- wr_s16b(r_ptr->r_pkills);
- wr_s16b(r_ptr->r_tkills);
+ wr_s16b((s16b)r_ptr->r_sights);
+ wr_s16b((s16b)r_ptr->r_deaths);
+ wr_s16b((s16b)r_ptr->r_pkills);
+ wr_s16b((s16b)r_ptr->r_akills);
+ wr_s16b((s16b)r_ptr->r_tkills);
/* Count wakes and ignores */
wr_byte(r_ptr->r_wake);
wr_byte(r_ptr->r_xtra2);
/* Count drops */
- wr_byte(r_ptr->r_drop_gold);
- wr_byte(r_ptr->r_drop_item);
+ wr_byte((byte_hack)r_ptr->r_drop_gold);
+ wr_byte((byte_hack)r_ptr->r_drop_item);
/* Count spells */
- wr_byte(r_ptr->r_cast_inate);
+ wr_byte(0); /* unused now */
wr_byte(r_ptr->r_cast_spell);
/* Count blows of each type */
wr_u32b(r_ptr->r_flags4);
wr_u32b(r_ptr->r_flags5);
wr_u32b(r_ptr->r_flags6);
+ wr_u32b(r_ptr->r_flagsr);
/* Monster limit per level */
- wr_byte(r_ptr->max_num);
+ wr_byte((byte_hack)r_ptr->max_num);
+
+ /* Location in saved floor */
+ wr_s16b(r_ptr->floor_id);
/* Later (?) */
wr_byte(0);
- wr_byte(0);
- wr_byte(0);
}
-
-/*
- * Write an "xtra" record
+/*!
+ * @brief その他のゲーム情報を書き込む(実質はアイテムの鑑定情報のみ) / Write an "xtra" record
+ * @param k_idx ベースアイテムのID
+ * @return なし
*/
-static void wr_xtra(int k_idx)
+static void wr_xtra(KIND_OBJECT_IDX k_idx)
{
byte tmp8u = 0;
}
-/*
- * Write a "store" record
+/*!
+ * @brief 店舗情報を書き込む / Write a "store" record
+ * @param st_ptr 店舗情報の参照ポインタ
+ * @return なし
*/
static void wr_store(store_type *st_ptr)
{
}
-/*
- * Write RNG state
+/*!
+ * @brief 乱数情報を書き込む / Write RNG state
+ * @return なし
*/
static errr wr_randomizer(void)
{
}
-/*
- * Write the "options"
+/*!
+ * @brief ゲームオプション情報を書き込む / Write the "options"
+ * @return なし
*/
static void wr_options(void)
{
/* Write "hitpoint_warn" */
wr_byte(hitpoint_warn);
+ /* Write "mana_warn" */
+ wr_byte(mana_warn);
/*** Cheating options ***/
c = 0;
- if (wizard) c |= 0x0002;
+ if (p_ptr->wizard) c |= 0x0002;
+
+ if (cheat_sight) c |= 0x0040;
+ if (cheat_turn) c |= 0x0080;
if (cheat_peek) c |= 0x0100;
if (cheat_hear) c |= 0x0200;
if (cheat_xtra) c |= 0x0800;
if (cheat_know) c |= 0x1000;
if (cheat_live) c |= 0x2000;
+ if (cheat_save) c |= 0x4000;
+ if (cheat_diary_output) c |= 0x8000;
wr_u16b(c);
}
-/*
- * Hack -- Write the "ghost" info
+/*!
+ * @brief ダミー情報スキップを書き込む / Hack -- Write the "ghost" info
+ * @return なし
*/
static void wr_ghost(void)
{
int i;
/* Name */
-#ifdef JP
- wr_string("ÉÔÀµ¤Ê¥´¡¼¥¹¥È");
-#else
- wr_string("Broken Ghost");
-#endif
-
+ wr_string(_("不正なゴースト", "Broken Ghost"));
/* Hack -- stupid data */
for (i = 0; i < 60; i++) wr_byte(0);
}
-/*
- * Save quick start data
+/*!
+ * @brief クイック・スタート情報を書き込む / Save quick start data
+ * @return なし
*/
-void save_quick_start()
+static void save_quick_start(void)
{
int i;
wr_byte(previous_char.prace);
wr_byte(previous_char.pclass);
wr_byte(previous_char.pseikaku);
- wr_byte(previous_char.realm1);
- wr_byte(previous_char.realm2);
+ wr_byte((byte_hack)previous_char.realm1);
+ wr_byte((byte_hack)previous_char.realm2);
wr_s16b(previous_char.age);
wr_s16b(previous_char.ht);
for (i = 0; i < 6; i++) wr_s16b(previous_char.stat_max[i]);
for (i = 0; i < 6; i++) wr_s16b(previous_char.stat_max_max[i]);
- for (i = 0; i < PY_MAX_LEVEL; i++) wr_s16b(previous_char.player_hp[i]);
+ for (i = 0; i < PY_MAX_LEVEL; i++) wr_s16b((s16b)previous_char.player_hp[i]);
wr_s16b(previous_char.chaos_patron);
for (i = 0; i < 4; i++) wr_string(previous_char.history[i]);
- wr_byte(previous_char.quests);
+ /* UNUSED : Was number of random quests */
+ wr_byte(0);
+
+ /* No quick start after using debug mode or cheat options */
+ if (p_ptr->noscore) previous_char.quick_ok = FALSE;
+
wr_byte((byte)previous_char.quick_ok);
}
-/*
- * Write some "extra" info
+
+/*!
+ * @brief その他の情報を書き込む / Write some "extra" info
+ * @return なし
*/
static void wr_extra(void)
{
int i,j;
byte tmp8u;
- wr_string(player_name);
+ wr_string(p_ptr->name);
- wr_string(died_from);
+ wr_string(p_ptr->died_from);
+
+ wr_string(p_ptr->last_message ? p_ptr->last_message : "");
save_quick_start();
for (i = 0; i < 4; i++)
{
- wr_string(history[i]);
+ wr_string(p_ptr->history[i]);
}
/* Race/Class/Gender/Spells */
wr_byte(p_ptr->pclass);
wr_byte(p_ptr->pseikaku);
wr_byte(p_ptr->psex);
- wr_byte(p_ptr->realm1);
- wr_byte(p_ptr->realm2);
+ wr_byte((byte_hack)p_ptr->realm1);
+ wr_byte((byte_hack)p_ptr->realm2);
wr_byte(0); /* oops */
- wr_byte(p_ptr->hitdie);
+ wr_byte((byte)p_ptr->hitdie);
wr_u16b(p_ptr->expfact);
wr_s16b(p_ptr->age);
wr_u32b(p_ptr->au);
wr_u32b(p_ptr->max_exp);
+ wr_u32b(p_ptr->max_max_exp);
wr_u32b(p_ptr->exp);
- wr_u16b(p_ptr->exp_frac);
+ wr_u32b(p_ptr->exp_frac);
wr_s16b(p_ptr->lev);
- for (i = 0; i < 64; i++) wr_s16b(spell_exp[i]);
- for (i = 0; i < 5; i++) for (j = 0; j < 64; j++) wr_s16b(weapon_exp[i][j]);
- for (i = 0; i < 10; i++) wr_s16b(skill_exp[i]);
+ for (i = 0; i < 64; i++) wr_s16b(p_ptr->spell_exp[i]);
+ for (i = 0; i < 5; i++) for (j = 0; j < 64; j++) wr_s16b(p_ptr->weapon_exp[i][j]);
+ for (i = 0; i < GINOU_MAX; i++) wr_s16b(p_ptr->skill_exp[i]);
for (i = 0; i < 108; i++) wr_s32b(p_ptr->magic_num1[i]);
for (i = 0; i < 108; i++) wr_byte(p_ptr->magic_num2[i]);
for (i = 0; i < MAX_MANE; i++)
{
- wr_s16b(mane_spell[i]);
- wr_s16b(mane_dam[i]);
+ wr_s16b((s16b)p_ptr->mane_spell[i]);
+ wr_s16b((s16b)p_ptr->mane_dam[i]);
}
- wr_s16b(mane_num);
+ wr_s16b(p_ptr->mane_num);
for (i = 0; i < MAX_KUBI; i++)
{
wr_s16b(p_ptr->inside_quest);
wr_s16b(p_ptr->inside_battle);
wr_byte(p_ptr->exit_bldg);
- wr_byte(p_ptr->leftbldg); /* save building leave status -KMW- */
-
- wr_s16b(p_ptr->oldpx);
- wr_s16b(p_ptr->oldpy);
+ wr_byte(0); /* Unused */
- /* Save builing rewards */
- wr_s16b(MAX_BACT);
+ wr_s16b((s16b)p_ptr->oldpx);
+ wr_s16b((s16b)p_ptr->oldpy);
- for (i = 0; i < MAX_BACT; i++) wr_s16b(p_ptr->rewards[i]);
+ /* Was number of p_ptr->rewards[] */
+ wr_s16b(0);
- wr_s16b(p_ptr->mhp);
- wr_s16b(p_ptr->chp);
- wr_u16b(p_ptr->chp_frac);
+ wr_s32b(p_ptr->mhp);
+ wr_s32b(p_ptr->chp);
+ wr_u32b(p_ptr->chp_frac);
- wr_s16b(p_ptr->msp);
- wr_s16b(p_ptr->csp);
- wr_u16b(p_ptr->csp_frac);
+ wr_s32b(p_ptr->msp);
+ wr_s32b(p_ptr->csp);
+ wr_u32b(p_ptr->csp_frac);
/* Max Player and Dungeon Levels */
wr_s16b(p_ptr->max_plv);
- tmp8u = (byte)max_d_idx;
- wr_byte(tmp8u);
- for (i = 0; i < tmp8u; i++)
- wr_s16b(max_dlv[i]);
+ tmp8u = (byte)max_d_idx;
+ wr_byte(tmp8u);
+ for (i = 0; i < tmp8u; i++)
+ wr_s16b((s16b)max_dlv[i]);
/* More info */
wr_s16b(0); /* oops */
wr_s16b(0); /* oops */
wr_s16b(0); /* oops */
wr_s16b(p_ptr->sc);
- wr_s16b(0); /* oops */
+ wr_s16b(p_ptr->concent);
wr_s16b(0); /* old "rest" */
wr_s16b(p_ptr->blind);
wr_s16b(0); /* old "food_digested" */
wr_s16b(0); /* old "protection" */
wr_s16b(p_ptr->energy_need);
+ wr_s16b(p_ptr->enchant_energy_need);
wr_s16b(p_ptr->fast);
wr_s16b(p_ptr->slow);
wr_s16b(p_ptr->afraid);
wr_s16b(p_ptr->blessed);
wr_s16b(p_ptr->tim_invis);
wr_s16b(p_ptr->word_recall);
- wr_s16b(p_ptr->recall_dungeon);
+ wr_s16b(p_ptr->recall_dungeon);
+ wr_s16b(p_ptr->alter_reality);
wr_s16b(p_ptr->see_infra);
wr_s16b(p_ptr->tim_infra);
wr_s16b(p_ptr->oppose_fire);
wr_s16b(p_ptr->tim_regen);
wr_s16b(p_ptr->kabenuke);
wr_s16b(p_ptr->tim_stealth);
- wr_s16b(p_ptr->tim_ffall);
+ wr_s16b(p_ptr->tim_levitation);
wr_s16b(p_ptr->tim_sh_touki);
wr_s16b(p_ptr->lightspeed);
wr_s16b(p_ptr->tsubureru);
wr_s16b(p_ptr->magicdef);
wr_s16b(p_ptr->tim_res_nether);
wr_s16b(p_ptr->tim_res_time);
- wr_byte(p_ptr->mimic_form);
+ wr_byte((byte)p_ptr->mimic_form);
wr_s16b(p_ptr->tim_mimic);
wr_s16b(p_ptr->tim_sh_fire);
+ wr_s16b(p_ptr->tim_sh_holy);
+ wr_s16b(p_ptr->tim_eyeeye);
/* by henkma */
wr_s16b(p_ptr->tim_reflect);
wr_s16b(p_ptr->ele_immune);
wr_u32b(p_ptr->special_defense);
wr_byte(p_ptr->knowledge);
+ wr_byte(p_ptr->autopick_autoregister);
wr_byte(0); /* oops */
- wr_byte(0); /* oops */
- wr_byte(p_ptr->action);
+ wr_byte((byte_hack)p_ptr->action);
wr_byte(0);
wr_byte(preserve_mode);
- wr_byte(wait_report_score);
+ wr_byte(p_ptr->wait_report_score);
/* Future use */
for (i = 0; i < 12; i++) wr_u32b(0L);
/* Special stuff */
- wr_u16b(panic_save);
- wr_u16b(total_winner);
- wr_u16b(noscore);
+ wr_u16b(p_ptr->panic_save);
+ wr_u16b(p_ptr->total_winner);
+ wr_u16b(p_ptr->noscore);
/* Write death */
- wr_byte(death);
+ wr_byte(p_ptr->is_dead);
/* Write feeling */
- wr_byte(feeling);
+ wr_byte(p_ptr->feeling);
- /* Turn of last "feeling" */
+ /* Turn when level began */
wr_s32b(old_turn);
+ /* Turn of last "feeling" */
+ wr_s32b(p_ptr->feeling_turn);
+
/* Current turn */
wr_s32b(turn);
wr_s16b(p_ptr->today_mon);
wr_s16b(p_ptr->riding);
+ /* Current floor_id */
+ wr_s16b(p_ptr->floor_id);
+
+ /* Save temporary preserved pets (obsolated) */
+ wr_s16b(0);
+
wr_u32b(playtime);
wr_s32b(p_ptr->visit);
}
+/*!
+ * @brief フロア保存時のcave情報テンプレートをソートするための比較処理
+ * @param u caveテンプレートの参照ポインタ
+ * @param v 未使用
+ * @param a スワップするモンスター種族のID1
+ * @param b スワップするモンスター種族のID2
+ * @return aの方が大きければtrue
+ */
+static bool ang_sort_comp_cave_temp(vptr u, vptr v, int a, int b)
+{
+ cave_template_type *who = (cave_template_type *)(u);
-/*
- * Write the current dungeon
+ u16b o1 = who[a].occurrence;
+ u16b o2 = who[b].occurrence;
+
+ /* Unused */
+ (void)v;
+
+ return o2 <= o1;
+}
+
+
+/*!
+ * @brief フロア保存時のcave情報テンプレートをソートするためのスワップ処理 / Sorting hook -- Swap function
+ * @param u caveテンプレートの参照ポインタ
+ * @param v 未使用
+ * @param a スワップするモンスター種族のID1
+ * @param b スワップするモンスター種族のID2
+ * @return なし
*/
-static void wr_dungeon(void)
+static void ang_sort_swap_cave_temp(vptr u, vptr v, int a, int b)
{
+ cave_template_type *who = (cave_template_type *)(u);
+
+ cave_template_type holder;
+
+ /* Unused */
+ (void)v;
+
+ /* Swap */
+ holder = who[a];
+ who[a] = who[b];
+ who[b] = holder;
+}
+
+
+/*!
+ * @brief 保存フロアの書き込み / Actually write a saved floor data using effectively compressed format.
+ * @param sf_ptr 保存したいフロアの参照ポインタ
+ * @return なし
+ */
+static void wr_saved_floor(saved_floor_type *sf_ptr)
+{
+ cave_template_type *templates;
+ u16b max_num_temp;
+ u16b num_temp = 0;
+ int dummy_why;
+
int i, y, x;
- byte tmp8u;
u16b tmp16u;
byte count;
- byte prev_char;
- s16b prev_s16b;
-
- cave_type *c_ptr;
+ u16b prev_u16b;
/*** Basic info ***/
- /* Dungeon specific info follows */
- wr_u16b(dun_level);
- wr_byte(dungeon_type);
- wr_u16b(base_level);
+ /* Dungeon floor specific info follows */
+
+ if (!sf_ptr)
+ {
+ /*** Not a saved floor ***/
+
+ wr_s16b((s16b)dun_level);
+ }
+ else
+ {
+ /*** The saved floor ***/
+
+ wr_s16b(sf_ptr->floor_id);
+ wr_byte((byte_hack)sf_ptr->savefile_id);
+ wr_s16b((s16b)sf_ptr->dun_level);
+ wr_s32b(sf_ptr->last_visit);
+ wr_u32b(sf_ptr->visit_mark);
+ wr_s16b(sf_ptr->upper_floor_id);
+ wr_s16b(sf_ptr->lower_floor_id);
+ }
+
+ wr_u16b((u16b)base_level);
wr_u16b(num_repro);
- wr_u16b((u16b)py);
- wr_u16b((u16b)px);
- wr_u16b(cur_hgt);
- wr_u16b(cur_wid);
- wr_u16b(0); /* max_panel_rows */
- wr_u16b(0); /* max_panel_cols */
+ wr_u16b((u16b)p_ptr->y);
+ wr_u16b((u16b)p_ptr->x);
+ wr_u16b((u16b)cur_hgt);
+ wr_u16b((u16b)cur_wid);
+ wr_byte(p_ptr->feeling);
- /*** Simple "Run-Length-Encoding" of cave ***/
- /* Note that this will induce two wasted bytes */
- count = 0;
- prev_s16b = 0;
+ /*********** Make template for cave_type **********/
- /* Dump the cave */
+ /*
+ * Usually number of templates are fewer than 255. Even if
+ * more than 254 are exist, the occurrence of each template
+ * with larger ID is very small when we sort templates by
+ * occurrence. So we will use two (or more) bytes for
+ * templete ID larger than 254.
+ *
+ * Ex: 256 will be "0xff" "0x01".
+ * 515 will be "0xff" "0xff" "0x03"
+ */
+
+ /* Fake max number */
+ max_num_temp = 255;
+
+ /* Allocate the "template" array */
+ C_MAKE(templates, max_num_temp, cave_template_type);
+
+ /* Extract template array */
for (y = 0; y < cur_hgt; y++)
{
for (x = 0; x < cur_wid; x++)
{
- /* Get the cave */
- c_ptr = &cave[y][x];
+ cave_type *c_ptr = &cave[y][x];
- /* Extract a byte */
- tmp16u = c_ptr->info;
-
- /* If the run is broken, or too full, flush it */
- if ((tmp16u != prev_s16b) || (count == MAX_UCHAR))
+ for (i = 0; i < num_temp; i++)
{
- wr_byte((byte)count);
- wr_u16b((u16b)prev_s16b);
- prev_s16b = tmp16u;
- count = 1;
+ if (templates[i].info == c_ptr->info &&
+ templates[i].feat == c_ptr->feat &&
+ templates[i].mimic == c_ptr->mimic &&
+ templates[i].special == c_ptr->special)
+ {
+ /* Same terrain is exist */
+ templates[i].occurrence++;
+ break;
+ }
}
- /* Continue the run */
- else
+ /* Are there same one? */
+ if (i < num_temp) continue;
+
+ /* If the max_num_temp is too small, increase it. */
+ if (num_temp >= max_num_temp)
{
- count++;
+ cave_template_type *old_template = templates;
+
+ /* Re-allocate the "template" array */
+ C_MAKE(templates, max_num_temp + 255, cave_template_type);
+ (void)C_COPY(templates, old_template, max_num_temp, cave_template_type);
+ C_KILL(old_template, max_num_temp, cave_template_type);
+ max_num_temp += 255;
}
+
+ /* Add new template */
+ templates[num_temp].info = c_ptr->info;
+ templates[num_temp].feat = c_ptr->feat;
+ templates[num_temp].mimic = c_ptr->mimic;
+ templates[num_temp].special = c_ptr->special;
+ templates[num_temp].occurrence = 1;
+
+ /* Increase number of template */
+ num_temp++;
}
}
- /* Flush the data (if any) */
- if (count)
+ /* Select the sort method */
+ ang_sort_comp = ang_sort_comp_cave_temp;
+ ang_sort_swap = ang_sort_swap_cave_temp;
+
+ /* Sort by occurrence */
+ ang_sort(templates, &dummy_why, num_temp);
+
+
+ /*** Dump templates ***/
+
+ /* Total templates */
+ wr_u16b(num_temp);
+
+ /* Dump the templates */
+ for (i = 0; i < num_temp; i++)
{
- wr_byte((byte)count);
- wr_u16b((byte)prev_s16b);
+ cave_template_type *ct_ptr = &templates[i];
+
+ /* Dump it */
+ wr_u16b((u16b)ct_ptr->info);
+ wr_s16b(ct_ptr->feat);
+ wr_s16b(ct_ptr->mimic);
+ wr_s16b(ct_ptr->special);
}
- /*** Simple "Run-Length-Encoding" of cave ***/
+
+ /*** "Run-Length-Encoding" of cave ***/
/* Note that this will induce two wasted bytes */
count = 0;
- prev_char = 0;
+ prev_u16b = 0;
/* Dump the cave */
for (y = 0; y < cur_hgt; y++)
{
for (x = 0; x < cur_wid; x++)
{
- /* Get the cave */
- c_ptr = &cave[y][x];
+ cave_type *c_ptr = &cave[y][x];
+
+ for (i = 0; i < num_temp; i++)
+ {
+ if (templates[i].info == c_ptr->info &&
+ templates[i].feat == c_ptr->feat &&
+ templates[i].mimic == c_ptr->mimic &&
+ templates[i].special == c_ptr->special)
+ break;
+ }
- /* Extract a byte */
- tmp8u = c_ptr->feat;
+ /* Extract an ID */
+ tmp16u = (u16b)i;
/* If the run is broken, or too full, flush it */
- if ((tmp8u != prev_char) || (count == MAX_UCHAR))
+ if ((tmp16u != prev_u16b) || (count == MAX_UCHAR))
{
wr_byte((byte)count);
- wr_byte((byte)prev_char);
- prev_char = tmp8u;
+
+ while (prev_u16b >= MAX_UCHAR)
+ {
+ /* Mark as actual data is larger than 254 */
+ wr_byte(MAX_UCHAR);
+ prev_u16b -= MAX_UCHAR;
+ }
+
+ wr_byte((byte)prev_u16b);
+ prev_u16b = tmp16u;
count = 1;
}
if (count)
{
wr_byte((byte)count);
- wr_byte((byte)prev_char);
+
+ while (prev_u16b >= MAX_UCHAR)
+ {
+ /* Mark as actual data is larger than 254 */
+ wr_byte(MAX_UCHAR);
+ prev_u16b -= MAX_UCHAR;
+ }
+ wr_byte((byte)prev_u16b);
}
- /*** Simple "Run-Length-Encoding" of cave ***/
+ /* Free the "template" array */
+ C_KILL(templates, max_num_temp, cave_template_type);
- /* Note that this will induce two wasted bytes */
- count = 0;
- prev_char = 0;
- /* Dump the cave */
- for (y = 0; y < cur_hgt; y++)
- {
- for (x = 0; x < cur_wid; x++)
- {
- /* Get the cave */
- c_ptr = &cave[y][x];
+ /*** Dump objects ***/
- /* Extract a byte */
- tmp8u = c_ptr->mimic;
+ /* Total objects */
+ wr_u16b(o_max);
- /* If the run is broken, or too full, flush it */
- if ((tmp8u != prev_char) || (count == MAX_UCHAR))
- {
- wr_byte((byte)count);
- wr_byte((byte)prev_char);
- prev_char = tmp8u;
- count = 1;
- }
+ /* Dump the objects */
+ for (i = 1; i < o_max; i++)
+ {
+ object_type *o_ptr = &o_list[i];
- /* Continue the run */
- else
- {
- count++;
- }
- }
+ /* Dump it */
+ wr_item(o_ptr);
}
- /* Flush the data (if any) */
- if (count)
+
+ /*** Dump the monsters ***/
+
+ /* Total monsters */
+ wr_u16b(m_max);
+
+ /* Dump the monsters */
+ for (i = 1; i < m_max; i++)
{
- wr_byte((byte)count);
- wr_byte((byte)prev_char);
+ monster_type *m_ptr = &m_list[i];
+
+ /* Dump it */
+ wr_monster(m_ptr);
}
+}
- /*** Simple "Run-Length-Encoding" of cave ***/
+/*!
+ * @brief 現在フロアの書き込み /
+ * Write the current dungeon (new method)
+ * @return なし
+ */
+static bool wr_dungeon(void)
+{
+ saved_floor_type *cur_sf_ptr;
+ int i;
- /* Note that this will induce two wasted bytes */
- count = 0;
- prev_s16b = 0;
+ /* Forget the lite */
+ forget_lite();
- /* Dump the cave */
- for (y = 0; y < cur_hgt; y++)
- {
- for (x = 0; x < cur_wid; x++)
- {
- /* Get the cave */
- c_ptr = &cave[y][x];
+ /* Forget the view */
+ forget_view();
- /* Extract a byte */
- tmp16u = c_ptr->special;
+ /* Forget the view */
+ clear_mon_lite();
- /* If the run is broken, or too full, flush it */
- if ((tmp16u != prev_s16b) || (count == MAX_UCHAR))
- {
- wr_byte((byte)count);
- wr_u16b(prev_s16b);
- prev_s16b = tmp16u;
- count = 1;
- }
+ /* Update lite/view */
+ p_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
+
+ /* Update monsters */
+ p_ptr->update |= (PU_MONSTERS | PU_DISTANCE | PU_FLOW);
+
+
+ /*** Meta info ***/
+
+ /* Number of floor_id used from birth */
+ wr_s16b(max_floor_id);
- /* Continue the run */
- else
- {
- count++;
- }
- }
- }
+ /* Current dungeon type */
+ wr_byte((byte_hack)dungeon_type);
- /* Flush the data (if any) */
- if (count)
+
+ /*** No saved floor (On the surface etc.) ***/
+ if (!p_ptr->floor_id)
{
- wr_byte((byte)count);
- wr_u16b(prev_s16b);
+ /* No array elements */
+ wr_byte(0);
+
+ /* Write the current floor data */
+ wr_saved_floor(NULL);
+
+ /* Success */
+ return TRUE;
}
- /*** Dump objects ***/
+ /*** In the dungeon ***/
- /* Total objects */
- wr_u16b(o_max);
+ /* Number of array elements */
+ wr_byte(MAX_SAVED_FLOORS);
- /* Dump the objects */
- for (i = 1; i < o_max; i++)
+ /* Write the saved_floors array */
+ for (i = 0; i < MAX_SAVED_FLOORS; i++)
{
- object_type *o_ptr = &o_list[i];
-
- /* Dump it */
- wr_item(o_ptr);
+ saved_floor_type *sf_ptr = &saved_floors[i];
+
+ wr_s16b(sf_ptr->floor_id);
+ wr_byte((byte_hack)sf_ptr->savefile_id);
+ wr_s16b((s16b)sf_ptr->dun_level);
+ wr_s32b(sf_ptr->last_visit);
+ wr_u32b(sf_ptr->visit_mark);
+ wr_s16b(sf_ptr->upper_floor_id);
+ wr_s16b(sf_ptr->lower_floor_id);
}
+ /* Extract pointer to current floor */
+ cur_sf_ptr = get_sf_ptr(p_ptr->floor_id);
- /*** Dump the monsters ***/
+ /* Save current floor to temporal file */
+ if (!save_floor(cur_sf_ptr, (SLF_SECOND))) return FALSE;
+ /* Move data in temporal files to the savefile */
+ for (i = 0; i < MAX_SAVED_FLOORS; i++)
+ {
+ saved_floor_type *sf_ptr = &saved_floors[i];
- /* Total monsters */
- wr_u16b(m_max);
+ /* Unused element */
+ if (!sf_ptr->floor_id) continue;
- /* Dump the monsters */
- for (i = 1; i < m_max; i++)
- {
- monster_type *m_ptr = &m_list[i];
+ /* Load temporal saved floor file */
+ if (load_floor(sf_ptr, (SLF_SECOND | SLF_NO_KILL)))
+ {
+ /* Mark success */
+ wr_byte(0);
- /* Dump it */
- wr_monster(m_ptr);
+ /* Write saved floor data to the save file */
+ wr_saved_floor(sf_ptr);
+ }
+ else
+ {
+ /* Mark failure */
+ wr_byte(1);
+ }
}
-}
+ /* Restore current floor */
+ if (!load_floor(cur_sf_ptr, (SLF_SECOND))) return FALSE;
+ /* Success */
+ return TRUE;
+}
-/*
+
+/*!
+ * @brief セーブデータの書き込み /
* Actually write a save-file
+ * @return 成功すればtrue
*/
static bool wr_savefile_new(void)
{
byte tmp8u;
u16b tmp16u;
+ u32b tmp32u;
+ MONRACE_IDX r_idx;
+ KIND_OBJECT_IDX k_idx;
/* Compact the objects */
compact_objects(0);
compact_monsters(0);
/* Guess at the current time */
- now = time((time_t *)0);
+ now = (u32b)time((time_t *)0);
/* Note the operating system */
- sf_xtra = 0L;
+ sf_system = 0L;
/* Note when the file was saved */
sf_when = now;
wr_byte(FAKE_VER_PATCH);
xor_byte = 0;
- tmp8u = (byte)randint0(256);
+ /* Initial value of xor_byte */
+ tmp8u = (byte)Rand_external(256);
wr_byte(tmp8u);
v_stamp = 0L;
x_stamp = 0L;
- /* Write the savefile version */
- wr_u32b(SAVEFILE_VERSION);
+ /* Write the savefile version for Hengband 1.1.1 and later */
+ wr_byte(H_VER_EXTRA);
+ wr_byte(H_VER_PATCH);
+ wr_byte(H_VER_MINOR);
+ wr_byte(H_VER_MAJOR);
/* Operating system */
- wr_u32b(sf_xtra);
+ wr_u32b(sf_system);
/* Time file last saved */
/* Space */
wr_u32b(0L);
- wr_u32b(0L);
+ wr_u16b(0);
+ wr_byte(0);
+#ifdef JP
+# ifdef EUC
+ /* EUC kanji code */
+ wr_byte(2);
+# endif
+# ifdef SJIS
+ /* SJIS kanji code */
+ wr_byte(3);
+# endif
+#else
+ /* ASCII */
+ wr_byte(1);
+#endif
/* Write the RNG state */
wr_randomizer();
/* Dump the number of "messages" */
- tmp16u = message_num();
- if (compress_savefile && (tmp16u > 40)) tmp16u = 40;
- wr_u16b(tmp16u);
+ tmp32u = message_num();
+ if (compress_savefile && (tmp32u > 40)) tmp32u = 40;
+ wr_u32b(tmp32u);
/* Dump the messages (oldest first!) */
- for (i = tmp16u - 1; i >= 0; i--)
+ for (i = tmp32u - 1; i >= 0; i--)
{
wr_string(message_str((s16b)i));
}
-
/* Dump the monster lore */
tmp16u = max_r_idx;
wr_u16b(tmp16u);
- for (i = 0; i < tmp16u; i++) wr_lore(i);
-
+ for (r_idx = 0; r_idx < tmp16u; r_idx++) wr_lore(r_idx);
/* Dump the object memory */
tmp16u = max_k_idx;
wr_u16b(tmp16u);
- for (i = 0; i < tmp16u; i++) wr_xtra(i);
+ for (k_idx = 0; k_idx < tmp16u; k_idx++) wr_xtra(k_idx);
/* Dump the towns */
tmp16u = max_towns;
wr_u16b(tmp16u);
/* Dump the quests */
- tmp16u = max_quests;
+ tmp16u = max_q_idx;
wr_u16b(tmp16u);
/* Dump the quests */
tmp8u = MAX_RANDOM_QUEST-MIN_RANDOM_QUEST;
wr_byte(tmp8u);
- for (i = 0; i < max_quests; i++)
+ for (i = 0; i < max_q_idx; i++)
{
+ quest_type* const q_ptr = &quest[i];
+
/* Save status for every quest */
- wr_s16b(quest[i].status);
+ wr_s16b(q_ptr->status);
/* And the dungeon level too */
/* (prevents problems with multi-level quests) */
- wr_s16b(quest[i].level);
+ wr_s16b((s16b)q_ptr->level);
- wr_byte(quest[i].complev);
+ wr_byte((byte_hack)q_ptr->complev);
+ wr_u32b(q_ptr->comptime);
/* Save quest status if quest is running */
- if (quest[i].status == QUEST_STATUS_TAKEN || quest[i].status == QUEST_STATUS_COMPLETED || ((i >= MIN_RANDOM_QUEST) && (i <= MAX_RANDOM_QUEST)))
+ if (q_ptr->status == QUEST_STATUS_TAKEN || q_ptr->status == QUEST_STATUS_COMPLETED || !is_fixed_quest_idx(i))
{
- wr_s16b(quest[i].cur_num);
- wr_s16b(quest[i].max_num);
- wr_s16b(quest[i].type);
- wr_s16b(quest[i].r_idx);
- wr_s16b(quest[i].k_idx);
- wr_byte(quest[i].flags);
- wr_byte(quest[i].dungeon);
+ wr_s16b((s16b)q_ptr->cur_num);
+ wr_s16b((s16b)q_ptr->max_num);
+ wr_s16b(q_ptr->type);
+ wr_s16b(q_ptr->r_idx);
+ wr_s16b(q_ptr->k_idx);
+ wr_byte((byte_hack)q_ptr->flags);
+ wr_byte((byte_hack)q_ptr->dungeon);
}
}
{
artifact_type *a_ptr = &a_info[i];
wr_byte(a_ptr->cur_num);
- wr_byte(0);
- wr_byte(0);
- wr_byte(0);
+ wr_s16b(a_ptr->floor_id);
}
wr_u16b(tmp16u);
for (i = 0; i < tmp16u; i++)
{
- wr_s16b(player_hp[i]);
+ wr_s16b((s16b)p_ptr->player_hp[i]);
}
/* Write spell data */
- wr_u32b(spell_learned1);
- wr_u32b(spell_learned2);
- wr_u32b(spell_worked1);
- wr_u32b(spell_worked2);
- wr_u32b(spell_forgotten1);
- wr_u32b(spell_forgotten2);
+ wr_u32b(p_ptr->spell_learned1);
+ wr_u32b(p_ptr->spell_learned2);
+ wr_u32b(p_ptr->spell_worked1);
+ wr_u32b(p_ptr->spell_worked2);
+ wr_u32b(p_ptr->spell_forgotten1);
+ wr_u32b(p_ptr->spell_forgotten2);
wr_s16b(p_ptr->learned_spells);
wr_s16b(p_ptr->add_spells);
/* Dump the ordered spells */
for (i = 0; i < 64; i++)
{
- wr_byte(spell_order[i]);
+ wr_byte((byte_hack)p_ptr->spell_order[i]);
}
wr_s16b(p_ptr->pet_extra_flags);
/* Write screen dump for sending score */
- if (screen_dump && (wait_report_score || !death))
+ if (screen_dump && (p_ptr->wait_report_score || !p_ptr->is_dead))
{
wr_string(screen_dump);
}
}
/* Player is not dead, write the dungeon */
- if (!death)
+ if (!p_ptr->is_dead)
{
/* Dump the dungeon */
- wr_dungeon();
+ if (!wr_dungeon()) return FALSE;
/* Dump the ghost */
wr_ghost();
}
-/*
+/*!
+ * @brief セーブデータ書き込みのサブルーチン /
* Medium level player saver
- *
+ * @return 成功すればtrue
+ * @details
* XXX XXX XXX Angband 2.8.0 will use "fd" instead of "fff" if possible
*/
static bool save_player_aux(char *name)
FILE_TYPE(FILE_TYPE_SAVE);
+ /* Grab permissions */
+ safe_setuid_grab();
+
/* Create the savefile */
fd = fd_make(name, mode);
+ /* Drop permissions */
+ safe_setuid_drop();
+
/* File is okay */
if (fd >= 0)
{
/* Close the "fd" */
(void)fd_close(fd);
+ /* Grab permissions */
+ safe_setuid_grab();
+
/* Open the savefile */
fff = my_fopen(name, "wb");
+ /* Drop permissions */
+ safe_setuid_drop();
+
/* Successful open */
if (fff)
{
if (my_fclose(fff)) ok = FALSE;
}
+ /* Grab permissions */
+ safe_setuid_grab();
+
/* Remove "broken" files */
if (!ok) (void)fd_kill(name);
+
+ /* Drop permissions */
+ safe_setuid_drop();
}
-/*
+/*!
+ * @brief セーブデータ書き込みのメインルーチン /
* Attempt to save the player in a savefile
+ * @return 成功すればtrue
*/
bool save_player(void)
{
- int result = FALSE;
+ bool result = FALSE;
- char safe[1024];
+ char safe[1024];
#ifdef SET_UID
strcpy(safe, savefile);
strcat(safe, ".new");
-#ifdef VM
- /* Hack -- support "flat directory" usage on VM/ESA */
- strcpy(safe, savefile);
- strcat(safe, "n");
-#endif /* VM */
+ /* Grab permissions */
+ safe_setuid_grab();
/* Remove it */
fd_kill(safe);
+ /* Drop permissions */
+ safe_setuid_drop();
+
update_playtime();
/* Attempt to save the player */
strcpy(temp, savefile);
strcat(temp, ".old");
-#ifdef VM
- /* Hack -- support "flat directory" usage on VM/ESA */
- strcpy(temp, savefile);
- strcat(temp, "o");
-#endif /* VM */
+ /* Grab permissions */
+ safe_setuid_grab();
/* Remove it */
fd_kill(temp);
/* Remove preserved savefile */
fd_kill(temp);
+ /* Drop permissions */
+ safe_setuid_drop();
+
/* Hack -- Pretend the character was loaded */
character_loaded = TRUE;
strcpy(temp, savefile);
strcat(temp, ".lok");
+ /* Grab permissions */
+ safe_setuid_grab();
+
/* Remove lock file */
fd_kill(temp);
+ /* Drop permissions */
+ safe_setuid_drop();
+
#endif
/* Success */
#endif
-
/* Return the result */
return (result);
}
-
-/*
+/*!
+ * @brief セーブデータ読み込みのメインルーチン /
* Attempt to Load a "savefile"
- *
+ * @return 成功すればtrue
+ * @details
+ * <pre>
* Version 2.7.0 introduced a slightly different "savefile" format from
* older versions, requiring a completely different parsing method.
*
*
* 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.
+ * </pre>
*/
bool load_player(void)
{
turn = 0;
/* Paranoia */
- death = FALSE;
+ p_ptr->is_dead = FALSE;
/* Allow empty savefile name */
if (!savefile[0]) return (TRUE);
-#if !defined(MACINTOSH) && !defined(WINDOWS) && !defined(VM)
+#if !defined(MACINTOSH) && !defined(WINDOWS)
/* XXX XXX XXX Fix this */
if (access(savefile, 0) < 0)
{
/* Give a message */
-#ifdef JP
- msg_print("¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤¬¤¢¤ê¤Þ¤»¤ó¡£");
-#else
- msg_print("Savefile does not exist.");
-#endif
+ msg_print(_("セーブファイルがありません。", "Savefile does not exist."));
msg_print(NULL);
my_fclose(fkk);
/* Message */
-#ifdef JP
- msg_print("¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤Ï¸½ºß»ÈÍÑÃæ¤Ç¤¹¡£");
-#else
- msg_print("Savefile is currently in use.");
-#endif
-
+ msg_print(_("セーブファイルは現在使用中です。", "Savefile is currently in use."));
msg_print(NULL);
/* Oops */
if (fd < 0) err = -1;
/* Message (below) */
-#ifdef JP
- if (err) what = "¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤ò³«¤±¤Þ¤»¤ó¡£";
-#else
- if (err) what = "Cannot open savefile";
-#endif
-
+ if (err) what = _("セーブファイルを開けません。", "Cannot open savefile");
}
/* Process file */
if (fd_read(fd, (char*)(vvv), 4)) err = -1;
/* What */
-#ifdef JP
- if (err) what = "¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤òÆɤá¤Þ¤»¤ó¡£";
-#else
- if (err) what = "Cannot read savefile";
-#endif
-
+ if (err) what = _("セーブファイルを読めません。", "Cannot read savefile");
/* Close the file */
(void)fd_close(fd);
z_minor = vvv[1];
z_patch = vvv[2];
sf_extra = vvv[3];
- sf_major = 2;
- sf_minor = 8;
- sf_patch = 1;
-
- /* Pre-2.1.0: Assume 2.0.6 (same as 2.0.0 - 2.0.5) */
- if ((z_major == sf_major) &&
- (z_minor == sf_minor) &&
- (z_patch == sf_patch))
- {
- z_major = 2;
- z_minor = 0;
- z_patch = 6;
- }
-
- /* Very old savefiles */
- if ((sf_major == 5) && (sf_minor == 2))
- {
- sf_major = 2;
- sf_minor = 5;
- }
-
- /* Extremely old savefiles */
- if (sf_major > 2)
- {
- sf_major = 1;
- }
/* Clear screen */
Term_clear();
- /* Parse "new" savefiles */
- if ((sf_major == 2) && (sf_minor >= 7))
- {
- /* Attempt to load */
- err = rd_savefile_new();
- }
-
- /* Parse "future" savefiles */
- else
- {
- /* Error XXX XXX XXX */
- err = -1;
- }
+ /* Attempt to load */
+ err = rd_savefile_new();
/* Message (below) */
-#ifdef JP
- if (err) what = "¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤ò²òÀϽÐÍè¤Þ¤»¤ó¡£";
-#else
- if (err) what = "Cannot parse savefile";
-#endif
-
+ if (err) what = _("セーブファイルを解析出来ません。", "Cannot parse savefile");
}
/* Paranoia */
if (!turn) err = -1;
/* Message (below) */
-#ifdef JP
- if (err) what = "¥»¡¼¥Ö¥Õ¥¡¥¤¥ë¤¬²õ¤ì¤Æ¤¤¤Þ¤¹";
-#else
- if (err) what = "Broken savefile";
-#endif
-
+ if (err) what = _("セーブファイルが壊れています", "Broken savefile");
}
#ifdef VERIFY_TIMESTAMP
sf_when < (statbuf.st_ctime - 100))
{
/* Message */
-#ifdef JP
- what = "̵¸ú¤Ê¥¿¥¤¥à¡¦¥¹¥¿¥ó¥×¤Ç¤¹";
-#else
- what = "Invalid timestamp";
-#endif
-
+ what = _("無効なタイム・スタンプです", "Invalid timestamp");
/* Oops */
err = -1;
{
if (z_major == 2 && z_minor == 0 && z_patch == 6)
{
-#ifdef JP
- msg_print("¥Ð¡¼¥¸¥ç¥ó 2.0.* ÍѤΥ»¡¼¥Ö¥Õ¥¡¥¤¥ë¤òÊÑ´¹¤·¤Þ¤·¤¿¡£");
-#else
- msg_print("Converted a 2.0.* savefile.");
-#endif
-
+ msg_print(_("バージョン 2.0.* 用のセーブファイルを変換しました。", "Converted a 2.0.* savefile."));
}
else
{
/* Message */
#ifdef JP
- msg_format("¥Ð¡¼¥¸¥ç¥ó %d.%d.%d ÍѤΥ»¡¼¥Ö¡¦¥Õ¥¡¥¤¥ë¤òÊÑ´¹¤·¤Þ¤·¤¿¡£",
+ msg_format("バージョン %d.%d.%d 用のセーブ・ファイルを変換しました。",
+ (z_major > 9) ? z_major-10 : z_major , z_minor, z_patch);
#else
msg_format("Converted a %d.%d.%d savefile.",
-#endif
-
(z_major > 9) ? z_major-10 : z_major , z_minor, z_patch);
+#endif
}
msg_print(NULL);
}
/* Player is dead */
- if (death)
+ if (p_ptr->is_dead)
{
- /* Player is no longer "dead" */
- death = FALSE;
-
/* Cheat death */
if (arg_wizard)
{
return (TRUE);
}
+ /* Player is no longer "dead" */
+ p_ptr->is_dead = FALSE;
+
/* Count lives */
sf_lives++;
- /* Forget turns */
- turn = old_turn = 0;
-
/* Done */
return (TRUE);
}
/* Message */
#ifdef JP
- msg_format("¥¨¥é¡¼(%s)¤¬¥Ð¡¼¥¸¥ç¥ó%d.%d.%d ÍÑ¥»¡¼¥Ö¥Õ¥¡¥¤¥ëÆɤ߹þÃæ¤ËȯÀ¸¡£",
+ msg_format("エラー(%s)がバージョン%d.%d.%d 用セーブファイル読み込み中に発生。",
+ what, (z_major>9) ? z_major - 10 : z_major, z_minor, z_patch);
#else
msg_format("Error (%s) reading %d.%d.%d savefile.",
-#endif
-
what, (z_major>9) ? z_major - 10 : z_major, z_minor, z_patch);
+#endif
msg_print(NULL);
/* Oops */
return (FALSE);
}
-
+/*!
+ * @brief ファイルロック処理
+ * @return なし
+ */
void remove_loc(void)
{
#ifdef VERIFY_SAVEFILE
#endif /* SET_UID */
}
+
+
+/*!
+ * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporal saved floor file
+ * @param sf_ptr 保存フロア参照ポインタ
+ * @return なし
+ */
+static bool save_floor_aux(saved_floor_type *sf_ptr)
+{
+ byte tmp8u;
+
+ /* Compact the objects */
+ compact_objects(0);
+ /* Compact the monsters */
+ compact_monsters(0);
+
+
+ /*** Actually write the file ***/
+
+ /* Initial value of xor_byte */
+ tmp8u = (byte)randint0(256);
+ xor_byte = 0;
+ wr_byte(tmp8u);
+
+
+ /* Reset the checksum */
+ v_stamp = 0L;
+ x_stamp = 0L;
+
+ /* Write the sign of this process */
+ wr_u32b(saved_floor_file_sign);
+
+ /* Dump the dungeon floor */
+ wr_saved_floor(sf_ptr);
+
+
+ /* Write the "value check-sum" */
+ wr_u32b(v_stamp);
+
+ /* Write the "encoded checksum" */
+ wr_u32b(x_stamp);
+
+
+ /* Error in save */
+ if (ferror(fff) || (fflush(fff) == EOF)) return FALSE;
+
+ /* Successful save */
+ return TRUE;
+}
+
+
+/*!
+ * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporally saved-floor data
+ * @param sf_ptr 保存フロア参照ポインタ
+ * @param mode 保存オプション
+ * @return なし
+ */
+bool save_floor(saved_floor_type *sf_ptr, BIT_FLAGS mode)
+{
+ FILE *old_fff = NULL;
+ byte old_xor_byte = 0;
+ u32b old_v_stamp = 0;
+ u32b old_x_stamp = 0;
+
+ char floor_savefile[1024];
+ int fd = -1;
+ bool ok = FALSE;
+
+ if (!(mode & SLF_SECOND))
+ {
+#ifdef SET_UID
+# ifdef SECURE
+ /* Get "games" permissions */
+ beGames();
+# endif
+#endif
+ }
+
+ /* We have one file already opened */
+ else
+ {
+ /* Backup original values */
+ old_fff = fff;
+ old_xor_byte = xor_byte;
+ old_v_stamp = v_stamp;
+ old_x_stamp = x_stamp;
+ }
+
+ /* New savefile */
+ sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
+
+ /* Grab permissions */
+ safe_setuid_grab();
+
+ /* Remove it */
+ fd_kill(floor_savefile);
+
+ /* Drop permissions */
+ safe_setuid_drop();
+
+
+ /* Attempt to save the player */
+
+ /* No file yet */
+ fff = NULL;
+
+ /* File type is "SAVE" */
+ FILE_TYPE(FILE_TYPE_SAVE);
+
+ /* Grab permissions */
+ safe_setuid_grab();
+
+ /* Create the savefile */
+ fd = fd_make(floor_savefile, 0644);
+
+ /* Drop permissions */
+ safe_setuid_drop();
+
+ /* File is okay */
+ if (fd >= 0)
+ {
+ /* Close the "fd" */
+ (void)fd_close(fd);
+
+ /* Grab permissions */
+ safe_setuid_grab();
+
+ /* Open the savefile */
+ fff = my_fopen(floor_savefile, "wb");
+
+ /* Drop permissions */
+ safe_setuid_drop();
+
+ /* Successful open */
+ if (fff)
+ {
+ /* Write the savefile */
+ if (save_floor_aux(sf_ptr)) ok = TRUE;
+
+ /* Attempt to close it */
+ if (my_fclose(fff)) ok = FALSE;
+ }
+
+ /* Remove "broken" files */
+ if (!ok)
+ {
+ /* Grab permissions */
+ safe_setuid_grab();
+
+ (void)fd_kill(floor_savefile);
+
+ /* Drop permissions */
+ safe_setuid_drop();
+ }
+ }
+
+ if (!(mode & SLF_SECOND))
+ {
+#ifdef SET_UID
+# ifdef SECURE
+ /* Drop "games" permissions */
+ bePlayer();
+# endif
+#endif
+ }
+
+ /* We have one file already opened */
+ else
+ {
+ /* Restore original values */
+ fff = old_fff;
+ xor_byte = old_xor_byte;
+ v_stamp = old_v_stamp;
+ x_stamp = old_x_stamp;
+ }
+
+ /* Return the result */
+ return ok;
+}