OSDN Git Service

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