OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / save / save.cpp
1 /*!
2  * @file save.c
3  * @brief セーブファイル書き込み処理 / Purpose: interact with savefiles
4  * @date 2014/07/12
5  * @author
6  * <pre>
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.
11  * </pre>
12  */
13
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"
41
42 /*!
43  * @brief セーブデータの書き込み /
44  * Actually write a save-file
45  * @param player_ptr プレーヤーへの参照ポインタ
46  * @return 成功すればtrue
47  */
48 static bool wr_savefile_new(player_type *player_ptr, save_type type)
49 {
50     compact_objects(player_ptr, 0);
51     compact_monsters(player_ptr, 0);
52
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++;
57     save_xor_byte = 0;
58     wr_byte(FAKE_VER_MAJOR);
59     save_xor_byte = 0;
60     wr_byte(FAKE_VER_MINOR);
61     save_xor_byte = 0;
62     wr_byte(FAKE_VER_PATCH);
63     save_xor_byte = 0;
64
65     byte tmp8u = (byte)Rand_external(256);
66     wr_byte(tmp8u);
67     v_stamp = 0L;
68     x_stamp = 0L;
69
70     wr_byte(H_VER_EXTRA);
71     wr_byte(H_VER_PATCH);
72     wr_byte(H_VER_MINOR);
73     wr_byte(H_VER_MAJOR);
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);
78
79     wr_u32b(SAVEFILE_VERSION);
80     wr_u16b(0);
81     wr_byte(0);
82
83 #ifdef JP
84 #ifdef EUC
85     wr_byte(2);
86 #endif
87 #ifdef SJIS
88     wr_byte(3);
89 #endif
90 #else
91     wr_byte(1);
92 #endif
93
94     wr_randomizer();
95     wr_options(type);
96     u32b tmp32u = message_num();
97     if ((compress_savefile || (type == SAVE_TYPE_DEBUG)) && (tmp32u > 40))
98         tmp32u = 40;
99
100     wr_u32b(tmp32u);
101     for (int i = tmp32u - 1; i >= 0; i--)
102         wr_string(message_str((s16b)i));
103
104     u16b tmp16u = max_r_idx;
105     wr_u16b(tmp16u);
106     for (MONRACE_IDX r_idx = 0; r_idx < tmp16u; r_idx++)
107         wr_lore(r_idx);
108
109     tmp16u = max_k_idx;
110     wr_u16b(tmp16u);
111     for (KIND_OBJECT_IDX k_idx = 0; k_idx < tmp16u; k_idx++)
112         wr_perception(k_idx);
113
114     tmp16u = max_towns;
115     wr_u16b(tmp16u);
116
117     tmp16u = max_q_idx;
118     wr_u16b(tmp16u);
119
120     tmp8u = MAX_RANDOM_QUEST - MIN_RANDOM_QUEST;
121     wr_byte(tmp8u);
122
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);
129
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)
134             continue;
135
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);
143     }
144
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);
154
155     tmp16u = max_a_idx;
156     wr_u16b(tmp16u);
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);
161     }
162
163     wr_player(player_ptr);
164     tmp16u = PY_MAX_LEVEL;
165     wr_u16b(tmp16u);
166     for (int i = 0; i < tmp16u; i++)
167         wr_s16b((s16b)player_ptr->player_hp[i]);
168
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]);
179
180     for (int i = 0; i < INVEN_TOTAL; i++) {
181         object_type *o_ptr = &player_ptr->inventory_list[i];
182         if (!o_ptr->k_idx)
183             continue;
184
185         wr_u16b((u16b)i);
186         wr_item(o_ptr);
187     }
188
189     wr_u16b(0xFFFF);
190     tmp16u = max_towns;
191     wr_u16b(tmp16u);
192
193     tmp16u = MAX_STORES;
194     wr_u16b(tmp16u);
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]);
198
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);
203     else
204         wr_string("");
205
206     if (!player_ptr->is_dead) {
207         if (!wr_dungeon(player_ptr))
208             return FALSE;
209
210         wr_ghost();
211         wr_s32b(0);
212     }
213
214     wr_u32b(v_stamp);
215     wr_u32b(x_stamp);
216     return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
217 }
218
219 /*!
220  * @brief セーブデータ書き込みのサブルーチン /
221  * Medium level player saver
222  * @param player_ptr プレーヤーへの参照ポインタ
223  * @return 成功すればtrue
224  * @details
225  * Angband 2.8.0 will use "fd" instead of "fff" if possible
226  */
227 static bool save_player_aux(player_type *player_ptr, char *name, save_type type)
228 {
229     safe_setuid_grab(player_ptr);
230     int file_permission = 0644;
231     int fd = fd_make(name, file_permission);
232     safe_setuid_drop();
233
234     bool is_save_successful = FALSE;
235     saving_savefile = NULL;
236     if (fd >= 0) {
237         (void)fd_close(fd);
238         safe_setuid_grab(player_ptr);
239         saving_savefile = angband_fopen(name, "wb");
240         safe_setuid_drop();
241         if (saving_savefile) {
242             if (wr_savefile_new(player_ptr, type))
243                 is_save_successful = TRUE;
244
245             if (angband_fclose(saving_savefile))
246                 is_save_successful = FALSE;
247         }
248
249         safe_setuid_grab(player_ptr);
250         if (!is_save_successful)
251             (void)fd_kill(name);
252
253         safe_setuid_drop();
254     }
255
256     if (!is_save_successful)
257         return FALSE;
258
259     counts_write(player_ptr, 0, current_world_ptr->play_time);
260     current_world_ptr->character_saved = TRUE;
261     return TRUE;
262 }
263
264 /*!
265  * @brief セーブデータ書き込みのメインルーチン /
266  * Attempt to save the player in a savefile
267  * @param player_ptr プレーヤーへの参照ポインタ
268  * @return 成功すればtrue
269  */
270 bool save_player(player_type *player_ptr, save_type type)
271 {
272     char safe[1024];
273     strcpy(safe, savefile);
274     strcat(safe, ".new");
275     safe_setuid_grab(player_ptr);
276     fd_kill(safe);
277     safe_setuid_drop();
278     update_playtime();
279     bool result = FALSE;
280     if (save_player_aux(player_ptr, safe, type)) {
281         char temp[1024];
282         char filename[1024];
283         strcpy(temp, savefile);
284         strcat(temp, ".old");
285         safe_setuid_grab(player_ptr);
286         fd_kill(temp);
287
288         if (type == SAVE_TYPE_DEBUG)
289             strcpy(filename, debug_savefile);
290         if (type != SAVE_TYPE_DEBUG)
291             strcpy(filename, savefile);
292
293         fd_move(filename, temp);
294         fd_move(safe, filename);
295         fd_kill(temp);
296         safe_setuid_drop();
297         current_world_ptr->character_loaded = TRUE;
298         result = TRUE;
299     }
300
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;
306     }
307
308     return result;
309 }