OSDN Git Service

[Refactor] #40414 Moved concrete spell kinds file (spell-*.c/h) from spell/ to spell...
[hengband/hengband.git] / src / spell-kind / spells-teleport.c
1 /*!
2  * todo 少し長いかも
3  * @brief テレポート魔法全般
4  * @date 2020/06/04
5  * @author Hourier
6  */
7
8 #include "spell-kind/spells-teleport.h"
9 #include "cmd-io/cmd-save.h"
10 #include "dungeon/dungeon.h"
11 #include "dungeon/quest.h"
12 #include "effect/effect-characteristics.h"
13 #include "io/targeting.h"
14 #include "io/write-diary.h"
15 #include "main/sound-definitions-table.h"
16 #include "monster/creature.h"
17 #include "monster/monster-status.h"
18 #include "object-enchant/artifact.h"
19 #include "object/object-hook.h"
20 #include "player/avatar.h"
21 #include "player/player-move.h"
22 #include "spell-kind/spells-launcher.h"
23 #include "spell/spells-type.h"
24 #include "world/world.h"
25
26 /*!
27  * @brief モンスターとの位置交換処理 / Switch position with a monster.
28  * @param caster_ptr プレーヤーへの参照ポインタ
29  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
30  * @return 作用が実際にあった場合TRUEを返す
31  */
32 bool teleport_swap(player_type *caster_ptr, DIRECTION dir)
33 {
34     POSITION tx, ty;
35     if ((dir == 5) && target_okay(caster_ptr)) {
36         tx = target_col;
37         ty = target_row;
38     } else {
39         tx = caster_ptr->x + ddx[dir];
40         ty = caster_ptr->y + ddy[dir];
41     }
42
43     if (caster_ptr->anti_tele) {
44         msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
45         return FALSE;
46     }
47
48     grid_type *g_ptr;
49     g_ptr = &caster_ptr->current_floor_ptr->grid_array[ty][tx];
50     if (!g_ptr->m_idx || (g_ptr->m_idx == caster_ptr->riding)) {
51         msg_print(_("それとは場所を交換できません。", "You can't trade places with that!"));
52         return FALSE;
53     }
54
55     if ((g_ptr->info & CAVE_ICKY) || (distance(ty, tx, caster_ptr->y, caster_ptr->x) > caster_ptr->lev * 3 / 2 + 10)) {
56         msg_print(_("失敗した。", "Failed to swap."));
57         return FALSE;
58     }
59
60     monster_type *m_ptr;
61     monster_race *r_ptr;
62     m_ptr = &caster_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
63     r_ptr = &r_info[m_ptr->r_idx];
64
65     (void)set_monster_csleep(caster_ptr, g_ptr->m_idx, 0);
66
67     if (r_ptr->flagsr & RFR_RES_TELE) {
68         msg_print(_("テレポートを邪魔された!", "Your teleportation is blocked!"));
69         if (is_original_ap_and_seen(caster_ptr, m_ptr))
70             r_ptr->r_flagsr |= RFR_RES_TELE;
71         return FALSE;
72     }
73
74     sound(SOUND_TELEPORT);
75     (void)move_player_effect(caster_ptr, ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
76     return TRUE;
77 }
78
79 /*!
80  * @brief モンスター用テレポート処理
81  * @param caster_ptr プレーヤーへの参照ポインタ
82  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
83  * @param distance 移動距離
84  * @return 作用が実際にあった場合TRUEを返す
85  */
86 bool teleport_monster(player_type *caster_ptr, DIRECTION dir, int distance)
87 {
88     BIT_FLAGS flg = PROJECT_BEAM | PROJECT_KILL;
89     return (project_hook(caster_ptr, GF_AWAY_ALL, dir, distance, flg));
90 }
91
92 /*!
93  * @brief モンスターのテレポートアウェイ処理 /
94  * Teleport a monster, normally up to "dis" grids away.
95  * @param caster_ptr プレーヤーへの参照ポインタ
96  * @param m_idx モンスターID
97  * @param dis テレポート距離
98  * @param mode オプション
99  * @return テレポートが実際に行われたらtrue
100  * @details
101  * Attempt to move the monster at least "dis/2" grids away.
102  * But allow variation to prevent infinite loops.
103  */
104 bool teleport_away(player_type *caster_ptr, MONSTER_IDX m_idx, POSITION dis, teleport_flags mode)
105 {
106     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
107     if (!monster_is_valid(m_ptr))
108         return FALSE;
109
110     if ((mode & TELEPORT_DEC_VALOUR) && (((caster_ptr->chp * 10) / caster_ptr->mhp) > 5) && (4 + randint1(5) < ((caster_ptr->chp * 10) / caster_ptr->mhp))) {
111         chg_virtue(caster_ptr, V_VALOUR, -1);
112     }
113
114     POSITION oy = m_ptr->fy;
115     POSITION ox = m_ptr->fx;
116     POSITION min = dis / 2;
117     int tries = 0;
118     POSITION ny = 0, nx = 0;
119     bool look = TRUE;
120     while (look) {
121         tries++;
122         if (dis > 200)
123             dis = 200;
124
125         for (int i = 0; i < 500; i++) {
126             while (TRUE) {
127                 ny = rand_spread(oy, dis);
128                 nx = rand_spread(ox, dis);
129                 POSITION d = distance(oy, ox, ny, nx);
130                 if ((d >= min) && (d <= dis))
131                     break;
132             }
133
134             if (!in_bounds(caster_ptr->current_floor_ptr, ny, nx))
135                 continue;
136             if (!cave_monster_teleportable_bold(caster_ptr, m_idx, ny, nx, mode))
137                 continue;
138             if (!(caster_ptr->current_floor_ptr->inside_quest || caster_ptr->current_floor_ptr->inside_arena))
139                 if (caster_ptr->current_floor_ptr->grid_array[ny][nx].info & CAVE_ICKY)
140                     continue;
141
142             look = FALSE;
143             break;
144         }
145
146         dis = dis * 2;
147         min = min / 2;
148         const int MAX_TELEPORT_TRIES = 100;
149         if (tries > MAX_TELEPORT_TRIES)
150             return FALSE;
151     }
152
153     sound(SOUND_TPOTHER);
154     caster_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = 0;
155     caster_ptr->current_floor_ptr->grid_array[ny][nx].m_idx = m_idx;
156
157     m_ptr->fy = ny;
158     m_ptr->fx = nx;
159
160     reset_target(m_ptr);
161     update_monster(caster_ptr, m_idx, TRUE);
162     lite_spot(caster_ptr, oy, ox);
163     lite_spot(caster_ptr, ny, nx);
164
165     if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
166         caster_ptr->update |= (PU_MON_LITE);
167
168     return TRUE;
169 }
170
171 /*!
172  * @brief モンスターを指定された座標付近にテレポートする /
173  * Teleport monster next to a grid near the given location
174  * @param caster_ptr プレーヤーへの参照ポインタ
175  * @param m_idx モンスターID
176  * @param ty 目安Y座標
177  * @param tx 目安X座標
178  * @param power テレポート成功確率
179  * @param mode オプション
180  * @return なし
181  */
182 void teleport_monster_to(player_type *caster_ptr, MONSTER_IDX m_idx, POSITION ty, POSITION tx, int power, teleport_flags mode)
183 {
184     monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
185     if (!m_ptr->r_idx)
186         return;
187     if (randint1(100) > power)
188         return;
189
190     POSITION ny = m_ptr->fy;
191     POSITION nx = m_ptr->fx;
192     POSITION oy = m_ptr->fy;
193     POSITION ox = m_ptr->fx;
194
195     POSITION dis = 2;
196     int min = dis / 2;
197     int attempts = 500;
198     bool look = TRUE;
199     while (look && --attempts) {
200         if (dis > 200)
201             dis = 200;
202
203         for (int i = 0; i < 500; i++) {
204             while (TRUE) {
205                 ny = rand_spread(ty, dis);
206                 nx = rand_spread(tx, dis);
207                 int d = distance(ty, tx, ny, nx);
208                 if ((d >= min) && (d <= dis))
209                     break;
210             }
211
212             if (!in_bounds(caster_ptr->current_floor_ptr, ny, nx))
213                 continue;
214             if (!cave_monster_teleportable_bold(caster_ptr, m_idx, ny, nx, mode))
215                 continue;
216
217             look = FALSE;
218             break;
219         }
220
221         dis = dis * 2;
222         min = min / 2;
223     }
224
225     if (attempts < 1)
226         return;
227
228     sound(SOUND_TPOTHER);
229     caster_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = 0;
230     caster_ptr->current_floor_ptr->grid_array[ny][nx].m_idx = m_idx;
231
232     m_ptr->fy = ny;
233     m_ptr->fx = nx;
234
235     update_monster(caster_ptr, m_idx, TRUE);
236     lite_spot(caster_ptr, oy, ox);
237     lite_spot(caster_ptr, ny, nx);
238
239     if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
240         caster_ptr->update |= (PU_MON_LITE);
241 }
242
243 /*!
244  * @brief プレイヤーのテレポート先選定と移動処理 /
245  * Teleport the player to a location up to "dis" grids away.
246  * @param creature_ptr プレーヤーへの参照ポインタ
247  * @param dis 基本移動距離
248  * @param is_quantum_effect 量子的効果 (反テレポ無効)によるテレポートアウェイならばTRUE
249  * @param mode オプション
250  * @return 実際にテレポート処理が行われたらtrue
251  * @details
252  * <pre>
253  * If no such spaces are readily available, the distance may increase.
254  * Try very hard to move the player at least a quarter that distance.
255  *
256  * There was a nasty tendency for a long time; which was causing the
257  * player to "bounce" between two or three different spots because
258  * these are the only spots that are "far enough" way to satisfy the
259  * algorithm.
260  *
261  * But this tendency is now removed; in the new algorithm, a list of
262  * candidates is selected first, which includes at least 50% of all
263  * floor grids within the distance, and any single grid in this list
264  * of candidates has equal possibility to be choosen as a destination.
265  * </pre>
266  */
267 bool teleport_player_aux(player_type *creature_ptr, POSITION dis, bool is_quantum_effect, teleport_flags mode)
268 {
269     if (creature_ptr->wild_mode)
270         return FALSE;
271     if (!is_quantum_effect && creature_ptr->anti_tele && !(mode & TELEPORT_NONMAGICAL)) {
272         msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
273         return FALSE;
274     }
275
276     int candidates_at[MAX_TELEPORT_DISTANCE + 1];
277     for (int i = 0; i <= MAX_TELEPORT_DISTANCE; i++)
278         candidates_at[i] = 0;
279
280     if (dis > MAX_TELEPORT_DISTANCE)
281         dis = MAX_TELEPORT_DISTANCE;
282
283     int left = MAX(1, creature_ptr->x - dis);
284     int right = MIN(creature_ptr->current_floor_ptr->width - 2, creature_ptr->x + dis);
285     int top = MAX(1, creature_ptr->y - dis);
286     int bottom = MIN(creature_ptr->current_floor_ptr->height - 2, creature_ptr->y + dis);
287     int total_candidates = 0;
288     for (POSITION y = top; y <= bottom; y++) {
289         for (POSITION x = left; x <= right; x++) {
290             if (!cave_player_teleportable_bold(creature_ptr, y, x, mode))
291                 continue;
292
293             int d = distance(creature_ptr->y, creature_ptr->x, y, x);
294             if (d > dis)
295                 continue;
296
297             total_candidates++;
298             candidates_at[d]++;
299         }
300     }
301
302     if (0 == total_candidates)
303         return FALSE;
304
305     int cur_candidates;
306     int min = dis;
307     for (cur_candidates = 0; min >= 0; min--) {
308         cur_candidates += candidates_at[min];
309         if (cur_candidates && (cur_candidates >= total_candidates / 2))
310             break;
311     }
312
313     int pick = randint1(cur_candidates);
314
315     /* Search again the choosen location */
316     POSITION yy, xx = 0;
317     for (yy = top; yy <= bottom; yy++) {
318         for (xx = left; xx <= right; xx++) {
319             if (!cave_player_teleportable_bold(creature_ptr, yy, xx, mode))
320                 continue;
321
322             int d = distance(creature_ptr->y, creature_ptr->x, yy, xx);
323             if (d > dis)
324                 continue;
325             if (d < min)
326                 continue;
327
328             pick--;
329             if (!pick)
330                 break;
331         }
332
333         if (!pick)
334             break;
335     }
336
337     if (player_bold(creature_ptr, yy, xx))
338         return FALSE;
339
340     sound(SOUND_TELEPORT);
341 #ifdef JP
342     if (IS_ECHIZEN(creature_ptr))
343         msg_format("『こっちだぁ、%s』", creature_ptr->name);
344 #endif
345     (void)move_player_effect(creature_ptr, yy, xx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
346     return TRUE;
347 }
348
349 /*!
350  * @brief プレイヤーのテレポート処理メインルーチン
351  * @param creature_ptr プレーヤーへの参照ポインタ
352  * @param dis 基本移動距離
353  * @param mode オプション
354  * @return なし
355  */
356 void teleport_player(player_type *creature_ptr, POSITION dis, BIT_FLAGS mode)
357 {
358     if (!teleport_player_aux(creature_ptr, dis, FALSE, mode))
359         return;
360
361     /* Monsters with teleport ability may follow the player */
362     POSITION oy = creature_ptr->y;
363     POSITION ox = creature_ptr->x;
364     for (POSITION xx = -1; xx < 2; xx++) {
365         for (POSITION yy = -1; yy < 2; yy++) {
366             MONSTER_IDX tmp_m_idx = creature_ptr->current_floor_ptr->grid_array[oy + yy][ox + xx].m_idx;
367             if (tmp_m_idx && (creature_ptr->riding != tmp_m_idx)) {
368                 continue;
369             }
370
371             monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[tmp_m_idx];
372             monster_race *r_ptr = &r_info[m_ptr->r_idx];
373
374             bool is_resistible = (r_ptr->a_ability_flags2 & RF6_TPORT) != 0;
375             is_resistible &= (r_ptr->flagsr & RFR_RES_TELE) == 0;
376             is_resistible &= MON_CSLEEP(m_ptr) == 0;
377             if (is_resistible) {
378                 teleport_monster_to(creature_ptr, tmp_m_idx, creature_ptr->y, creature_ptr->x, r_ptr->level, TELEPORT_SPONTANEOUS);
379             }
380         }
381     }
382 }
383
384 /*!
385  * @brief プレイヤーのテレポートアウェイ処理 /
386  * @param m_idx アウェイを試みたモンスターID
387  * @param target_ptr プレーヤーへの参照ポインタ
388  * @param dis テレポート距離
389  * @param is_quantum_effect 量子的効果によるテレポートアウェイならばTRUE
390  * @return なし
391  */
392 void teleport_player_away(MONSTER_IDX m_idx, player_type *target_ptr, POSITION dis, bool is_quantum_effect)
393 {
394     if (!teleport_player_aux(target_ptr, dis, TELEPORT_PASSIVE, is_quantum_effect))
395         return;
396
397     /* Monsters with teleport ability may follow the player */
398     POSITION oy = target_ptr->y;
399     POSITION ox = target_ptr->x;
400     for (POSITION xx = -1; xx < 2; xx++) {
401         for (POSITION yy = -1; yy < 2; yy++) {
402             MONSTER_IDX tmp_m_idx = target_ptr->current_floor_ptr->grid_array[oy + yy][ox + xx].m_idx;
403             bool is_teleportable = tmp_m_idx > 0;
404             is_teleportable &= target_ptr->riding != tmp_m_idx;
405             is_teleportable &= m_idx != tmp_m_idx;
406             if (!is_teleportable) {
407                 continue;
408             }
409
410             monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[tmp_m_idx];
411             monster_race *r_ptr = &r_info[m_ptr->r_idx];
412
413             bool is_resistible = (r_ptr->a_ability_flags2 & RF6_TPORT) != 0;
414             is_resistible &= (r_ptr->flagsr & RFR_RES_TELE) == 0;
415             is_resistible &= MON_CSLEEP(m_ptr) == 0;
416             if (is_resistible) {
417                 teleport_monster_to(target_ptr, tmp_m_idx, target_ptr->y, target_ptr->x, r_ptr->level, TELEPORT_SPONTANEOUS);
418             }
419         }
420     }
421 }
422
423 /*!
424  * @brief プレイヤーを指定位置近辺にテレポートさせる
425  * Teleport player to a grid near the given location
426  * @param creature_ptr プレーヤーへの参照ポインタ
427  * @param ny 目標Y座標
428  * @param nx 目標X座標
429  * @param mode オプションフラグ
430  * @return なし
431  * @details
432  * <pre>
433  * This function is slightly obsessive about correctness.
434  * This function allows teleporting into vaults (!)
435  * </pre>
436  */
437 void teleport_player_to(player_type *creature_ptr, POSITION ny, POSITION nx, teleport_flags mode)
438 {
439     if (creature_ptr->anti_tele && !(mode & TELEPORT_NONMAGICAL)) {
440         msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
441         return;
442     }
443
444     /* Find a usable location */
445     POSITION y, x;
446     POSITION dis = 0, ctr = 0;
447     while (TRUE) {
448         while (TRUE) {
449             y = (POSITION)rand_spread(ny, dis);
450             x = (POSITION)rand_spread(nx, dis);
451             if (in_bounds(creature_ptr->current_floor_ptr, y, x))
452                 break;
453         }
454
455         bool is_anywhere = current_world_ptr->wizard;
456         is_anywhere &= (mode & TELEPORT_PASSIVE) == 0;
457         is_anywhere
458             &= (creature_ptr->current_floor_ptr->grid_array[y][x].m_idx > 0) || creature_ptr->current_floor_ptr->grid_array[y][x].m_idx == creature_ptr->riding;
459         if (is_anywhere)
460             break;
461
462         if (cave_player_teleportable_bold(creature_ptr, y, x, mode))
463             break;
464
465         if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
466             ctr = 0;
467             dis++;
468         }
469     }
470
471     sound(SOUND_TELEPORT);
472     (void)move_player_effect(creature_ptr, y, x, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
473 }
474
475 void teleport_away_followable(player_type *tracer_ptr, MONSTER_IDX m_idx)
476 {
477     monster_type *m_ptr = &tracer_ptr->current_floor_ptr->m_list[m_idx];
478     POSITION oldfy = m_ptr->fy;
479     POSITION oldfx = m_ptr->fx;
480     bool old_ml = m_ptr->ml;
481     POSITION old_cdis = m_ptr->cdis;
482
483     teleport_away(tracer_ptr, m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
484
485     bool is_followable = old_ml;
486     is_followable &= old_cdis <= MAX_SIGHT;
487     is_followable &= current_world_ptr->timewalk_m_idx == 0;
488     is_followable &= !tracer_ptr->phase_out;
489     is_followable &= los(tracer_ptr, tracer_ptr->y, tracer_ptr->x, oldfy, oldfx);
490     if (!is_followable)
491         return;
492
493     bool follow = FALSE;
494     if ((tracer_ptr->muta1 & MUT1_VTELEPORT) || (tracer_ptr->pclass == CLASS_IMITATOR))
495         follow = TRUE;
496     else {
497         BIT_FLAGS flgs[TR_FLAG_SIZE];
498         object_type *o_ptr;
499         INVENTORY_IDX i;
500
501         for (i = INVEN_RARM; i < INVEN_TOTAL; i++) {
502             o_ptr = &tracer_ptr->inventory_list[i];
503             if (o_ptr->k_idx && !object_is_cursed(o_ptr)) {
504                 object_flags(o_ptr, flgs);
505                 if (have_flag(flgs, TR_TELEPORT)) {
506                     follow = TRUE;
507                     break;
508                 }
509             }
510         }
511     }
512
513     if (!follow)
514         return;
515     if (!get_check_strict(_("ついていきますか?", "Do you follow it? "), CHECK_OKAY_CANCEL))
516         return;
517
518     if (one_in_(3)) {
519         teleport_player(tracer_ptr, 200, TELEPORT_PASSIVE);
520         msg_print(_("失敗!", "Failed!"));
521     } else {
522         teleport_player_to(tracer_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_SPONTANEOUS);
523     }
524
525     tracer_ptr->energy_need += ENERGY_NEED();
526 }
527
528 bool teleport_level_other(player_type *caster_ptr)
529 {
530     if (!target_set(caster_ptr, TARGET_KILL))
531         return FALSE;
532     MONSTER_IDX target_m_idx = caster_ptr->current_floor_ptr->grid_array[target_row][target_col].m_idx;
533     if (!target_m_idx)
534         return TRUE;
535     if (!player_has_los_bold(caster_ptr, target_row, target_col))
536         return TRUE;
537     if (!projectable(caster_ptr, caster_ptr->y, caster_ptr->x, target_row, target_col))
538         return TRUE;
539
540     monster_type *m_ptr;
541     monster_race *r_ptr;
542     m_ptr = &caster_ptr->current_floor_ptr->m_list[target_m_idx];
543     r_ptr = &r_info[m_ptr->r_idx];
544     GAME_TEXT m_name[MAX_NLEN];
545     monster_desc(caster_ptr, m_name, m_ptr, 0);
546     msg_format(_("%^sの足を指さした。", "You gesture at %^s's feet."), m_name);
547
548     if ((r_ptr->flagsr & (RFR_EFF_RES_NEXU_MASK | RFR_RES_TELE)) || (r_ptr->flags1 & RF1_QUESTOR)
549         || (r_ptr->level + randint1(50) > caster_ptr->lev + randint1(60))) {
550         msg_format(_("しかし効果がなかった!", "%^s is unaffected!"), m_name);
551     } else {
552         teleport_level(caster_ptr, target_m_idx);
553     }
554
555     return TRUE;
556 }
557
558 /*!
559  * todo cmd-save.h への依存あり。コールバックで何とかしたい
560  * @brief プレイヤー及びモンスターをレベルテレポートさせる /
561  * Teleport the player one level up or down (random when legal)
562  * @param creature_ptr プレーヤーへの参照ポインタ
563  * @param m_idx テレポートの対象となるモンスターID(0ならばプレイヤー) / If m_idx <= 0, target is player.
564  * @return なし
565  */
566 void teleport_level(player_type *creature_ptr, MONSTER_IDX m_idx)
567 {
568     GAME_TEXT m_name[160];
569     bool see_m = TRUE;
570     if (m_idx <= 0) {
571         strcpy(m_name, _("あなた", "you"));
572     } else {
573         monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[m_idx];
574         monster_desc(creature_ptr, m_name, m_ptr, 0);
575         see_m = is_seen(m_ptr);
576     }
577
578     if (is_teleport_level_ineffective(creature_ptr, m_idx)) {
579         if (see_m)
580             msg_print(_("効果がなかった。", "There is no effect."));
581         return;
582     }
583
584     if ((m_idx <= 0) && creature_ptr->anti_tele) {
585         msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
586         return;
587     }
588
589     bool go_up;
590     if (randint0(100) < 50)
591         go_up = TRUE;
592     else
593         go_up = FALSE;
594
595     if ((m_idx <= 0) && current_world_ptr->wizard) {
596         if (get_check("Force to go up? "))
597             go_up = TRUE;
598         else if (get_check("Force to go down? "))
599             go_up = FALSE;
600     }
601
602     if ((ironman_downward && (m_idx <= 0)) || (creature_ptr->current_floor_ptr->dun_level <= d_info[creature_ptr->dungeon_idx].mindepth)) {
603 #ifdef JP
604         if (see_m)
605             msg_format("%^sは床を突き破って沈んでいく。", m_name);
606 #else
607         if (see_m)
608             msg_format("%^s sink%s through the floor.", m_name, (m_idx <= 0) ? "" : "s");
609 #endif
610         if (m_idx <= 0) {
611             if (!creature_ptr->current_floor_ptr->dun_level) {
612                 creature_ptr->dungeon_idx = ironman_downward ? DUNGEON_ANGBAND : creature_ptr->recall_dungeon;
613                 creature_ptr->oldpy = creature_ptr->y;
614                 creature_ptr->oldpx = creature_ptr->x;
615             }
616
617             if (record_stair)
618                 exe_write_diary(creature_ptr, DIARY_TELEPORT_LEVEL, 1, NULL);
619
620             if (autosave_l)
621                 do_cmd_save_game(creature_ptr, TRUE);
622
623             if (!creature_ptr->current_floor_ptr->dun_level) {
624                 creature_ptr->current_floor_ptr->dun_level = d_info[creature_ptr->dungeon_idx].mindepth;
625                 prepare_change_floor_mode(creature_ptr, CFM_RAND_PLACE);
626             } else {
627                 prepare_change_floor_mode(creature_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
628             }
629
630             creature_ptr->leaving = TRUE;
631         }
632     } else if (quest_number(creature_ptr, creature_ptr->current_floor_ptr->dun_level)
633         || (creature_ptr->current_floor_ptr->dun_level >= d_info[creature_ptr->dungeon_idx].maxdepth)) {
634 #ifdef JP
635         if (see_m)
636             msg_format("%^sは天井を突き破って宙へ浮いていく。", m_name);
637 #else
638         if (see_m)
639             msg_format("%^s rise%s up through the ceiling.", m_name, (m_idx <= 0) ? "" : "s");
640 #endif
641
642         if (m_idx <= 0) {
643             if (record_stair)
644                 exe_write_diary(creature_ptr, DIARY_TELEPORT_LEVEL, -1, NULL);
645
646             if (autosave_l)
647                 do_cmd_save_game(creature_ptr, TRUE);
648
649             prepare_change_floor_mode(creature_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_RAND_PLACE | CFM_RAND_CONNECT);
650
651             leave_quest_check(creature_ptr);
652             creature_ptr->current_floor_ptr->inside_quest = 0;
653             creature_ptr->leaving = TRUE;
654         }
655     } else if (go_up) {
656 #ifdef JP
657         if (see_m)
658             msg_format("%^sは天井を突き破って宙へ浮いていく。", m_name);
659 #else
660         if (see_m)
661             msg_format("%^s rise%s up through the ceiling.", m_name, (m_idx <= 0) ? "" : "s");
662 #endif
663
664         if (m_idx <= 0) {
665             if (record_stair)
666                 exe_write_diary(creature_ptr, DIARY_TELEPORT_LEVEL, -1, NULL);
667
668             if (autosave_l)
669                 do_cmd_save_game(creature_ptr, TRUE);
670
671             prepare_change_floor_mode(creature_ptr, CFM_SAVE_FLOORS | CFM_UP | CFM_RAND_PLACE | CFM_RAND_CONNECT);
672             creature_ptr->leaving = TRUE;
673         }
674     } else {
675 #ifdef JP
676         if (see_m)
677             msg_format("%^sは床を突き破って沈んでいく。", m_name);
678 #else
679         if (see_m)
680             msg_format("%^s sink%s through the floor.", m_name, (m_idx <= 0) ? "" : "s");
681 #endif
682
683         if (m_idx <= 0) {
684             if (record_stair)
685                 exe_write_diary(creature_ptr, DIARY_TELEPORT_LEVEL, 1, NULL);
686             if (autosave_l)
687                 do_cmd_save_game(creature_ptr, TRUE);
688
689             prepare_change_floor_mode(creature_ptr, CFM_SAVE_FLOORS | CFM_DOWN | CFM_RAND_PLACE | CFM_RAND_CONNECT);
690             creature_ptr->leaving = TRUE;
691         }
692     }
693
694     if (m_idx <= 0) {
695         sound(SOUND_TPLEVEL);
696         return;
697     }
698
699     monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[m_idx];
700     check_quest_completion(creature_ptr, m_ptr);
701     if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname) {
702         char m2_name[MAX_NLEN];
703
704         monster_desc(creature_ptr, m2_name, m_ptr, MD_INDEF_VISIBLE);
705         exe_write_diary(creature_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_TELE_LEVEL, m2_name);
706     }
707
708     delete_monster_idx(creature_ptr, m_idx);
709     sound(SOUND_TPLEVEL);
710 }
711
712 /*!
713  * todo 変数名が実態と合っているかどうかは要確認
714  * テレポート・レベルが効かないモンスターであるかどうかを判定する
715  * @param caster_ptr プレーヤーへの参照ポインタ
716  * @param idx テレポート・レベル対象のモンスター
717  */
718 bool is_teleport_level_ineffective(player_type *caster_ptr, MONSTER_IDX idx)
719 {
720     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
721     bool is_special_floor
722         = floor_ptr->inside_arena || caster_ptr->phase_out || (floor_ptr->inside_quest && !random_quest_number(caster_ptr, floor_ptr->dun_level));
723     bool is_invalid_floor = idx <= 0;
724     is_invalid_floor &= quest_number(caster_ptr, floor_ptr->dun_level) || (floor_ptr->dun_level >= d_info[caster_ptr->dungeon_idx].maxdepth);
725     is_invalid_floor &= caster_ptr->current_floor_ptr->dun_level >= 1;
726     is_invalid_floor &= ironman_downward;
727     return is_special_floor || is_invalid_floor;
728 }