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/report.h"
22 #include "io/uid-checker.h"
23 #include "monster-race/monster-race.h"
24 #include "monster/monster-compaction.h"
25 #include "monster/monster-status.h"
26 #include "object/object-kind.h"
27 #include "save/floor-writer.h"
28 #include "save/info-writer.h"
29 #include "save/item-writer.h"
30 #include "save/monster-writer.h"
31 #include "save/player-writer.h"
32 #include "save/save-util.h"
33 #include "store/store-owners.h"
34 #include "store/store-util.h"
35 #include "system/angband-version.h"
36 #include "system/artifact-type-definition.h"
37 #include "util/angband-files.h"
38 #include "view/display-messages.h"
39 #include "world/world.h"
42 * @brief セーブデータの書き込み /
43 * Actually write a save-file
44 * @param player_ptr プレーヤーへの参照ポインタ
47 static bool wr_savefile_new(player_type *player_ptr, save_type type)
49 compact_objects(player_ptr, 0);
50 compact_monsters(player_ptr, 0);
52 u32b now = (u32b)time((time_t *)0);
53 current_world_ptr->sf_system = 0L;
54 current_world_ptr->sf_when = now;
55 current_world_ptr->sf_saves++;
57 wr_byte(FAKE_VER_MAJOR);
59 wr_byte(FAKE_VER_MINOR);
61 wr_byte(FAKE_VER_PATCH);
64 byte tmp8u = (byte)Rand_external(256);
73 wr_u32b(current_world_ptr->sf_system);
74 wr_u32b(current_world_ptr->sf_when);
75 wr_u16b(current_world_ptr->sf_lives);
76 wr_u16b(current_world_ptr->sf_saves);
95 u32b tmp32u = message_num();
96 if (compress_savefile && (tmp32u > 40))
100 for (int i = tmp32u - 1; i >= 0; i--)
101 wr_string(message_str((s16b)i));
103 u16b tmp16u = max_r_idx;
105 for (MONRACE_IDX r_idx = 0; r_idx < tmp16u; r_idx++)
110 for (KIND_OBJECT_IDX k_idx = 0; k_idx < tmp16u; k_idx++)
111 wr_perception(k_idx);
119 tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
122 for (int i = 0; i < max_q_idx; i++) {
123 quest_type *const q_ptr = &quest[i];
124 wr_s16b(q_ptr->status);
125 wr_s16b((s16b)q_ptr->level);
126 wr_byte((byte)q_ptr->complev);
127 wr_u32b(q_ptr->comptime);
129 bool is_quest_running = q_ptr->status == QUEST_STATUS_TAKEN;
130 is_quest_running |= q_ptr->status == QUEST_STATUS_COMPLETED;
131 is_quest_running |= !is_fixed_quest_idx(i);
132 if (!is_quest_running)
135 wr_s16b((s16b)q_ptr->cur_num);
136 wr_s16b((s16b)q_ptr->max_num);
137 wr_s16b(q_ptr->type);
138 wr_s16b(q_ptr->r_idx);
139 wr_s16b(q_ptr->k_idx);
140 wr_byte((byte)q_ptr->flags);
141 wr_byte((byte)q_ptr->dungeon);
144 wr_s32b(player_ptr->wilderness_x);
145 wr_s32b(player_ptr->wilderness_y);
146 wr_byte(player_ptr->wild_mode);
147 wr_byte(player_ptr->ambush_flag);
148 wr_s32b(current_world_ptr->max_wild_x);
149 wr_s32b(current_world_ptr->max_wild_y);
150 for (int i = 0; i < current_world_ptr->max_wild_x; i++)
151 for (int j = 0; j < current_world_ptr->max_wild_y; j++)
152 wr_u32b(wilderness[j][i].seed);
156 for (int i = 0; i < tmp16u; i++) {
157 artifact_type *a_ptr = &a_info[i];
158 wr_byte(a_ptr->cur_num);
159 wr_s16b(a_ptr->floor_id);
162 wr_player(player_ptr);
163 tmp16u = PY_MAX_LEVEL;
165 for (int i = 0; i < tmp16u; i++)
166 wr_s16b((s16b)player_ptr->player_hp[i]);
168 wr_u32b(player_ptr->spell_learned1);
169 wr_u32b(player_ptr->spell_learned2);
170 wr_u32b(player_ptr->spell_worked1);
171 wr_u32b(player_ptr->spell_worked2);
172 wr_u32b(player_ptr->spell_forgotten1);
173 wr_u32b(player_ptr->spell_forgotten2);
174 wr_s16b(player_ptr->learned_spells);
175 wr_s16b(player_ptr->add_spells);
176 for (int i = 0; i < 64; i++)
177 wr_byte((byte)player_ptr->spell_order[i]);
179 for (int i = 0; i < INVEN_TOTAL; i++) {
180 object_type *o_ptr = &player_ptr->inventory_list[i];
194 for (int i = 1; i < max_towns; i++)
195 for (int j = 0; j < MAX_STORES; j++)
196 wr_store(&town_info[i].store[j]);
198 wr_s16b(player_ptr->pet_follow_distance);
199 wr_s16b(player_ptr->pet_extra_flags);
200 if (screen_dump && (player_ptr->wait_report_score || !player_ptr->is_dead))
201 wr_string(screen_dump);
205 if (!player_ptr->is_dead) {
206 if (!wr_dungeon(player_ptr))
215 return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
219 * @brief セーブデータ書き込みのサブルーチン /
220 * Medium level player saver
221 * @param player_ptr プレーヤーへの参照ポインタ
224 * Angband 2.8.0 will use "fd" instead of "fff" if possible
226 static bool save_player_aux(player_type *player_ptr, char *name, save_type type)
228 safe_setuid_grab(player_ptr);
229 int file_permission = 0644;
230 int fd = fd_make(name, file_permission);
233 bool is_save_successful = FALSE;
234 saving_savefile = NULL;
237 safe_setuid_grab(player_ptr);
238 saving_savefile = angband_fopen(name, "wb");
240 if (saving_savefile) {
241 if (wr_savefile_new(player_ptr, type))
242 is_save_successful = TRUE;
244 if (angband_fclose(saving_savefile))
245 is_save_successful = FALSE;
248 safe_setuid_grab(player_ptr);
249 if (!is_save_successful)
255 if (!is_save_successful)
258 counts_write(player_ptr, 0, current_world_ptr->play_time);
259 current_world_ptr->character_saved = TRUE;
264 * @brief セーブデータ書き込みのメインルーチン /
265 * Attempt to save the player in a savefile
266 * @param player_ptr プレーヤーへの参照ポインタ
269 bool save_player(player_type *player_ptr, save_type type)
272 strcpy(safe, savefile);
273 strcat(safe, ".new");
274 safe_setuid_grab(player_ptr);
279 if (save_player_aux(player_ptr, safe, type)) {
282 strcpy(temp, savefile);
283 strcat(temp, ".old");
284 safe_setuid_grab(player_ptr);
287 if (type == SAVE_TYPE_DEBUG)
288 strcpy(filename, debug_savefile);
289 if (type != SAVE_TYPE_DEBUG)
290 strcpy(filename, savefile);
292 fd_move(filename, temp);
293 fd_move(safe, filename);
296 current_world_ptr->character_loaded = TRUE;
300 if (type != SAVE_TYPE_CLOSE_GAME) {
301 current_world_ptr->is_loading_now = FALSE;
302 update_creature(player_ptr);
303 mproc_init(player_ptr->current_floor_ptr);
304 current_world_ptr->is_loading_now = TRUE;