OSDN Git Service

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