OSDN Git Service

v3.0.0 Alpha5 OSDN最終版
[hengband/hengband.git] / src / save / floor-writer.c
1 #include "save/floor-writer.h"
2 #include "core/object-compressor.h"
3 #include "core/player-update-types.h"
4 #include "floor/floor-events.h"
5 #include "floor/floor-save-util.h"
6 #include "floor/floor-save.h"
7 #include "grid/grid.h"
8 #include "io/files-util.h"
9 #include "io/uid-checker.h"
10 #include "load/floor-loader.h"
11 #include "monster-floor/monster-lite.h"
12 #include "monster/monster-compaction.h"
13 #include "save/item-writer.h"
14 #include "save/monster-writer.h"
15 #include "save/save-util.h"
16 #include "system/floor-type-definition.h"
17 #include "system/object-type-definition.h"
18 #include "util/angband-files.h"
19 #include "util/sort.h"
20
21 /*!
22  * @brief 保存フロアの書き込み / Actually write a saved floor data using effectively compressed format.
23  * @param sf_ptr 保存したいフロアの参照ポインタ
24  * @return なし
25  */
26 void wr_saved_floor(player_type *player_ptr, saved_floor_type *sf_ptr)
27 {
28     floor_type *floor_ptr = player_ptr->current_floor_ptr;
29     if (!sf_ptr) {
30         wr_s16b((s16b)floor_ptr->dun_level);
31     } else {
32         wr_s16b(sf_ptr->floor_id);
33         wr_byte((byte)sf_ptr->savefile_id);
34         wr_s16b((s16b)sf_ptr->dun_level);
35         wr_s32b(sf_ptr->last_visit);
36         wr_u32b(sf_ptr->visit_mark);
37         wr_s16b(sf_ptr->upper_floor_id);
38         wr_s16b(sf_ptr->lower_floor_id);
39     }
40
41     wr_u16b((u16b)floor_ptr->base_level);
42     wr_u16b((s16b)player_ptr->current_floor_ptr->num_repro);
43     wr_u16b((u16b)player_ptr->y);
44     wr_u16b((u16b)player_ptr->x);
45     wr_u16b((u16b)floor_ptr->height);
46     wr_u16b((u16b)floor_ptr->width);
47     wr_byte(player_ptr->feeling);
48
49     /*
50      * Usually number of templates are fewer than 255.  Even if
51      * more than 254 are exist, the occurrence of each template
52      * with larger ID is very small when we sort templates by
53      * occurrence.  So we will use two (or more) bytes for
54      * templete ID larger than 254.
55      *
56      * Ex: 256 will be "0xff" "0x01".
57      *     515 will be "0xff" "0xff" "0x03"
58      */
59
60     /* Fake max number */
61     u16b max_num_temp = 255;
62
63     grid_template_type *templates;
64     C_MAKE(templates, max_num_temp, grid_template_type);
65     u16b num_temp = 0;
66     for (int y = 0; y < floor_ptr->height; y++) {
67         for (int x = 0; x < floor_ptr->width; x++) {
68             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
69             int i;
70             for (i = 0; i < num_temp; i++) {
71                 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
72                     && templates[i].special == g_ptr->special) {
73                     templates[i].occurrence++;
74                     break;
75                 }
76             }
77
78             if (i < num_temp)
79                 continue;
80
81             if (num_temp >= max_num_temp) {
82                 grid_template_type *old_template = templates;
83                 C_MAKE(templates, max_num_temp + 255, grid_template_type);
84                 (void)C_COPY(templates, old_template, max_num_temp, grid_template_type);
85                 C_KILL(old_template, max_num_temp, grid_template_type);
86                 max_num_temp += 255;
87             }
88
89             templates[num_temp].info = g_ptr->info;
90             templates[num_temp].feat = g_ptr->feat;
91             templates[num_temp].mimic = g_ptr->mimic;
92             templates[num_temp].special = g_ptr->special;
93             templates[num_temp].occurrence = 1;
94             num_temp++;
95         }
96     }
97
98     int dummy_why;
99     ang_sort(player_ptr, templates, &dummy_why, num_temp, ang_sort_comp_cave_temp, ang_sort_swap_cave_temp);
100
101     /*** Dump templates ***/
102     wr_u16b(num_temp);
103     for (int i = 0; i < num_temp; i++) {
104         grid_template_type *ct_ptr = &templates[i];
105         wr_u16b((u16b)ct_ptr->info);
106         wr_s16b(ct_ptr->feat);
107         wr_s16b(ct_ptr->mimic);
108         wr_s16b(ct_ptr->special);
109     }
110
111     byte count = 0;
112     u16b prev_u16b = 0;
113     for (int y = 0; y < floor_ptr->height; y++) {
114         for (int x = 0; x < floor_ptr->width; x++) {
115             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
116             int i;
117             for (i = 0; i < num_temp; i++) {
118                 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
119                     && templates[i].special == g_ptr->special)
120                     break;
121             }
122
123             u16b tmp16u = (u16b)i;
124             if ((tmp16u == prev_u16b) && (count != MAX_UCHAR)) {
125                 count++;
126                 continue;
127             }
128
129             wr_byte((byte)count);
130             while (prev_u16b >= MAX_UCHAR) {
131                 wr_byte(MAX_UCHAR);
132                 prev_u16b -= MAX_UCHAR;
133             }
134
135             wr_byte((byte)prev_u16b);
136             prev_u16b = tmp16u;
137             count = 1;
138         }
139     }
140
141     if (count > 0) {
142         wr_byte((byte)count);
143         while (prev_u16b >= MAX_UCHAR) {
144             wr_byte(MAX_UCHAR);
145             prev_u16b -= MAX_UCHAR;
146         }
147
148         wr_byte((byte)prev_u16b);
149     }
150
151     C_KILL(templates, max_num_temp, grid_template_type);
152
153     /*** Dump objects ***/
154     wr_u16b(floor_ptr->o_max);
155     for (int i = 1; i < floor_ptr->o_max; i++) {
156         object_type *o_ptr = &floor_ptr->o_list[i];
157         wr_item(o_ptr);
158     }
159
160     /*** Dump the monsters ***/
161     wr_u16b(floor_ptr->m_max);
162     for (int i = 1; i < floor_ptr->m_max; i++) {
163         monster_type *m_ptr = &floor_ptr->m_list[i];
164         wr_monster(m_ptr);
165     }
166 }
167
168 /*!
169  * @brief 現在フロアの書き込み /
170  * Write the current dungeon (new method)
171  * @player_ptr プレーヤーへの参照ポインタ
172  * @return 保存に成功したらTRUE
173  */
174 bool wr_dungeon(player_type *player_ptr)
175 {
176     forget_lite(player_ptr->current_floor_ptr);
177     forget_view(player_ptr->current_floor_ptr);
178     clear_mon_lite(player_ptr->current_floor_ptr);
179     player_ptr->update |= PU_VIEW | PU_LITE | PU_MON_LITE;
180     player_ptr->update |= PU_MONSTERS | PU_DISTANCE | PU_FLOW;
181     wr_s16b(max_floor_id);
182     wr_byte((byte)player_ptr->dungeon_idx);
183     if (!player_ptr->floor_id) {
184         /* No array elements */
185         wr_byte(0);
186         wr_saved_floor(player_ptr, NULL);
187         return TRUE;
188     }
189
190     /*** In the dungeon ***/
191     wr_byte(MAX_SAVED_FLOORS);
192     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
193         saved_floor_type *sf_ptr = &saved_floors[i];
194         wr_s16b(sf_ptr->floor_id);
195         wr_byte((byte)sf_ptr->savefile_id);
196         wr_s16b((s16b)sf_ptr->dun_level);
197         wr_s32b(sf_ptr->last_visit);
198         wr_u32b(sf_ptr->visit_mark);
199         wr_s16b(sf_ptr->upper_floor_id);
200         wr_s16b(sf_ptr->lower_floor_id);
201     }
202
203     saved_floor_type *cur_sf_ptr;
204     cur_sf_ptr = get_sf_ptr(player_ptr->floor_id);
205     if (!save_floor(player_ptr, cur_sf_ptr, SLF_SECOND))
206         return FALSE;
207
208     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
209         saved_floor_type *sf_ptr = &saved_floors[i];
210         if (!sf_ptr->floor_id)
211             continue;
212         if (!load_floor(player_ptr, sf_ptr, (SLF_SECOND | SLF_NO_KILL))) {
213             wr_byte(1);
214             continue;
215         }
216
217         wr_byte(0);
218         wr_saved_floor(player_ptr, sf_ptr);
219     }
220
221     return load_floor(player_ptr, cur_sf_ptr, (SLF_SECOND));
222 }
223
224 /*!
225  * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporary saved floor file
226  * @param player_ptr プレーヤーへの参照ポインタ
227  * @param sf_ptr 保存フロア参照ポインタ
228  * @return なし
229  */
230 static bool save_floor_aux(player_type *player_ptr, saved_floor_type *sf_ptr)
231 {
232     compact_objects(player_ptr, 0);
233     compact_monsters(player_ptr, 0);
234
235     byte tmp8u = (byte)randint0(256);
236     save_xor_byte = 0;
237     wr_byte(tmp8u);
238
239     /* Reset the checksum */
240     v_stamp = 0L;
241     x_stamp = 0L;
242     wr_u32b(saved_floor_file_sign);
243     wr_saved_floor(player_ptr, sf_ptr);
244     wr_u32b(v_stamp);
245     wr_u32b(x_stamp);
246
247     return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
248 }
249 /*!
250  * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporarily saved-floor data
251  * @param player_ptr プレーヤーへの参照ポインタ
252  * @param sf_ptr 保存フロア参照ポインタ
253  * @param mode 保存オプション
254  * @return なし
255  */
256 bool save_floor(player_type *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode)
257 {
258     FILE *old_fff = NULL;
259     byte old_xor_byte = 0;
260     u32b old_v_stamp = 0;
261     u32b old_x_stamp = 0;
262
263     char floor_savefile[1024];
264     if ((mode & SLF_SECOND) != 0) {
265         old_fff = saving_savefile;
266         old_xor_byte = save_xor_byte;
267         old_v_stamp = v_stamp;
268         old_x_stamp = x_stamp;
269     }
270
271     sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
272     safe_setuid_grab(player_ptr);
273     fd_kill(floor_savefile);
274     safe_setuid_drop();
275     saving_savefile = NULL;
276     safe_setuid_grab(player_ptr);
277
278     int fd = fd_make(floor_savefile, 0644);
279     safe_setuid_drop();
280     bool is_save_successful = FALSE;
281     if (fd >= 0) {
282         (void)fd_close(fd);
283         safe_setuid_grab(player_ptr);
284         saving_savefile = angband_fopen(floor_savefile, "wb");
285         safe_setuid_drop();
286         if (saving_savefile) {
287             if (save_floor_aux(player_ptr, sf_ptr))
288                 is_save_successful = TRUE;
289
290             if (angband_fclose(saving_savefile))
291                 is_save_successful = FALSE;
292         }
293
294         if (!is_save_successful) {
295             safe_setuid_grab(player_ptr);
296             (void)fd_kill(floor_savefile);
297             safe_setuid_drop();
298         }
299     }
300
301     if ((mode & SLF_SECOND) != 0) {
302         saving_savefile = old_fff;
303         save_xor_byte = old_xor_byte;
304         v_stamp = old_v_stamp;
305         x_stamp = old_x_stamp;
306     }
307
308     return is_save_successful;
309 }