OSDN Git Service

Merge remote-tracking branch 'remotes/hengband-osx/For2.2.2-Refactoring-English-New...
[hengband/hengband.git] / src / floor / floor-leaver.c
1 #include "floor/floor-leaver.h"
2 #include "cmd-building/cmd-building.h"
3 #include "dungeon/dungeon.h"
4 #include "dungeon/quest.h"
5 #include "floor/cave.h"
6 #include "floor/floor-events.h"
7 #include "floor/floor-mode-changer.h"
8 #include "floor/floor-save-util.h"
9 #include "floor/floor-save.h"
10 #include "floor/floor.h"
11 #include "game-option/birth-options.h"
12 #include "game-option/play-record-options.h"
13 #include "grid/feature.h"
14 #include "inventory/inventory-slot-types.h"
15 #include "io/write-diary.h"
16 #include "mind/mind-mirror-master.h"
17 #include "mind/mind-ninja.h"
18 #include "monster-floor/monster-lite.h"
19 #include "monster-floor/monster-remover.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-flags1.h"
22 #include "monster-race/race-flags7.h"
23 #include "monster/monster-describer.h"
24 #include "monster/monster-description-types.h"
25 #include "monster/monster-info.h"
26 #include "monster/monster-status.h"
27 #include "object-hook/hook-checker.h"
28 #include "object-hook/hook-enchant.h"
29 #include "pet/pet-util.h"
30 #include "player/special-defense-types.h"
31 #include "save/floor-writer.h"
32 #include "system/artifact-type-definition.h"
33 #include "system/floor-type-definition.h"
34 #include "system/monster-type-definition.h"
35 #include "util/bit-flags-calculator.h"
36 #include "view/display-messages.h"
37 #include "world/world.h"
38
39 static void check_riding_preservation(player_type *master_ptr)
40 {
41     if (!master_ptr->riding)
42         return;
43
44     monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[master_ptr->riding];
45     if (m_ptr->parent_m_idx) {
46         master_ptr->riding = 0;
47         master_ptr->pet_extra_flags &= ~(PF_TWO_HANDS);
48         master_ptr->riding_ryoute = master_ptr->old_riding_ryoute = FALSE;
49     } else {
50         (void)COPY(&party_mon[0], m_ptr, monster_type);
51         delete_monster_idx(master_ptr, master_ptr->riding);
52     }
53 }
54
55 static bool check_pet_preservation_conditions(player_type *master_ptr, monster_type *m_ptr)
56 {
57     if (reinit_wilderness)
58         return FALSE;
59
60     POSITION dis = distance(master_ptr->y, master_ptr->x, m_ptr->fy, m_ptr->fx);
61     if (monster_confused_remaining(m_ptr) || monster_stunned_remaining(m_ptr) || monster_csleep_remaining(m_ptr) || (m_ptr->parent_m_idx != 0))
62         return TRUE;
63
64     if (m_ptr->nickname
65         && ((player_has_los_bold(master_ptr, m_ptr->fy, m_ptr->fx) && projectable(master_ptr, master_ptr->y, master_ptr->x, m_ptr->fy, m_ptr->fx))
66             || (los(master_ptr, m_ptr->fy, m_ptr->fx, master_ptr->y, master_ptr->x)
67                 && projectable(master_ptr, m_ptr->fy, m_ptr->fx, master_ptr->y, master_ptr->x)))) {
68         if (dis > 3)
69             return TRUE;
70     } else if (dis > 1)
71         return TRUE;
72
73     return FALSE;
74 }
75
76 static void sweep_preserving_pet(player_type *master_ptr)
77 {
78     if (master_ptr->wild_mode || master_ptr->current_floor_ptr->inside_arena || master_ptr->phase_out)
79         return;
80
81     for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1, party_monster_num = 1; (i >= 1) && (party_monster_num < MAX_PARTY_MON); i--) {
82         monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
83         if (!monster_is_valid(m_ptr) || !is_pet(m_ptr) || (i == master_ptr->riding) || check_pet_preservation_conditions(master_ptr, m_ptr))
84             continue;
85
86         (void)COPY(&party_mon[party_monster_num], &master_ptr->current_floor_ptr->m_list[i], monster_type);
87         party_monster_num++;
88         delete_monster_idx(master_ptr, i);
89     }
90 }
91
92 static void record_pet_diary(player_type *master_ptr)
93 {
94     if (!record_named_pet)
95         return;
96
97     for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1; i >= 1; i--) {
98         monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
99         GAME_TEXT m_name[MAX_NLEN];
100         if (!monster_is_valid(m_ptr) || !is_pet(m_ptr) || !m_ptr->nickname || (master_ptr->riding == i))
101             continue;
102
103         monster_desc(master_ptr, m_name, m_ptr, MD_ASSUME_VISIBLE | MD_INDEF_VISIBLE);
104         exe_write_diary(master_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_MOVED, m_name);
105     }
106 }
107
108 /*!
109  * @brief フロア移動時のペット保存処理 / Preserve_pets
110  * @param master_ptr プレーヤーへの参照ポインタ
111  * @return なし
112  */
113 static void preserve_pet(player_type *master_ptr)
114 {
115     for (MONSTER_IDX party_monster_num = 0; party_monster_num < MAX_PARTY_MON; party_monster_num++)
116         party_mon[party_monster_num].r_idx = 0;
117
118     check_riding_preservation(master_ptr);
119     sweep_preserving_pet(master_ptr);
120     record_pet_diary(master_ptr);
121     for (MONSTER_IDX i = master_ptr->current_floor_ptr->m_max - 1; i >= 1; i--) {
122         monster_type *m_ptr = &master_ptr->current_floor_ptr->m_list[i];
123         if ((m_ptr->parent_m_idx == 0) || (master_ptr->current_floor_ptr->m_list[m_ptr->parent_m_idx].r_idx != 0))
124             continue;
125
126         if (is_seen(master_ptr, m_ptr)) {
127             GAME_TEXT m_name[MAX_NLEN];
128             monster_desc(master_ptr, m_name, m_ptr, 0);
129             msg_format(_("%sは消え去った!", "%^s disappears!"), m_name);
130         }
131
132         delete_monster_idx(master_ptr, i);
133     }
134 }
135
136 /*!
137  * @brief 新フロアに移動元フロアに繋がる階段を配置する / Virtually teleport onto the stairs that is connecting between two floors.
138  * @param sf_ptr 移動元の保存フロア構造体参照ポインタ
139  * @return なし
140  */
141 static void locate_connected_stairs(player_type *creature_ptr, floor_type *floor_ptr, saved_floor_type *sf_ptr, BIT_FLAGS floor_mode)
142 {
143     POSITION sx = 0;
144     POSITION sy = 0;
145     POSITION x_table[20];
146     POSITION y_table[20];
147     int num = 0;
148     for (POSITION y = 0; y < floor_ptr->height; y++) {
149         for (POSITION x = 0; x < floor_ptr->width; x++) {
150             grid_type *g_ptr = &floor_ptr->grid_array[y][x];
151             feature_type *f_ptr = &f_info[g_ptr->feat];
152             bool ok = FALSE;
153             if (floor_mode & CFM_UP) {
154                 if (have_flag(f_ptr->flags, FF_LESS) && have_flag(f_ptr->flags, FF_STAIRS) && !have_flag(f_ptr->flags, FF_SPECIAL)) {
155                     ok = TRUE;
156                     if (g_ptr->special && g_ptr->special == sf_ptr->upper_floor_id) {
157                         sx = x;
158                         sy = y;
159                     }
160                 }
161             } else if (floor_mode & CFM_DOWN) {
162                 if (have_flag(f_ptr->flags, FF_MORE) && have_flag(f_ptr->flags, FF_STAIRS) && !have_flag(f_ptr->flags, FF_SPECIAL)) {
163                     ok = TRUE;
164                     if (g_ptr->special && g_ptr->special == sf_ptr->lower_floor_id) {
165                         sx = x;
166                         sy = y;
167                     }
168                 }
169             } else {
170                 if (have_flag(f_ptr->flags, FF_BLDG)) {
171                     ok = TRUE;
172                 }
173             }
174
175             if (ok && (num < 20)) {
176                 x_table[num] = x;
177                 y_table[num] = y;
178                 num++;
179             }
180         }
181     }
182
183     if (sx) {
184         creature_ptr->y = sy;
185         creature_ptr->x = sx;
186         return;
187     }
188
189     if (num == 0) {
190         prepare_change_floor_mode(creature_ptr, CFM_RAND_PLACE | CFM_NO_RETURN);
191         if (!feat_uses_special(floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].feat))
192             floor_ptr->grid_array[creature_ptr->y][creature_ptr->x].special = 0;
193
194         return;
195     }
196
197     int i = randint0(num);
198     creature_ptr->y = y_table[i];
199     creature_ptr->x = x_table[i];
200 }
201
202 /*!
203  * @brief フロア移動時、プレイヤーの移動先モンスターが既にいた場合ランダムな近隣に移動させる / When a monster is at a place where player will return,
204  * @return なし
205  */
206 static void get_out_monster(player_type *protected_ptr)
207 {
208     int tries = 0;
209     POSITION dis = 1;
210     POSITION oy = protected_ptr->y;
211     POSITION ox = protected_ptr->x;
212     floor_type *floor_ptr = protected_ptr->current_floor_ptr;
213     MONSTER_IDX m_idx = floor_ptr->grid_array[oy][ox].m_idx;
214     if (m_idx == 0)
215         return;
216
217     while (TRUE) {
218         monster_type *m_ptr;
219         POSITION ny = rand_spread(oy, dis);
220         POSITION nx = rand_spread(ox, dis);
221         tries++;
222         if (tries > 10000)
223             return;
224
225         if (tries > 20 * dis * dis)
226             dis++;
227
228         if (!in_bounds(floor_ptr, ny, nx) || !is_cave_empty_bold(protected_ptr, ny, nx) || is_glyph_grid(&floor_ptr->grid_array[ny][nx])
229             || is_explosive_rune_grid(&floor_ptr->grid_array[ny][nx]) || pattern_tile(floor_ptr, ny, nx))
230             continue;
231
232         m_ptr = &floor_ptr->m_list[m_idx];
233         floor_ptr->grid_array[oy][ox].m_idx = 0;
234         floor_ptr->grid_array[ny][nx].m_idx = m_idx;
235         m_ptr->fy = ny;
236         m_ptr->fx = nx;
237         return;
238     }
239 }
240
241 /*!
242  * @brief クエスト・フロア内のモンスター・インベントリ情報を保存する
243  * @param creature_ptr プレーヤーへの参照ポインタ
244  * @return なし
245  */
246 static void preserve_info(player_type *creature_ptr)
247 {
248     MONRACE_IDX quest_r_idx = 0;
249     for (DUNGEON_IDX i = 0; i < max_q_idx; i++) {
250         if ((quest[i].status == QUEST_STATUS_TAKEN) && ((quest[i].type == QUEST_TYPE_KILL_LEVEL) || (quest[i].type == QUEST_TYPE_RANDOM))
251             && (quest[i].level == creature_ptr->current_floor_ptr->dun_level) && (creature_ptr->dungeon_idx == quest[i].dungeon)
252             && !(quest[i].flags & QUEST_FLAG_PRESET)) {
253             quest_r_idx = quest[i].r_idx;
254         }
255     }
256
257     for (DUNGEON_IDX i = 1; i < creature_ptr->current_floor_ptr->m_max; i++) {
258         monster_race *r_ptr;
259         monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[i];
260         if (!monster_is_valid(m_ptr) || (quest_r_idx != m_ptr->r_idx))
261             continue;
262
263         r_ptr = real_r_ptr(m_ptr);
264         if ((r_ptr->flags1 & RF1_UNIQUE) || (r_ptr->flags7 & RF7_NAZGUL))
265             continue;
266
267         delete_monster_idx(creature_ptr, i);
268     }
269
270     for (DUNGEON_IDX i = 0; i < INVEN_PACK; i++) {
271         object_type *o_ptr = &creature_ptr->inventory_list[i];
272         if (!object_is_valid(o_ptr))
273             continue;
274
275         if (object_is_fixed_artifact(o_ptr))
276             a_info[o_ptr->name1].floor_id = 0;
277     }
278 }
279
280 static void set_grid_by_leaving_floor(player_type *creature_ptr, grid_type **g_ptr)
281 {
282     if ((creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) == 0)
283         return;
284
285     *g_ptr = &creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x];
286     feature_type *f_ptr =  &f_info[(*g_ptr)->feat];
287     if ((*g_ptr)->special && !have_flag(f_ptr->flags, FF_SPECIAL) && get_sf_ptr((*g_ptr)->special))
288         new_floor_id = (*g_ptr)->special;
289
290     if (have_flag(f_ptr->flags, FF_STAIRS) && have_flag(f_ptr->flags, FF_SHAFT))
291         prepare_change_floor_mode(creature_ptr, CFM_SHAFT);
292 }
293
294 static void jump_floors(player_type *creature_ptr)
295 {
296     if ((creature_ptr->change_floor_mode & (CFM_DOWN | CFM_UP)) == 0)
297         return;
298
299     int move_num = 0;
300     if (creature_ptr->change_floor_mode & CFM_DOWN)
301         move_num = 1;
302     else if (creature_ptr->change_floor_mode & CFM_UP)
303         move_num = -1;
304
305     if (creature_ptr->change_floor_mode & CFM_SHAFT)
306         move_num += SGN(move_num);
307
308     if (creature_ptr->change_floor_mode & CFM_DOWN) {
309         if (!creature_ptr->current_floor_ptr->dun_level)
310             move_num = d_info[creature_ptr->dungeon_idx].mindepth;
311     } else if (creature_ptr->change_floor_mode & CFM_UP) {
312         if (creature_ptr->current_floor_ptr->dun_level + move_num < d_info[creature_ptr->dungeon_idx].mindepth)
313             move_num = -creature_ptr->current_floor_ptr->dun_level;
314     }
315
316     creature_ptr->current_floor_ptr->dun_level += move_num;
317 }
318
319 static void exit_to_wilderness(player_type *creature_ptr)
320 {
321     if ((creature_ptr->current_floor_ptr->dun_level != 0) || (creature_ptr->dungeon_idx == 0))
322         return;
323
324     creature_ptr->leaving_dungeon = TRUE;
325     if (!vanilla_town && !lite_town) {
326         creature_ptr->wilderness_y = d_info[creature_ptr->dungeon_idx].dy;
327         creature_ptr->wilderness_x = d_info[creature_ptr->dungeon_idx].dx;
328     }
329
330     creature_ptr->recall_dungeon = creature_ptr->dungeon_idx;
331     creature_ptr->dungeon_idx = 0;
332     creature_ptr->change_floor_mode &= ~CFM_SAVE_FLOORS; // TODO
333 }
334
335 static void kill_saved_floors(player_type *creature_ptr, saved_floor_type *sf_ptr)
336 {
337     if (!(creature_ptr->change_floor_mode & CFM_SAVE_FLOORS)) {
338         for (DUNGEON_IDX i = 0; i < MAX_SAVED_FLOORS; i++)
339             kill_saved_floor(creature_ptr, &saved_floors[i]);
340
341         latest_visit_mark = 1;
342         return;
343     }
344     
345     if (creature_ptr->change_floor_mode & CFM_NO_RETURN)
346         kill_saved_floor(creature_ptr, sf_ptr);
347 }
348
349 static void refresh_new_floor_id(player_type *creature_ptr, grid_type *g_ptr)
350 {
351     if (new_floor_id != 0)
352         return;
353
354     new_floor_id = get_new_floor_id(creature_ptr);
355     if ((g_ptr != NULL) && !feat_uses_special(g_ptr->feat))
356         g_ptr->special = new_floor_id;
357 }
358
359 static void update_upper_lower_or_floor_id(player_type *creature_ptr, saved_floor_type *sf_ptr)
360 {
361     if ((creature_ptr->change_floor_mode & CFM_RAND_CONNECT) == 0)
362         return;
363
364     if (creature_ptr->change_floor_mode & CFM_UP)
365         sf_ptr->upper_floor_id = new_floor_id;
366     else if (creature_ptr->change_floor_mode & CFM_DOWN)
367         sf_ptr->lower_floor_id = new_floor_id;
368 }
369
370 static void exe_leave_floor(player_type *creature_ptr, saved_floor_type *sf_ptr)
371 {
372     grid_type *g_ptr = NULL;
373     set_grid_by_leaving_floor(creature_ptr, &g_ptr);
374     jump_floors(creature_ptr);
375     exit_to_wilderness(creature_ptr);
376     kill_saved_floors(creature_ptr, sf_ptr);
377     if (creature_ptr->floor_id == 0)
378         return;
379
380     refresh_new_floor_id(creature_ptr, g_ptr);
381     update_upper_lower_or_floor_id(creature_ptr, sf_ptr);
382     if (((creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) == 0) || ((creature_ptr->change_floor_mode & CFM_NO_RETURN) != 0))
383         return;
384
385     get_out_monster(creature_ptr);
386     sf_ptr->last_visit = current_world_ptr->game_turn;
387     forget_lite(creature_ptr->current_floor_ptr);
388     forget_view(creature_ptr->current_floor_ptr);
389     clear_mon_lite(creature_ptr->current_floor_ptr);
390     if (save_floor(creature_ptr, sf_ptr, 0))
391         return;
392
393     prepare_change_floor_mode(creature_ptr, CFM_NO_RETURN);
394     kill_saved_floor(creature_ptr, get_sf_ptr(creature_ptr->floor_id));
395 }
396
397 /*!
398  * @brief 現在のフロアを離れるに伴って行なわれる保存処理
399  * / Maintain quest monsters, mark next floor_id at stairs, save current floor, and prepare to enter next floor.
400  * @param creature_ptr プレーヤーへの参照ポインタ
401  * @return なし
402  */
403 void leave_floor(player_type *creature_ptr)
404 {
405     preserve_pet(creature_ptr);
406     remove_all_mirrors(creature_ptr, FALSE);
407     if (creature_ptr->special_defense & NINJA_S_STEALTH)
408         set_superstealth(creature_ptr, FALSE);
409
410     new_floor_id = 0;
411     FLOOR_IDX tmp_floor_idx = 0;
412     if (!creature_ptr->floor_id && (creature_ptr->change_floor_mode & CFM_SAVE_FLOORS) && !(creature_ptr->change_floor_mode & CFM_NO_RETURN))
413         tmp_floor_idx = get_new_floor_id(creature_ptr);
414
415     preserve_info(creature_ptr);
416     saved_floor_type *sf_ptr = get_sf_ptr(creature_ptr->floor_id);
417     if ((creature_ptr->change_floor_mode & CFM_RAND_CONNECT) && tmp_floor_idx)
418         locate_connected_stairs(creature_ptr, creature_ptr->current_floor_ptr, sf_ptr, creature_ptr->change_floor_mode);
419
420     exe_leave_floor(creature_ptr, sf_ptr);
421 }