3 * @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
7 * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
8 * This software may be copied and distributed for educational, research,
9 * and not for profit purposes provided that this copyright and statement
10 * are included in all such copies. Other copyrights may also apply.
14 #include "save/save.h"
15 #include "core/object-compressor.h"
16 #include "dungeon/quest.h"
17 #include "floor/floor-town.h"
18 #include "floor/wild.h"
19 #include "game-option/text-display-options.h"
20 #include "inventory/inventory-slot-types.h"
21 #include "io/files-util.h"
22 #include "io/report.h"
23 #include "io/uid-checker.h"
24 #include "monster-race/monster-race.h"
25 #include "monster/monster-compaction.h"
26 #include "monster/monster-status.h"
27 #include "object/object-kind.h"
28 #include "save/floor-writer.h"
29 #include "save/info-writer.h"
30 #include "save/item-writer.h"
31 #include "save/monster-writer.h"
32 #include "save/player-writer.h"
33 #include "save/save-util.h"
34 #include "store/store-owners.h"
35 #include "store/store-util.h"
36 #include "system/angband-version.h"
37 #include "system/artifact-type-definition.h"
38 #include "util/angband-files.h"
39 #include "view/display-messages.h"
40 #include "world/world.h"
43 * @brief セーブデータの書き込み /
44 * Actually write a save-file
45 * @param player_ptr プレーヤーへの参照ポインタ
48 static bool wr_savefile_new(player_type *player_ptr, save_type type)
50 compact_objects(player_ptr, 0);
51 compact_monsters(player_ptr, 0);
53 u32b now = (u32b)time((time_t *)0);
54 current_world_ptr->sf_system = 0L;
55 current_world_ptr->sf_when = now;
56 current_world_ptr->sf_saves++;
58 wr_byte(FAKE_VER_MAJOR);
60 wr_byte(FAKE_VER_MINOR);
62 wr_byte(FAKE_VER_PATCH);
65 byte tmp8u = (byte)Rand_external(256);
74 wr_u32b(current_world_ptr->sf_system);
75 wr_u32b(current_world_ptr->sf_when);
76 wr_u16b(current_world_ptr->sf_lives);
77 wr_u16b(current_world_ptr->sf_saves);
79 wr_u32b(SAVEFILE_VERSION);
96 u32b tmp32u = message_num();
97 if ((compress_savefile || (type == SAVE_TYPE_DEBUG)) && (tmp32u > 40))
101 for (int i = tmp32u - 1; i >= 0; i--)
102 wr_string(message_str((s16b)i));
104 u16b tmp16u = max_r_idx;
106 for (MONRACE_IDX r_idx = 0; r_idx < tmp16u; r_idx++)
111 for (KIND_OBJECT_IDX k_idx = 0; k_idx < tmp16u; k_idx++)
112 wr_perception(k_idx);
120 tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
123 for (int i = 0; i < max_q_idx; i++) {
124 quest_type *const q_ptr = &quest[i];
125 wr_s16b(q_ptr->status);
126 wr_s16b((s16b)q_ptr->level);
127 wr_byte((byte)q_ptr->complev);
128 wr_u32b(q_ptr->comptime);
130 bool is_quest_running = q_ptr->status == QUEST_STATUS_TAKEN;
131 is_quest_running |= q_ptr->status == QUEST_STATUS_COMPLETED;
132 is_quest_running |= !is_fixed_quest_idx(i);
133 if (!is_quest_running)
136 wr_s16b((s16b)q_ptr->cur_num);
137 wr_s16b((s16b)q_ptr->max_num);
138 wr_s16b(q_ptr->type);
139 wr_s16b(q_ptr->r_idx);
140 wr_s16b(q_ptr->k_idx);
141 wr_byte((byte)q_ptr->flags);
142 wr_byte((byte)q_ptr->dungeon);
145 wr_s32b(player_ptr->wilderness_x);
146 wr_s32b(player_ptr->wilderness_y);
147 wr_byte(player_ptr->wild_mode);
148 wr_byte(player_ptr->ambush_flag);
149 wr_s32b(current_world_ptr->max_wild_x);
150 wr_s32b(current_world_ptr->max_wild_y);
151 for (int i = 0; i < current_world_ptr->max_wild_x; i++)
152 for (int j = 0; j < current_world_ptr->max_wild_y; j++)
153 wr_u32b(wilderness[j][i].seed);
157 for (int i = 0; i < tmp16u; i++) {
158 artifact_type *a_ptr = &a_info[i];
159 wr_byte(a_ptr->cur_num);
160 wr_s16b(a_ptr->floor_id);
163 wr_player(player_ptr);
164 tmp16u = PY_MAX_LEVEL;
166 for (int i = 0; i < tmp16u; i++)
167 wr_s16b((s16b)player_ptr->player_hp[i]);
169 wr_u32b(player_ptr->spell_learned1);
170 wr_u32b(player_ptr->spell_learned2);
171 wr_u32b(player_ptr->spell_worked1);
172 wr_u32b(player_ptr->spell_worked2);
173 wr_u32b(player_ptr->spell_forgotten1);
174 wr_u32b(player_ptr->spell_forgotten2);
175 wr_s16b(player_ptr->learned_spells);
176 wr_s16b(player_ptr->add_spells);
177 for (int i = 0; i < 64; i++)
178 wr_byte((byte)player_ptr->spell_order[i]);
180 for (int i = 0; i < INVEN_TOTAL; i++) {
181 object_type *o_ptr = &player_ptr->inventory_list[i];
195 for (int i = 1; i < max_towns; i++)
196 for (int j = 0; j < MAX_STORES; j++)
197 wr_store(&town_info[i].store[j]);
199 wr_s16b(player_ptr->pet_follow_distance);
200 wr_s16b(player_ptr->pet_extra_flags);
201 if (screen_dump && (player_ptr->wait_report_score || !player_ptr->is_dead))
202 wr_string(screen_dump);
206 if (!player_ptr->is_dead) {
207 if (!wr_dungeon(player_ptr))
216 return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
220 * @brief セーブデータ書き込みのサブルーチン /
221 * Medium level player saver
222 * @param player_ptr プレーヤーへの参照ポインタ
225 * Angband 2.8.0 will use "fd" instead of "fff" if possible
227 static bool save_player_aux(player_type *player_ptr, char *name, save_type type)
229 safe_setuid_grab(player_ptr);
230 int file_permission = 0644;
231 int fd = fd_make(name, file_permission);
234 bool is_save_successful = FALSE;
235 saving_savefile = NULL;
238 safe_setuid_grab(player_ptr);
239 saving_savefile = angband_fopen(name, "wb");
241 if (saving_savefile) {
242 if (wr_savefile_new(player_ptr, type))
243 is_save_successful = TRUE;
245 if (angband_fclose(saving_savefile))
246 is_save_successful = FALSE;
249 safe_setuid_grab(player_ptr);
250 if (!is_save_successful)
256 if (!is_save_successful)
259 counts_write(player_ptr, 0, current_world_ptr->play_time);
260 current_world_ptr->character_saved = TRUE;
265 * @brief セーブデータ書き込みのメインルーチン /
266 * Attempt to save the player in a savefile
267 * @param player_ptr プレーヤーへの参照ポインタ
270 bool save_player(player_type *player_ptr, save_type type)
273 strcpy(safe, savefile);
274 strcat(safe, ".new");
275 safe_setuid_grab(player_ptr);
280 if (save_player_aux(player_ptr, safe, type)) {
283 strcpy(temp, savefile);
284 strcat(temp, ".old");
285 safe_setuid_grab(player_ptr);
288 if (type == SAVE_TYPE_DEBUG)
289 strcpy(filename, debug_savefile);
290 if (type != SAVE_TYPE_DEBUG)
291 strcpy(filename, savefile);
293 fd_move(filename, temp);
294 fd_move(safe, filename);
297 current_world_ptr->character_loaded = TRUE;
301 if (type != SAVE_TYPE_CLOSE_GAME) {
302 current_world_ptr->is_loading_now = FALSE;
303 update_creature(player_ptr);
304 mproc_init(player_ptr->current_floor_ptr);
305 current_world_ptr->is_loading_now = TRUE;