1 #include "save/floor-writer.h"
2 #include "core/object-compressor.h"
3 #include "floor/floor-events.h"
4 #include "floor/floor-save-util.h"
5 #include "floor/floor-save.h"
7 #include "io/files-util.h"
8 #include "io/uid-checker.h"
9 #include "load/floor-loader.h"
10 #include "monster-floor/monster-lite.h"
11 #include "monster/monster-compaction.h"
12 #include "save/item-writer.h"
13 #include "save/monster-writer.h"
14 #include "save/save-util.h"
15 #include "system/floor-type-definition.h"
16 #include "system/grid-type-definition.h"
17 #include "system/item-entity.h"
18 #include "system/redrawing-flags-updater.h"
19 #include "term/z-form.h"
20 #include "util/angband-files.h"
21 #include "util/sort.h"
24 * @brief 保存フロアの書き込み / Actually write a saved floor data using effectively compressed format.
25 * @param sf_ptr 保存したいフロアの参照ポインタ
27 void wr_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
29 auto *floor_ptr = player_ptr->current_floor_ptr;
31 wr_s16b((int16_t)floor_ptr->dun_level);
33 wr_s16b(sf_ptr->floor_id);
34 wr_byte((byte)sf_ptr->savefile_id);
35 wr_s16b((int16_t)sf_ptr->dun_level);
36 wr_s32b(sf_ptr->last_visit);
37 wr_u32b(sf_ptr->visit_mark);
38 wr_s16b(sf_ptr->upper_floor_id);
39 wr_s16b(sf_ptr->lower_floor_id);
42 wr_u16b((uint16_t)floor_ptr->base_level);
43 wr_u16b((int16_t)player_ptr->current_floor_ptr->num_repro);
44 wr_u16b((uint16_t)player_ptr->y);
45 wr_u16b((uint16_t)player_ptr->x);
46 wr_u16b((uint16_t)floor_ptr->height);
47 wr_u16b((uint16_t)floor_ptr->width);
48 wr_byte(player_ptr->feeling);
51 * Usually number of templates are fewer than 255. Even if
52 * more than 254 are exist, the occurrence of each template
53 * with larger ID is very small when we sort templates by
54 * occurrence. So we will use two (or more) bytes for
55 * templete ID larger than 254.
57 * Ex: 256 will be "0xff" "0x01".
58 * 515 will be "0xff" "0xff" "0x03"
61 std::vector<grid_template_type> templates;
62 for (int y = 0; y < floor_ptr->height; y++) {
63 for (int x = 0; x < floor_ptr->width; x++) {
64 auto *g_ptr = &floor_ptr->grid_array[y][x];
66 for (i = 0; i < templates.size(); i++) {
67 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic && templates[i].special == g_ptr->special) {
68 templates[i].occurrence++;
73 if (i < templates.size()) {
77 templates.push_back({ g_ptr->info, g_ptr->feat, g_ptr->mimic, g_ptr->special, 1 });
82 ang_sort(player_ptr, templates.data(), &dummy_why, templates.size(), ang_sort_comp_cave_temp, ang_sort_swap_cave_temp);
84 /*** Dump templates ***/
85 wr_u16b(static_cast<uint16_t>(templates.size()));
86 for (const auto &ct_ref : templates) {
87 wr_u16b(static_cast<uint16_t>(ct_ref.info));
89 wr_s16b(ct_ref.mimic);
90 wr_s16b(ct_ref.special);
94 uint16_t prev_u16b = 0;
95 for (int y = 0; y < floor_ptr->height; y++) {
96 for (int x = 0; x < floor_ptr->width; x++) {
97 auto *g_ptr = &floor_ptr->grid_array[y][x];
99 for (i = 0; i < templates.size(); i++) {
100 if (templates[i].info == g_ptr->info && templates[i].feat == g_ptr->feat && templates[i].mimic == g_ptr->mimic && templates[i].special == g_ptr->special) {
105 uint16_t tmp16u = (uint16_t)i;
106 if ((tmp16u == prev_u16b) && (count != MAX_UCHAR)) {
111 wr_byte((byte)count);
112 while (prev_u16b >= MAX_UCHAR) {
114 prev_u16b -= MAX_UCHAR;
117 wr_byte((byte)prev_u16b);
124 wr_byte((byte)count);
125 while (prev_u16b >= MAX_UCHAR) {
127 prev_u16b -= MAX_UCHAR;
130 wr_byte((byte)prev_u16b);
133 /*** Dump objects ***/
134 wr_u16b(floor_ptr->o_max);
135 for (int i = 1; i < floor_ptr->o_max; i++) {
136 auto *o_ptr = &floor_ptr->o_list[i];
140 /*** Dump the monsters ***/
141 wr_u16b(floor_ptr->m_max);
142 for (int i = 1; i < floor_ptr->m_max; i++) {
143 auto *m_ptr = &floor_ptr->m_list[i];
149 * @brief 現在フロアの書き込み /
150 * Write the current dungeon (new method)
151 * @player_ptr プレイヤーへの参照ポインタ
152 * @return 保存に成功したらTRUE
154 bool wr_dungeon(PlayerType *player_ptr)
156 forget_lite(player_ptr->current_floor_ptr);
157 forget_view(player_ptr->current_floor_ptr);
158 clear_mon_lite(player_ptr->current_floor_ptr);
159 static constexpr auto flags = {
160 StatusRecalculatingFlag::VIEW,
161 StatusRecalculatingFlag::LITE,
162 StatusRecalculatingFlag::MONSTER_LITE,
163 StatusRecalculatingFlag::MONSTER_STATUSES,
164 StatusRecalculatingFlag::DISTANCE,
165 StatusRecalculatingFlag::FLOW,
167 RedrawingFlagsUpdater::get_instance().set_flags(flags);
168 wr_s16b(max_floor_id);
169 wr_byte((byte)player_ptr->current_floor_ptr->dungeon_idx);
170 if (!player_ptr->floor_id) {
171 /* No array elements */
173 wr_saved_floor(player_ptr, nullptr);
177 /*** In the dungeon ***/
178 wr_byte(MAX_SAVED_FLOORS);
179 for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
180 saved_floor_type *sf_ptr = &saved_floors[i];
181 wr_s16b(sf_ptr->floor_id);
182 wr_byte((byte)sf_ptr->savefile_id);
183 wr_s16b((int16_t)sf_ptr->dun_level);
184 wr_s32b(sf_ptr->last_visit);
185 wr_u32b(sf_ptr->visit_mark);
186 wr_s16b(sf_ptr->upper_floor_id);
187 wr_s16b(sf_ptr->lower_floor_id);
190 saved_floor_type *cur_sf_ptr;
191 cur_sf_ptr = get_sf_ptr(player_ptr->floor_id);
192 if (!save_floor(player_ptr, cur_sf_ptr, SLF_SECOND)) {
196 for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
197 saved_floor_type *sf_ptr = &saved_floors[i];
198 if (!sf_ptr->floor_id) {
201 if (!load_floor(player_ptr, sf_ptr, (SLF_SECOND | SLF_NO_KILL))) {
207 wr_saved_floor(player_ptr, sf_ptr);
210 return load_floor(player_ptr, cur_sf_ptr, (SLF_SECOND));
214 * @brief ゲームプレイ中のフロア一時保存出力処理サブルーチン / Actually write a temporary saved floor file
215 * @param player_ptr プレイヤーへの参照ポインタ
216 * @param sf_ptr 保存フロア参照ポインタ
218 static bool save_floor_aux(PlayerType *player_ptr, saved_floor_type *sf_ptr)
220 compact_objects(player_ptr, 0);
221 compact_monsters(player_ptr, 0);
223 byte tmp8u = (byte)randint0(256);
227 /* Reset the checksum */
230 wr_u32b(saved_floor_file_sign);
231 wr_saved_floor(player_ptr, sf_ptr);
235 return !ferror(saving_savefile) && (fflush(saving_savefile) != EOF);
238 * @brief ゲームプレイ中のフロア一時保存出力処理メインルーチン / Attempt to save the temporarily saved-floor data
239 * @param player_ptr プレイヤーへの参照ポインタ
240 * @param sf_ptr 保存フロア参照ポインタ
241 * @param mode 保存オプション
243 bool save_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr, BIT_FLAGS mode)
245 FILE *old_fff = nullptr;
246 byte old_xor_byte = 0;
247 uint32_t old_v_stamp = 0;
248 uint32_t old_x_stamp = 0;
250 if ((mode & SLF_SECOND) != 0) {
251 old_fff = saving_savefile;
252 old_xor_byte = save_xor_byte;
253 old_v_stamp = v_stamp;
254 old_x_stamp = x_stamp;
257 auto floor_savefile = savefile.string();
259 strnfmt(ext, sizeof(ext), ".F%02d", (int)sf_ptr->savefile_id);
260 floor_savefile.append(ext);
262 fd_kill(floor_savefile);
264 saving_savefile = nullptr;
267 auto fd = fd_make(floor_savefile);
269 bool is_save_successful = false;
273 saving_savefile = angband_fopen(floor_savefile, FileOpenMode::WRITE, true);
275 if (saving_savefile) {
276 if (save_floor_aux(player_ptr, sf_ptr)) {
277 is_save_successful = true;
280 if (angband_fclose(saving_savefile)) {
281 is_save_successful = false;
285 if (!is_save_successful) {
287 (void)fd_kill(floor_savefile);
292 if ((mode & SLF_SECOND) != 0) {
293 saving_savefile = old_fff;
294 save_xor_byte = old_xor_byte;
295 v_stamp = old_v_stamp;
296 x_stamp = old_x_stamp;
299 return is_save_successful;