7 #include "spell-kind/spells-teleport.h"
8 #include "core/asking-player.h"
9 #include "core/player-update-types.h"
10 #include "core/speed-table.h"
11 #include "effect/effect-characteristics.h"
12 #include "floor/cave.h"
13 #include "floor/geometry.h"
14 #include "floor/line-of-sight.h"
15 #include "grid/grid.h"
16 #include "inventory/inventory-slot-types.h"
17 #include "main/sound-definitions-table.h"
18 #include "main/sound-of-music.h"
19 #include "monster-floor/monster-move.h"
20 #include "monster-race/monster-race.h"
21 #include "monster-race/race-flags-resistance.h"
22 #include "monster-race/race-flags7.h"
23 #include "monster/monster-info.h"
24 #include "monster/monster-status-setter.h"
25 #include "monster/monster-status.h"
26 #include "monster/monster-update.h"
27 #include "mutation/mutation-flag-types.h"
28 #include "object-enchant/tr-types.h"
29 #include "object-hook/hook-checker.h"
30 #include "object/object-flags.h"
31 #include "player-info/avatar.h"
32 #include "player/player-move.h"
33 #include "player/player-status.h"
34 #include "spell-kind/spells-launcher.h"
35 #include "spell/spell-types.h"
36 #include "system/floor-type-definition.h"
37 #include "system/monster-race-definition.h"
38 #include "system/monster-type-definition.h"
39 #include "system/object-type-definition.h"
40 #include "system/player-type-definition.h"
41 #include "target/grid-selector.h"
42 #include "target/target-checker.h"
43 #include "util/bit-flags-calculator.h"
44 #include "view/display-messages.h"
45 #include "world/world.h"
48 * @brief モンスターとの位置交換処理 / Switch position with a monster.
49 * @param caster_ptr プレーヤーへの参照ポインタ
50 * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
51 * @return 作用が実際にあった場合TRUEを返す
53 bool teleport_swap(player_type *caster_ptr, DIRECTION dir)
56 if ((dir == 5) && target_okay(caster_ptr)) {
60 tx = caster_ptr->x + ddx[dir];
61 ty = caster_ptr->y + ddy[dir];
64 if (caster_ptr->anti_tele) {
65 msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
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!"));
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."));
83 m_ptr = &caster_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
84 r_ptr = &r_info[m_ptr->r_idx];
86 (void)set_monster_csleep(caster_ptr, g_ptr->m_idx, 0);
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;
95 sound(SOUND_TELEPORT);
96 (void)move_player_effect(caster_ptr, ty, tx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
101 * @brief モンスター用テレポート処理
102 * @param caster_ptr プレーヤーへの参照ポインタ
103 * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
104 * @param distance 移動距離
105 * @return 作用が実際にあった場合TRUEを返す
107 bool teleport_monster(player_type *caster_ptr, DIRECTION dir, int distance)
109 BIT_FLAGS flg = PROJECT_BEAM | PROJECT_KILL;
110 return (project_hook(caster_ptr, GF_AWAY_ALL, dir, distance, flg));
114 * @brief モンスターのテレポートアウェイ処理 /
115 * Teleport a monster, normally up to "dis" grids away.
116 * @param caster_ptr プレーヤーへの参照ポインタ
117 * @param m_idx モンスターID
120 * @return テレポートが実際に行われたらtrue
122 * Attempt to move the monster at least "dis/2" grids away.
123 * But allow variation to prevent infinite loops.
125 bool teleport_away(player_type *caster_ptr, MONSTER_IDX m_idx, POSITION dis, teleport_flags mode)
127 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
128 if (!monster_is_valid(m_ptr))
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);
135 POSITION oy = m_ptr->fy;
136 POSITION ox = m_ptr->fx;
137 POSITION min = dis / 2;
139 POSITION ny = 0, nx = 0;
146 for (int i = 0; i < 500; i++) {
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))
155 if (!in_bounds(caster_ptr->current_floor_ptr, ny, nx))
157 if (!cave_monster_teleportable_bold(caster_ptr, m_idx, ny, nx, mode))
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)
169 const int MAX_TELEPORT_TRIES = 100;
170 if (tries > MAX_TELEPORT_TRIES)
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;
182 update_monster(caster_ptr, m_idx, TRUE);
183 lite_spot(caster_ptr, oy, ox);
184 lite_spot(caster_ptr, ny, nx);
186 if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
187 caster_ptr->update |= (PU_MON_LITE);
193 * @brief モンスターを指定された座標付近にテレポートする /
194 * Teleport monster next to a grid near the given location
195 * @param caster_ptr プレーヤーへの参照ポインタ
196 * @param m_idx モンスターID
199 * @param power テレポート成功確率
202 void teleport_monster_to(player_type *caster_ptr, MONSTER_IDX m_idx, POSITION ty, POSITION tx, int power, teleport_flags mode)
204 monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[m_idx];
207 if (randint1(100) > power)
210 POSITION ny = m_ptr->fy;
211 POSITION nx = m_ptr->fx;
212 POSITION oy = m_ptr->fy;
213 POSITION ox = m_ptr->fx;
219 while (look && --attempts) {
223 for (int i = 0; i < 500; i++) {
225 ny = rand_spread(ty, dis);
226 nx = rand_spread(tx, dis);
227 int d = distance(ty, tx, ny, nx);
228 if ((d >= min) && (d <= dis))
232 if (!in_bounds(caster_ptr->current_floor_ptr, ny, nx))
234 if (!cave_monster_teleportable_bold(caster_ptr, m_idx, ny, nx, mode))
248 sound(SOUND_TPOTHER);
249 caster_ptr->current_floor_ptr->grid_array[oy][ox].m_idx = 0;
250 caster_ptr->current_floor_ptr->grid_array[ny][nx].m_idx = m_idx;
255 update_monster(caster_ptr, m_idx, TRUE);
256 lite_spot(caster_ptr, oy, ox);
257 lite_spot(caster_ptr, ny, nx);
259 if (r_info[m_ptr->r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK))
260 caster_ptr->update |= (PU_MON_LITE);
264 * @brief プレイヤーのテレポート先選定と移動処理 /
265 * Teleport the player to a location up to "dis" grids away.
266 * @param creature_ptr プレーヤーへの参照ポインタ
268 * @param is_quantum_effect 量子的効果 (反テレポ無効)によるテレポートアウェイならばTRUE
270 * @return 実際にテレポート処理が行われたらtrue
273 * If no such spaces are readily available, the distance may increase.
274 * Try very hard to move the player at least a quarter that distance.
276 * There was a nasty tendency for a long time; which was causing the
277 * player to "bounce" between two or three different spots because
278 * these are the only spots that are "far enough" way to satisfy the
281 * But this tendency is now removed; in the new algorithm, a list of
282 * candidates is selected first, which includes at least 50% of all
283 * floor grids within the distance, and any single grid in this list
284 * of candidates has equal possibility to be choosen as a destination.
287 bool teleport_player_aux(player_type *creature_ptr, POSITION dis, bool is_quantum_effect, teleport_flags mode)
289 if (creature_ptr->wild_mode)
291 if (!is_quantum_effect && creature_ptr->anti_tele && !(mode & TELEPORT_NONMAGICAL)) {
292 msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
296 int candidates_at[MAX_TELEPORT_DISTANCE + 1];
297 for (int i = 0; i <= MAX_TELEPORT_DISTANCE; i++)
298 candidates_at[i] = 0;
300 if (dis > MAX_TELEPORT_DISTANCE)
301 dis = MAX_TELEPORT_DISTANCE;
303 int left = MAX(1, creature_ptr->x - dis);
304 int right = MIN(creature_ptr->current_floor_ptr->width - 2, creature_ptr->x + dis);
305 int top = MAX(1, creature_ptr->y - dis);
306 int bottom = MIN(creature_ptr->current_floor_ptr->height - 2, creature_ptr->y + dis);
307 int total_candidates = 0;
308 for (POSITION y = top; y <= bottom; y++) {
309 for (POSITION x = left; x <= right; x++) {
310 if (!cave_player_teleportable_bold(creature_ptr, y, x, mode))
313 int d = distance(creature_ptr->y, creature_ptr->x, y, x);
322 if (0 == total_candidates)
327 for (cur_candidates = 0; min >= 0; min--) {
328 cur_candidates += candidates_at[min];
329 if (cur_candidates && (cur_candidates >= total_candidates / 2))
333 int pick = randint1(cur_candidates);
335 /* Search again the choosen location */
337 for (yy = top; yy <= bottom; yy++) {
338 for (xx = left; xx <= right; xx++) {
339 if (!cave_player_teleportable_bold(creature_ptr, yy, xx, mode))
342 int d = distance(creature_ptr->y, creature_ptr->x, yy, xx);
357 if (player_bold(creature_ptr, yy, xx))
360 sound(SOUND_TELEPORT);
362 if (is_echizen(creature_ptr))
363 msg_format("『こっちだぁ、%s』", creature_ptr->name);
365 (void)move_player_effect(creature_ptr, yy, xx, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
370 * @brief プレイヤーのテレポート処理メインルーチン
371 * @param creature_ptr プレーヤーへの参照ポインタ
375 void teleport_player(player_type *creature_ptr, POSITION dis, BIT_FLAGS mode)
377 const POSITION oy = creature_ptr->y;
378 const POSITION ox = creature_ptr->x;
380 if (!teleport_player_aux(creature_ptr, dis, FALSE, static_cast<teleport_flags>(mode)))
383 /* Monsters with teleport ability may follow the player */
384 for (POSITION xx = -1; xx < 2; xx++) {
385 for (POSITION yy = -1; yy < 2; yy++) {
386 MONSTER_IDX tmp_m_idx = creature_ptr->current_floor_ptr->grid_array[oy + yy][ox + xx].m_idx;
387 if (tmp_m_idx && (creature_ptr->riding != tmp_m_idx)) {
388 monster_type *m_ptr = &creature_ptr->current_floor_ptr->m_list[tmp_m_idx];
389 monster_race *r_ptr = &r_info[m_ptr->r_idx];
391 bool can_follow = r_ptr->ability_flags.has(RF_ABILITY::TPORT);
392 can_follow &= none_bits(r_ptr->flagsr, RFR_RES_TELE);
393 can_follow &= monster_csleep_remaining(m_ptr) == 0;
395 teleport_monster_to(creature_ptr, tmp_m_idx, creature_ptr->y, creature_ptr->x, r_ptr->level, TELEPORT_SPONTANEOUS);
403 * @brief プレイヤーのテレポートアウェイ処理 /
404 * @param m_idx アウェイを試みたモンスターID
405 * @param target_ptr プレーヤーへの参照ポインタ
407 * @param is_quantum_effect 量子的効果によるテレポートアウェイならばTRUE
409 void teleport_player_away(MONSTER_IDX m_idx, player_type *target_ptr, POSITION dis, bool is_quantum_effect)
411 const POSITION oy = target_ptr->y;
412 const POSITION ox = target_ptr->x;
414 if (!teleport_player_aux(target_ptr, dis, is_quantum_effect, TELEPORT_PASSIVE))
417 /* Monsters with teleport ability may follow the player */
418 for (POSITION xx = -1; xx < 2; xx++) {
419 for (POSITION yy = -1; yy < 2; yy++) {
420 MONSTER_IDX tmp_m_idx = target_ptr->current_floor_ptr->grid_array[oy + yy][ox + xx].m_idx;
421 bool is_teleportable = tmp_m_idx > 0;
422 is_teleportable &= target_ptr->riding != tmp_m_idx;
423 is_teleportable &= m_idx != tmp_m_idx;
424 if (!is_teleportable) {
428 monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[tmp_m_idx];
429 monster_race *r_ptr = &r_info[m_ptr->r_idx];
431 bool can_follow = r_ptr->ability_flags.has(RF_ABILITY::TPORT);
432 can_follow &= none_bits(r_ptr->flagsr, RFR_RES_TELE);
433 can_follow &= monster_csleep_remaining(m_ptr) == 0;
435 teleport_monster_to(target_ptr, tmp_m_idx, target_ptr->y, target_ptr->x, r_ptr->level, TELEPORT_SPONTANEOUS);
442 * @brief プレイヤーを指定位置近辺にテレポートさせる
443 * Teleport player to a grid near the given location
444 * @param creature_ptr プレーヤーへの参照ポインタ
447 * @param mode オプションフラグ
450 * This function is slightly obsessive about correctness.
451 * This function allows teleporting into vaults (!)
454 void teleport_player_to(player_type *creature_ptr, POSITION ny, POSITION nx, teleport_flags mode)
456 if (creature_ptr->anti_tele && !(mode & TELEPORT_NONMAGICAL)) {
457 msg_print(_("不思議な力がテレポートを防いだ!", "A mysterious force prevents you from teleporting!"));
461 /* Find a usable location */
463 POSITION dis = 0, ctr = 0;
466 y = (POSITION)rand_spread(ny, dis);
467 x = (POSITION)rand_spread(nx, dis);
468 if (in_bounds(creature_ptr->current_floor_ptr, y, x))
472 bool is_anywhere = current_world_ptr->wizard;
473 is_anywhere &= (mode & TELEPORT_PASSIVE) == 0;
475 &= (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;
479 if (cave_player_teleportable_bold(creature_ptr, y, x, mode))
482 if (++ctr > (4 * dis * dis + 4 * dis + 1)) {
488 sound(SOUND_TELEPORT);
489 (void)move_player_effect(creature_ptr, y, x, MPE_FORGET_FLOW | MPE_HANDLE_STUFF | MPE_DONT_PICKUP);
492 void teleport_away_followable(player_type *tracer_ptr, MONSTER_IDX m_idx)
494 monster_type *m_ptr = &tracer_ptr->current_floor_ptr->m_list[m_idx];
495 POSITION oldfy = m_ptr->fy;
496 POSITION oldfx = m_ptr->fx;
497 bool old_ml = m_ptr->ml;
498 POSITION old_cdis = m_ptr->cdis;
500 teleport_away(tracer_ptr, m_idx, MAX_SIGHT * 2 + 5, TELEPORT_SPONTANEOUS);
502 bool is_followable = old_ml;
503 is_followable &= old_cdis <= MAX_SIGHT;
504 is_followable &= current_world_ptr->timewalk_m_idx == 0;
505 is_followable &= !tracer_ptr->phase_out;
506 is_followable &= los(tracer_ptr, tracer_ptr->y, tracer_ptr->x, oldfy, oldfx);
511 if (tracer_ptr->muta.has(MUTA::VTELEPORT) || (tracer_ptr->pclass == CLASS_IMITATOR))
514 BIT_FLAGS flgs[TR_FLAG_SIZE];
518 for (i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
519 o_ptr = &tracer_ptr->inventory_list[i];
520 if (o_ptr->k_idx && !object_is_cursed(o_ptr)) {
521 object_flags(tracer_ptr, o_ptr, flgs);
522 if (has_flag(flgs, TR_TELEPORT)) {
532 if (!get_check_strict(tracer_ptr, _("ついていきますか?", "Do you follow it? "), CHECK_OKAY_CANCEL))
536 teleport_player(tracer_ptr, 200, TELEPORT_PASSIVE);
537 msg_print(_("失敗!", "Failed!"));
539 teleport_player_to(tracer_ptr, m_ptr->fy, m_ptr->fx, TELEPORT_SPONTANEOUS);
542 tracer_ptr->energy_need += ENERGY_NEED();
548 * @param caster_ptr プレーヤーへの参照ポインタ
549 * @param x テレポート先のX座標
550 * @param y テレポート先のY座標
551 * @return 目標に指定通りテレポートできたならばTRUEを返す
553 bool exe_dimension_door(player_type *caster_ptr, POSITION x, POSITION y)
555 PLAYER_LEVEL plev = caster_ptr->lev;
557 caster_ptr->energy_need += (s16b)((s32b)(60 - plev) * ENERGY_NEED() / 100L);
559 if (!cave_player_teleportable_bold(caster_ptr, y, x, TELEPORT_SPONTANEOUS) || (distance(y, x, caster_ptr->y, caster_ptr->x) > plev / 2 + 10)
560 || (!randint0(plev / 10 + 10))) {
561 caster_ptr->energy_need += (s16b)((s32b)(60 - plev) * ENERGY_NEED() / 100L);
562 teleport_player(caster_ptr, (plev + 2) * 2, TELEPORT_PASSIVE);
566 teleport_player_to(caster_ptr, y, x, TELEPORT_SPONTANEOUS);
571 * @brief 次元の扉処理のメインルーチン /
572 * @param caster_ptr プレーヤーへの参照ポインタ
574 * @return ターンを消費した場合TRUEを返す
576 bool dimension_door(player_type *caster_ptr)
579 if (!tgt_pt(caster_ptr, &x, &y))
582 if (exe_dimension_door(caster_ptr, x, y))
585 msg_print(_("精霊界から物質界に戻る時うまくいかなかった!", "You fail to exit the astral plane correctly!"));