OSDN Git Service

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