OSDN Git Service

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