OSDN Git Service

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