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/uid-checker.h"
22 #include "io/report.h"
23 #include "monster-race/monster-race.h"
24 #include "monster/monster-compaction.h"
25 #include "object/object-kind.h"
26 #include "save/floor-writer.h"
27 #include "save/info-writer.h"
28 #include "save/item-writer.h"
29 #include "save/monster-writer.h"
30 #include "save/player-writer.h"
31 #include "save/save-util.h"
32 #include "store/store-owners.h"
33 #include "store/store-util.h"
34 #include "system/angband-version.h"
35 #include "system/artifact-type-definition.h"
36 #include "util/angband-files.h"
37 #include "view/display-messages.h"
38 #include "world/world.h"
41 * @brief セーブデータの書き込み /
42 * Actually write a save-file
43 * @param player_ptr プレーヤーへの参照ポインタ
46 static bool wr_savefile_new(player_type *player_ptr)
48 compact_objects(player_ptr, 0);
49 compact_monsters(player_ptr, 0);
51 u32b now = (u32b)time((time_t *)0);
52 current_world_ptr->sf_system = 0L;
53 current_world_ptr->sf_when = now;
54 current_world_ptr->sf_saves++;
56 wr_byte(FAKE_VER_MAJOR);
58 wr_byte(FAKE_VER_MINOR);
60 wr_byte(FAKE_VER_PATCH);
63 byte tmp8u = (byte)Rand_external(256);
72 wr_u32b(current_world_ptr->sf_system);
73 wr_u32b(current_world_ptr->sf_when);
74 wr_u16b(current_world_ptr->sf_lives);
75 wr_u16b(current_world_ptr->sf_saves);
94 u32b tmp32u = message_num();
95 if (compress_savefile && (tmp32u > 40))
99 for (int i = tmp32u - 1; i >= 0; i--)
100 wr_string(message_str((s16b)i));
102 u16b tmp16u = max_r_idx;
104 for (MONRACE_IDX r_idx = 0; r_idx < tmp16u; r_idx++)
109 for (KIND_OBJECT_IDX k_idx = 0; k_idx < tmp16u; k_idx++)
110 wr_perception(k_idx);
118 tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
121 for (int i = 0; i < max_q_idx; i++) {
122 quest_type *const q_ptr = &quest[i];
123 wr_s16b(q_ptr->status);
124 wr_s16b((s16b)q_ptr->level);
125 wr_byte((byte)q_ptr->complev);
126 wr_u32b(q_ptr->comptime);
128 bool is_quest_running = q_ptr->status == QUEST_STATUS_TAKEN;
129 is_quest_running |= q_ptr->status == QUEST_STATUS_COMPLETED;
130 is_quest_running |= !is_fixed_quest_idx(i);
131 if (!is_quest_running)
134 wr_s16b((s16b)q_ptr->cur_num);
135 wr_s16b((s16b)q_ptr->max_num);
136 wr_s16b(q_ptr->type);
137 wr_s16b(q_ptr->r_idx);
138 wr_s16b(q_ptr->k_idx);
139 wr_byte((byte)q_ptr->flags);
140 wr_byte((byte)q_ptr->dungeon);
143 wr_s32b(player_ptr->wilderness_x);
144 wr_s32b(player_ptr->wilderness_y);
145 wr_byte(player_ptr->wild_mode);
146 wr_byte(player_ptr->ambush_flag);
147 wr_s32b(current_world_ptr->max_wild_x);
148 wr_s32b(current_world_ptr->max_wild_y);
149 for (int i = 0; i < current_world_ptr->max_wild_x; i++)
150 for (int j = 0; j < current_world_ptr->max_wild_y; j++)
151 wr_u32b(wilderness[j][i].seed);
155 for (int i = 0; i < tmp16u; i++) {
156 artifact_type *a_ptr = &a_info[i];
157 wr_byte(a_ptr->cur_num);
158 wr_s16b(a_ptr->floor_id);
161 wr_player(player_ptr);
162 tmp16u = PY_MAX_LEVEL;
164 for (int i = 0; i < tmp16u; i++)
165 wr_s16b((s16b)player_ptr->player_hp[i]);
167 wr_u32b(player_ptr->spell_learned1);
168 wr_u32b(player_ptr->spell_learned2);
169 wr_u32b(player_ptr->spell_worked1);
170 wr_u32b(player_ptr->spell_worked2);
171 wr_u32b(player_ptr->spell_forgotten1);
172 wr_u32b(player_ptr->spell_forgotten2);
173 wr_s16b(player_ptr->learned_spells);
174 wr_s16b(player_ptr->add_spells);
175 for (int i = 0; i < 64; i++)
176 wr_byte((byte)player_ptr->spell_order[i]);
178 for (int i = 0; i < INVEN_TOTAL; i++) {
179 object_type *o_ptr = &player_ptr->inventory_list[i];
193 for (int i = 1; i < max_towns; i++)
194 for (int j = 0; j < MAX_STORES; j++)
195 wr_store(&town_info[i].store[j]);
197 wr_s16b(player_ptr->pet_follow_distance);
198 wr_s16b(player_ptr->pet_extra_flags);
199 if (screen_dump && (player_ptr->wait_report_score || !player_ptr->is_dead))
200 wr_string(screen_dump);
204 if (!player_ptr->is_dead) {
205 if (!wr_dungeon(player_ptr))
214 return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
218 * @brief セーブデータ書き込みのサブルーチン /
219 * Medium level player saver
220 * @param player_ptr プレーヤーへの参照ポインタ
223 * Angband 2.8.0 will use "fd" instead of "fff" if possible
225 static bool save_player_aux(player_type *player_ptr, char *name)
227 safe_setuid_grab(player_ptr);
228 int file_permission = 0644;
229 int fd = fd_make(name, file_permission);
232 bool is_save_successful = FALSE;
233 saving_savefile = NULL;
236 safe_setuid_grab(player_ptr);
237 saving_savefile = angband_fopen(name, "wb");
239 if (saving_savefile) {
240 if (wr_savefile_new(player_ptr))
241 is_save_successful = TRUE;
243 if (angband_fclose(saving_savefile))
244 is_save_successful = FALSE;
247 safe_setuid_grab(player_ptr);
248 if (!is_save_successful)
254 if (!is_save_successful)
257 counts_write(player_ptr, 0, current_world_ptr->play_time);
258 current_world_ptr->character_saved = TRUE;
263 * @brief セーブデータ書き込みのメインルーチン /
264 * Attempt to save the player in a savefile
265 * @param player_ptr プレーヤーへの参照ポインタ
268 bool save_player(player_type *player_ptr)
271 strcpy(safe, savefile);
272 strcat(safe, ".new");
273 safe_setuid_grab(player_ptr);
278 if (save_player_aux(player_ptr, safe)) {
280 strcpy(temp, savefile);
281 strcat(temp, ".old");
282 safe_setuid_grab(player_ptr);
284 fd_move(savefile, temp);
285 fd_move(safe, savefile);
288 current_world_ptr->character_loaded = TRUE;