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"
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"
22 * @brief 保存フロアの書き込み / Actually write a saved floor data using effectively compressed format.
23 * @param sf_ptr 保存したいフロアの参照ポインタ
25 void wr_saved_floor(player_type *player_ptr, saved_floor_type *sf_ptr)
27 floor_type *floor_ptr = player_ptr->current_floor_ptr;
29 wr_s16b((s16b)floor_ptr->dun_level);
31 wr_s16b(sf_ptr->floor_id);
32 wr_byte((byte)sf_ptr->savefile_id);
33 wr_s16b((s16b)sf_ptr->dun_level);
34 wr_s32b(sf_ptr->last_visit);
35 wr_u32b(sf_ptr->visit_mark);
36 wr_s16b(sf_ptr->upper_floor_id);
37 wr_s16b(sf_ptr->lower_floor_id);
40 wr_u16b((u16b)floor_ptr->base_level);
41 wr_u16b((s16b)player_ptr->current_floor_ptr->num_repro);
42 wr_u16b((u16b)player_ptr->y);
43 wr_u16b((u16b)player_ptr->x);
44 wr_u16b((u16b)floor_ptr->height);
45 wr_u16b((u16b)floor_ptr->width);
46 wr_byte(player_ptr->feeling);
49 * Usually number of templates are fewer than 255. Even if
50 * more than 254 are exist, the occurrence of each template
51 * with larger ID is very small when we sort templates by
52 * occurrence. So we will use two (or more) bytes for
53 * templete ID larger than 254.
55 * Ex: 256 will be "0xff" "0x01".
56 * 515 will be "0xff" "0xff" "0x03"
60 u16b max_num_temp = 255;
62 grid_template_type *templates;
63 C_MAKE(templates, max_num_temp, grid_template_type);
65 for (int y = 0; y < floor_ptr->height; y++) {
66 for (int x = 0; x < floor_ptr->width; x++) {
67 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
69 for (i = 0; i < num_temp; i++) {
70 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
71 && templates[i].special == g_ptr->special) {
72 templates[i].occurrence++;
80 if (num_temp >= max_num_temp) {
81 grid_template_type *old_template = templates;
82 C_MAKE(templates, max_num_temp + 255, grid_template_type);
83 (void)C_COPY(templates, old_template, max_num_temp, grid_template_type);
84 C_KILL(old_template, max_num_temp, grid_template_type);
88 templates[num_temp].info = g_ptr->info;
89 templates[num_temp].feat = g_ptr->feat;
90 templates[num_temp].mimic = g_ptr->mimic;
91 templates[num_temp].special = g_ptr->special;
92 templates[num_temp].occurrence = 1;
98 ang_sort(player_ptr, templates, &dummy_why, num_temp, ang_sort_comp_cave_temp, ang_sort_swap_cave_temp);
100 /*** Dump templates ***/
102 for (int i = 0; i < num_temp; i++) {
103 grid_template_type *ct_ptr = &templates[i];
104 wr_u16b((u16b)ct_ptr->info);
105 wr_s16b(ct_ptr->feat);
106 wr_s16b(ct_ptr->mimic);
107 wr_s16b(ct_ptr->special);
112 for (int y = 0; y < floor_ptr->height; y++) {
113 for (int x = 0; x < floor_ptr->width; x++) {
114 grid_type *g_ptr = &floor_ptr->grid_array[y][x];
116 for (i = 0; i < num_temp; i++) {
117 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic
118 && templates[i].special == g_ptr->special)
122 u16b tmp16u = (u16b)i;
123 if ((tmp16u == prev_u16b) && (count != MAX_UCHAR)) {
128 wr_byte((byte)count);
129 while (prev_u16b >= MAX_UCHAR) {
131 prev_u16b -= MAX_UCHAR;
134 wr_byte((byte)prev_u16b);
141 wr_byte((byte)count);
142 while (prev_u16b >= MAX_UCHAR) {
144 prev_u16b -= MAX_UCHAR;
147 wr_byte((byte)prev_u16b);
150 C_KILL(templates, max_num_temp, grid_template_type);
152 /*** Dump objects ***/
153 wr_u16b(floor_ptr->o_max);
154 for (int i = 1; i < floor_ptr->o_max; i++) {
155 object_type *o_ptr = &floor_ptr->o_list[i];
159 /*** Dump the monsters ***/
160 wr_u16b(floor_ptr->m_max);
161 for (int i = 1; i < floor_ptr->m_max; i++) {
162 monster_type *m_ptr = &floor_ptr->m_list[i];
168 * @brief 現在フロアの書き込み /
169 * Write the current dungeon (new method)
170 * @player_ptr プレーヤーへの参照ポインタ
171 * @return 保存に成功したらTRUE
173 bool wr_dungeon(player_type *player_ptr)
175 forget_lite(player_ptr->current_floor_ptr);
176 forget_view(player_ptr->current_floor_ptr);
177 clear_mon_lite(player_ptr->current_floor_ptr);
178 player_ptr->update |= PU_VIEW | PU_LITE | PU_MON_LITE;
179 player_ptr->update |= PU_MONSTERS | PU_DISTANCE | PU_FLOW;
180 wr_s16b(max_floor_id);
181 wr_byte((byte)player_ptr->dungeon_idx);
182 if (!player_ptr->floor_id) {
183 /* No array elements */
185 wr_saved_floor(player_ptr, NULL);
189 /*** In the dungeon ***/
190 wr_byte(MAX_SAVED_FLOORS);
191 for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
192 saved_floor_type *sf_ptr = &saved_floors[i];
193 wr_s16b(sf_ptr->floor_id);
194 wr_byte((byte)sf_ptr->savefile_id);
195 wr_s16b((s16b)sf_ptr->dun_level);
196 wr_s32b(sf_ptr->last_visit);
197 wr_u32b(sf_ptr->visit_mark);
198 wr_s16b(sf_ptr->upper_floor_id);
199 wr_s16b(sf_ptr->lower_floor_id);
202 saved_floor_type *cur_sf_ptr;
203 cur_sf_ptr = get_sf_ptr(player_ptr->floor_id);
204 if (!save_floor(player_ptr, cur_sf_ptr, SLF_SECOND))
207 for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
208 saved_floor_type *sf_ptr = &saved_floors[i];
209 if (!sf_ptr->floor_id)
211 if (!load_floor(player_ptr, sf_ptr, (SLF_SECOND | SLF_NO_KILL))) {
217 wr_saved_floor(player_ptr, sf_ptr);
220 return load_floor(player_ptr, cur_sf_ptr, (SLF_SECOND));
224 * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporary saved floor file
225 * @param player_ptr プレーヤーへの参照ポインタ
226 * @param sf_ptr 保存フロア参照ポインタ
228 static bool save_floor_aux(player_type *player_ptr, saved_floor_type *sf_ptr)
230 compact_objects(player_ptr, 0);
231 compact_monsters(player_ptr, 0);
233 byte tmp8u = (byte)randint0(256);
237 /* Reset the checksum */
240 wr_u32b(saved_floor_file_sign);
241 wr_saved_floor(player_ptr, sf_ptr);
245 return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
248 * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporarily saved-floor data
249 * @param player_ptr プレーヤーへの参照ポインタ
250 * @param sf_ptr 保存フロア参照ポインタ
251 * @param mode 保存オプション
253 bool save_floor(player_type *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode)
255 FILE *old_fff = NULL;
256 byte old_xor_byte = 0;
257 u32b old_v_stamp = 0;
258 u32b old_x_stamp = 0;
260 char floor_savefile[sizeof(savefile) + 32];
261 if ((mode & SLF_SECOND) != 0) {
262 old_fff = saving_savefile;
263 old_xor_byte = save_xor_byte;
264 old_v_stamp = v_stamp;
265 old_x_stamp = x_stamp;
268 sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
269 safe_setuid_grab(player_ptr);
270 fd_kill(floor_savefile);
272 saving_savefile = NULL;
273 safe_setuid_grab(player_ptr);
275 int fd = fd_make(floor_savefile, 0644);
277 bool is_save_successful = false;
280 safe_setuid_grab(player_ptr);
281 saving_savefile = angband_fopen(floor_savefile, "wb");
283 if (saving_savefile) {
284 if (save_floor_aux(player_ptr, sf_ptr))
285 is_save_successful = true;
287 if (angband_fclose(saving_savefile))
288 is_save_successful = false;
291 if (!is_save_successful) {
292 safe_setuid_grab(player_ptr);
293 (void)fd_kill(floor_savefile);
298 if ((mode & SLF_SECOND) != 0) {
299 saving_savefile = old_fff;
300 save_xor_byte = old_xor_byte;
301 v_stamp = old_v_stamp;
302 x_stamp = old_x_stamp;
305 return is_save_successful;