OSDN Git Service

[Refactor] ビット判定・操作式を ***_bits() にした
[hengbandforosx/hengbandosx.git] / src / floor / floor-save.cpp
1 /*!
2  * @brief 保存された階の管理 / management of the saved floor
3  * @date 2014/01/04
4  * @author
5  * Copyright (c) 2002  Mogami \n
6  * This software may be copied and distributed for educational, research, and \n
7  * not for profit purposes provided that this copyright and statement are \n
8  * included in all such copies. \n
9  * 2014 Deskull rearranged comment for Doxygen. \n
10  */
11
12 #include "floor/floor-save.h"
13 #include "core/asking-player.h"
14 #include "floor/floor-save-util.h"
15 #include "io/files-util.h"
16 #include "io/uid-checker.h"
17 #include "monster-race/monster-race.h"
18 #include "monster/monster-info.h"
19 #include "monster/monster-status.h"
20 #include "system/floor-type-definition.h"
21 #include "system/monster-race-definition.h"
22 #include "system/monster-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "util/angband-files.h"
25 #include "view/display-messages.h"
26
27 static void check_saved_tmp_files(const int fd, bool *force)
28 {
29     if (fd >= 0) {
30         (void)fd_close(fd);
31         return;
32     }
33
34     if (*force) {
35         return;
36     }
37
38     msg_print(_("エラー:古いテンポラリ・ファイルが残っています。", "Error: There are old temporary files."));
39     msg_print(_("変愚蛮怒を二重に起動していないか確認してください。", "Make sure you are not running two game processes simultaneously."));
40     msg_print(_("過去に変愚蛮怒がクラッシュした場合は一時ファイルを", "If the temporary files are garbage from an old crashed process, "));
41     msg_print(_("強制的に削除して実行を続けられます。", "you can delete them safely."));
42     if (!get_check(_("強制的に削除してもよろしいですか?", "Do you delete the old temporary files? "))) {
43         quit(_("実行中止", "Aborted."));
44     }
45
46     *force = true;
47 }
48
49 /*!
50  * @brief 保存フロア配列を初期化する / Initialize saved_floors array.
51  * @param player_ptr プレイヤーへの参照ポインタ
52  * @param force テンポラリファイルが残っていた場合も警告なしで強制的に削除するフラグ
53  * @details Make sure that old temporary files are not remaining as gurbages.
54  */
55 void init_saved_floors(PlayerType *player_ptr, bool force)
56 {
57     char floor_savefile[sizeof(savefile) + 32];
58     int fd = -1;
59     BIT_FLAGS mode = 0644;
60     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
61         saved_floor_type *sf_ptr = &saved_floors[i];
62         sprintf(floor_savefile, "%s.F%02d", savefile, i);
63         safe_setuid_grab(player_ptr);
64         fd = fd_make(floor_savefile, mode);
65         safe_setuid_drop();
66         check_saved_tmp_files(fd, &force);
67         safe_setuid_grab(player_ptr);
68         (void)fd_kill(floor_savefile);
69         safe_setuid_drop();
70         sf_ptr->floor_id = 0;
71     }
72
73     max_floor_id = 1;
74     latest_visit_mark = 1;
75     saved_floor_file_sign = (uint32_t)time(nullptr);
76     new_floor_id = 0;
77     player_ptr->change_floor_mode = 0;
78 }
79
80 /*!
81  * @brief 保存フロア用テンポラリファイルを削除する / Kill temporary files
82  * @details Should be called just before the game quit.
83  * @param player_ptr プレイヤーへの参照ポインタ
84  */
85 void clear_saved_floor_files(PlayerType *player_ptr)
86 {
87     char floor_savefile[sizeof(savefile) + 32];
88     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
89         saved_floor_type *sf_ptr = &saved_floors[i];
90         if ((sf_ptr->floor_id == 0) || (sf_ptr->floor_id == player_ptr->floor_id)) {
91             continue;
92         }
93
94         sprintf(floor_savefile, "%s.F%02d", savefile, i);
95         safe_setuid_grab(player_ptr);
96         (void)fd_kill(floor_savefile);
97         safe_setuid_drop();
98     }
99 }
100
101 /*!
102  * @brief 保存フロアIDから参照ポインタを得る / Get a pointer for an item of the saved_floors array.
103  * @param floor_id 保存フロアID
104  * @return IDに対応する保存フロアのポインタ、ない場合はnullptrを返す。
105  */
106 saved_floor_type *get_sf_ptr(FLOOR_IDX floor_id)
107 {
108     if (!floor_id) {
109         return nullptr;
110     }
111
112     for (int i = 0; i < MAX_SAVED_FLOORS; i++) {
113         saved_floor_type *sf_ptr = &saved_floors[i];
114         if (sf_ptr->floor_id == floor_id) {
115             return sf_ptr;
116         }
117     }
118
119     return nullptr;
120 }
121
122 /*!
123  * @brief 参照ポインタ先の保存フロアを抹消する / kill a saved floor and get an empty space
124  * @param player_ptr プレイヤーへの参照ポインタ
125  * @param sf_ptr 保存フロアの参照ポインタ
126  */
127 void kill_saved_floor(PlayerType *player_ptr, saved_floor_type *sf_ptr)
128 {
129     char floor_savefile[sizeof(savefile) + 32];
130     if (!sf_ptr || (sf_ptr->floor_id == 0)) {
131         return;
132     }
133
134     if (sf_ptr->floor_id == player_ptr->floor_id) {
135         player_ptr->floor_id = 0;
136         sf_ptr->floor_id = 0;
137         return;
138     }
139
140     sprintf(floor_savefile, "%s.F%02d", savefile, (int)sf_ptr->savefile_id);
141     safe_setuid_grab(player_ptr);
142     (void)fd_kill(floor_savefile);
143     safe_setuid_drop();
144     sf_ptr->floor_id = 0;
145 }
146
147 static FLOOR_IDX find_oldest_floor_idx(PlayerType *player_ptr)
148 {
149     FLOOR_IDX oldest_floor_idx = 0;
150     uint32_t oldest_visit = 0xffffffffL;
151
152     for (FLOOR_IDX fl_idx = 0; fl_idx < MAX_SAVED_FLOORS; fl_idx++) {
153         const saved_floor_type *sf_ptr = &saved_floors[fl_idx];
154         if ((sf_ptr->floor_id == player_ptr->floor_id) || (sf_ptr->visit_mark > oldest_visit)) {
155             continue;
156         }
157
158         oldest_floor_idx = fl_idx;
159         oldest_visit = sf_ptr->visit_mark;
160     }
161
162     return oldest_floor_idx;
163 }
164
165 /*!
166  * @brief 新規に利用可能な保存フロアを返す / Initialize new saved floor and get its floor id.
167  * @param player_ptr プレイヤーへの参照ポインタ
168  * @return 利用可能な保存フロアID
169  * @details
170  * If number of saved floors are already MAX_SAVED_FLOORS, kill the oldest one.
171  */
172 FLOOR_IDX get_new_floor_id(PlayerType *player_ptr)
173 {
174     saved_floor_type *sf_ptr = nullptr;
175     FLOOR_IDX fl_idx;
176     for (fl_idx = 0; fl_idx < MAX_SAVED_FLOORS; fl_idx++) {
177         sf_ptr = &saved_floors[fl_idx];
178         if (!sf_ptr->floor_id) {
179             break;
180         }
181     }
182
183     if (fl_idx == MAX_SAVED_FLOORS) {
184         fl_idx = find_oldest_floor_idx(player_ptr);
185         sf_ptr = &saved_floors[fl_idx];
186         kill_saved_floor(player_ptr, sf_ptr);
187     }
188
189     sf_ptr->savefile_id = fl_idx;
190     sf_ptr->floor_id = max_floor_id;
191     sf_ptr->last_visit = 0;
192     sf_ptr->upper_floor_id = 0;
193     sf_ptr->lower_floor_id = 0;
194     sf_ptr->visit_mark = latest_visit_mark++;
195     sf_ptr->dun_level = player_ptr->current_floor_ptr->dun_level;
196     if (max_floor_id < MAX_SHORT) {
197         max_floor_id++;
198     } else {
199         max_floor_id = 1;
200     } // 32767 floor_ids are all used up!  Re-use ancient IDs.
201
202     return sf_ptr->floor_id;
203 }
204
205 /*!
206  * @brief フロア移動時にペットを伴った場合の準備処理 / Pre-calculate the racial counters of preserved pets
207  * @param player_ptr プレイヤーへの参照ポインタ
208  * @details
209  * To prevent multiple generation of unique monster who is the minion of player
210  */
211 void precalc_cur_num_of_pet(PlayerType *player_ptr)
212 {
213     monster_type *m_ptr;
214     int max_num = player_ptr->wild_mode ? 1 : MAX_PARTY_MON;
215     for (int i = 0; i < max_num; i++) {
216         m_ptr = &party_mon[i];
217         if (!monster_is_valid(m_ptr)) {
218             continue;
219         }
220
221         real_r_ptr(m_ptr)->cur_num++;
222     }
223 }