OSDN Git Service

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