8 #include "mind/mind-mirror-master.h"
9 #include "core/disturbance.h"
10 #include "core/stuff-handler.h"
11 #include "effect/attribute-types.h"
12 #include "effect/effect-characteristics.h"
13 #include "effect/effect-feature.h"
14 #include "effect/effect-item.h"
15 #include "effect/effect-monster.h"
16 #include "effect/effect-processor.h"
17 #include "effect/spells-effect-util.h"
18 #include "floor/cave.h"
19 #include "floor/geometry.h"
20 #include "game-option/disturbance-options.h"
21 #include "game-option/map-screen-options.h"
22 #include "game-option/special-options.h"
23 #include "grid/feature.h"
24 #include "grid/grid.h"
25 #include "io/cursor.h"
26 #include "io/screen-util.h"
27 #include "mind/mind-magic-resistance.h"
28 #include "mind/mind-numbers.h"
29 #include "pet/pet-util.h"
30 #include "spell-class/spells-mirror-master.h"
31 #include "spell-kind/spells-detection.h"
32 #include "spell-kind/spells-floor.h"
33 #include "spell-kind/spells-launcher.h"
34 #include "spell-kind/spells-lite.h"
35 #include "spell-kind/spells-sight.h"
36 #include "spell-kind/spells-teleport.h"
37 #include "spell-kind/spells-world.h"
38 #include "status/body-improvement.h"
39 #include "status/buff-setter.h"
40 #include "status/sight-setter.h"
41 #include "system/floor-type-definition.h"
42 #include "system/grid-type-definition.h"
43 #include "system/player-type-definition.h"
44 #include "system/redrawing-flags-updater.h"
45 #include "target/grid-selector.h"
46 #include "target/projection-path-calculator.h"
47 #include "target/target-getter.h"
48 #include "timed-effect/player-blindness.h"
49 #include "timed-effect/timed-effects.h"
50 #include "util/bit-flags-calculator.h"
51 #include "view/display-messages.h"
52 #include "world/world.h"
55 * @brief Multishadow effects is determined by turn
57 bool check_multishadow(PlayerType *player_ptr)
59 return (player_ptr->multishadow != 0) && ((w_ptr->game_turn & 1) != 0);
63 * @brief 鏡魔法「封魔結界」の効果処理
65 * @return 効果があったらTRUEを返す
67 bool binding_field(PlayerType *player_ptr, int dam)
69 POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
70 int mirror_num = 0; /* 鏡の数 */
76 /* Default target of monsterspell is player */
77 monster_target_y = player_ptr->y;
78 monster_target_x = player_ptr->x;
80 for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
81 for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++) {
82 if (!player_ptr->current_floor_ptr->grid_array[y][x].is_mirror()) {
86 const auto dist = distance(player_ptr->y, player_ptr->x, y, x);
87 const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, y, x);
88 if ((dist == 0) || (dist > get_max_range(player_ptr)) || !player_has_los_bold(player_ptr, y, x) || !is_projectable) {
92 mirror_y[mirror_num] = y;
93 mirror_x[mirror_num] = x;
102 point_x[0] = randint0(mirror_num);
104 point_x[1] = randint0(mirror_num);
105 } while (point_x[0] == point_x[1]);
107 point_y[0] = mirror_y[point_x[0]];
108 point_x[0] = mirror_x[point_x[0]];
109 point_y[1] = mirror_y[point_x[1]];
110 point_x[1] = mirror_x[point_x[1]];
111 point_y[2] = player_ptr->y;
112 point_x[2] = player_ptr->x;
114 POSITION x = point_x[0] + point_x[1] + point_x[2];
115 POSITION y = point_y[0] + point_y[1] + point_y[2];
117 POSITION centersign = (point_x[0] * 3 - x) * (point_y[1] * 3 - y) - (point_y[0] * 3 - y) * (point_x[1] * 3 - x);
118 if (centersign == 0) {
122 POSITION x1 = point_x[0] < point_x[1] ? point_x[0] : point_x[1];
123 x1 = x1 < point_x[2] ? x1 : point_x[2];
124 POSITION y1 = point_y[0] < point_y[1] ? point_y[0] : point_y[1];
125 y1 = y1 < point_y[2] ? y1 : point_y[2];
127 POSITION x2 = point_x[0] > point_x[1] ? point_x[0] : point_x[1];
128 x2 = x2 > point_x[2] ? x2 : point_x[2];
129 POSITION y2 = point_y[0] > point_y[1] ? point_y[0] : point_y[1];
130 y2 = y2 > point_y[2] ? y2 : point_y[2];
132 for (y = y1; y <= y2; y++) {
133 for (x = x1; x <= x2; x++) {
134 if ((centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0)) {
138 if ((centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0)) {
142 if ((centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0)) {
146 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
147 if (!(player_ptr->effects()->blindness()->is_blind()) && panel_contains(y, x)) {
148 print_bolt_pict(player_ptr, y, x, y, x, AttributeType::MANA);
149 move_cursor_relative(y, x);
151 term_xtra(TERM_XTRA_DELAY, delay_factor);
157 for (y = y1; y <= y2; y++) {
158 for (x = x1; x <= x2; x++) {
159 if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
163 if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
167 if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
171 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
172 (void)affect_feature(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
177 for (y = y1; y <= y2; y++) {
178 for (x = x1; x <= x2; x++) {
179 if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
183 if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
187 if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
191 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
192 (void)affect_item(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
197 for (y = y1; y <= y2; y++) {
198 for (x = x1; x <= x2; x++) {
199 if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) < 0) {
203 if (centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) < 0) {
207 if (centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) < 0) {
211 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
212 constexpr auto flags = PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP;
213 (void)affect_monster(player_ptr, 0, 0, y, x, dam, AttributeType::MANA, flags, true);
219 msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
220 SpellsMirrorMaster(player_ptr).remove_mirror(point_y[0], point_x[0]);
227 * 幻惑の光 @ 鏡使いだけでなく混沌の戦士も使える
228 * @param player_ptr プレイヤーへの参照ポインタ
231 bool confusing_light(PlayerType *player_ptr)
233 msg_print(_("辺りを睨んだ...", "You glare at nearby monsters..."));
234 slow_monsters(player_ptr, player_ptr->lev);
235 stun_monsters(player_ptr, player_ptr->lev * 4);
236 confuse_monsters(player_ptr, player_ptr->lev * 4);
237 turn_monsters(player_ptr, player_ptr->lev * 4);
238 stasis_monsters(player_ptr, player_ptr->lev * 4);
243 * Set "multishadow", notice observable changes
245 bool set_multishadow(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
248 v = (v > 10000) ? 10000 : (v < 0) ? 0
251 if (player_ptr->is_dead) {
256 if (player_ptr->multishadow && !do_dec) {
257 if (player_ptr->multishadow > v) {
260 } else if (!player_ptr->multishadow) {
261 msg_print(_("あなたの周りに幻影が生まれた。", "Your Shadow enveloped you."));
265 if (player_ptr->multishadow) {
266 msg_print(_("幻影が消えた。", "Your Shadow disappears."));
271 player_ptr->multishadow = v;
272 auto &rfu = RedrawingFlagsUpdater::get_instance();
273 rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
279 disturb(player_ptr, false, false);
282 rfu.set_flag(StatusRecalculatingFlag::BONUS);
283 handle_stuff(player_ptr);
288 * @brief 一時的破片のオーラの継続時間をセットする / Set "dustrobe", notice observable changes
290 * @param do_dec 現在の継続時間より長い値のみ上書きする
291 * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
293 bool set_dustrobe(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
296 v = (v > 10000) ? 10000 : (v < 0) ? 0
299 if (player_ptr->is_dead) {
304 if (player_ptr->dustrobe && !do_dec) {
305 if (player_ptr->dustrobe > v) {
308 } else if (!player_ptr->dustrobe) {
309 msg_print(_("体が鏡のオーラで覆われた。", "You are enveloped by mirror shards."));
313 if (player_ptr->dustrobe) {
314 msg_print(_("鏡のオーラが消えた。", "The mirror shards disappear."));
319 player_ptr->dustrobe = v;
320 auto &rfu = RedrawingFlagsUpdater::get_instance();
321 rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
327 disturb(player_ptr, false, false);
330 rfu.set_flag(StatusRecalculatingFlag::BONUS);
331 handle_stuff(player_ptr);
336 * @brief 現在フロアに存在している鏡の数を数える / calculate mirrors
339 static int number_of_mirrors(FloorType *floor_ptr)
342 for (POSITION x = 0; x < floor_ptr->width; x++) {
343 for (POSITION y = 0; y < floor_ptr->height; y++) {
344 if (floor_ptr->grid_array[y][x].is_mirror()) {
355 * do_cmd_cast calls this function if the player's class is 'Mirror magic'.
356 * @param spell 発動する特殊技能のID
357 * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
359 bool cast_mirror_spell(PlayerType *player_ptr, MindMirrorMasterType spell)
362 PLAYER_LEVEL plev = player_ptr->lev;
366 auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
368 case MindMirrorMasterType::MIRROR_SEEING:
369 tmp = g_ptr->is_mirror() ? 4 : 0;
370 if (plev + tmp > 4) {
371 detect_monsters_normal(player_ptr, DETECT_RAD_DEFAULT);
373 if (plev + tmp > 18) {
374 detect_monsters_invis(player_ptr, DETECT_RAD_DEFAULT);
376 if (plev + tmp > 28) {
377 set_tim_esp(player_ptr, (TIME_EFFECT)plev, false);
379 if (plev + tmp > 38) {
380 map_area(player_ptr, DETECT_RAD_MAP);
382 if (tmp == 0 && plev < 5) {
383 msg_print(_("鏡がなくて集中できなかった!", "You need a mirror to concentrate!"));
386 case MindMirrorMasterType::MAKE_MIRROR:
387 if (number_of_mirrors(player_ptr->current_floor_ptr) < 4 + plev / 10) {
388 SpellsMirrorMaster(player_ptr).place_mirror();
390 msg_format(_("これ以上鏡は制御できない!", "There are too many mirrors to control!"));
394 case MindMirrorMasterType::DRIP_LIGHT:
395 if (!get_aim_dir(player_ptr, &dir)) {
399 if (plev > 9 && g_ptr->is_mirror()) {
400 fire_beam(player_ptr, AttributeType::LITE, dir, damroll(3 + ((plev - 1) / 5), 4));
402 fire_bolt(player_ptr, AttributeType::LITE, dir, damroll(3 + ((plev - 1) / 5), 4));
406 case MindMirrorMasterType::WRAPPED_MIRROR:
407 teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
409 case MindMirrorMasterType::MIRROR_LIGHT:
410 (void)lite_area(player_ptr, damroll(2, (plev / 2)), (plev / 10) + 1);
412 case MindMirrorMasterType::WANDERING_MIRROR:
413 teleport_player(player_ptr, plev * 5, TELEPORT_SPONTANEOUS);
415 case MindMirrorMasterType::ROBE_DUST:
416 set_dustrobe(player_ptr, 20 + randint1(20), false);
418 case MindMirrorMasterType::BANISHING_MIRROR:
419 if (!get_aim_dir(player_ptr, &dir)) {
423 (void)fire_beam(player_ptr, AttributeType::AWAY_ALL, dir, plev);
425 case MindMirrorMasterType::MIRROR_CRASHING:
426 if (!get_aim_dir(player_ptr, &dir)) {
430 fire_ball(player_ptr, AttributeType::SHARDS, dir, damroll(8 + ((plev - 5) / 4), 8), (plev > 20 ? (plev - 20) / 8 + 1 : 0));
432 case MindMirrorMasterType::SLEEPING_MIRROR:
433 for (x = 0; x < player_ptr->current_floor_ptr->width; x++) {
434 for (y = 0; y < player_ptr->current_floor_ptr->height; y++) {
435 if (player_ptr->current_floor_ptr->grid_array[y][x].is_mirror()) {
436 project(player_ptr, 0, 2, y, x, (int)plev, AttributeType::OLD_SLEEP,
437 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
443 case MindMirrorMasterType::SEEKER_RAY:
444 if (!get_aim_dir(player_ptr, &dir)) {
448 SpellsMirrorMaster(player_ptr).seeker_ray(dir, damroll(11 + (plev - 5) / 4, 8));
450 case MindMirrorMasterType::SEALING_MIRROR:
451 SpellsMirrorMaster(player_ptr).seal_of_mirror(plev * 4 + 100);
453 case MindMirrorMasterType::WATER_SHIELD:
454 t = 20 + randint1(20);
455 set_shield(player_ptr, t, false);
457 set_tim_reflect(player_ptr, t, false);
461 set_resist_magic(player_ptr, t, false);
465 case MindMirrorMasterType::SUPER_RAY:
466 if (!get_aim_dir(player_ptr, &dir)) {
470 SpellsMirrorMaster(player_ptr).super_ray(dir, damroll(11 + (plev - 5) / 4, 8));
472 case MindMirrorMasterType::ILLUSION_LIGHT:
473 tmp = g_ptr->is_mirror() ? 4 : 3;
474 slow_monsters(player_ptr, plev);
475 stun_monsters(player_ptr, plev * tmp * 2);
476 confuse_monsters(player_ptr, plev * tmp);
477 turn_monsters(player_ptr, plev * tmp);
478 stasis_monsters(player_ptr, plev * tmp);
480 case MindMirrorMasterType::MIRROR_SHIFT:
481 if (!g_ptr->is_mirror()) {
482 msg_print(_("鏡の国の場所がわからない!", "You cannot find out where the mirror is!"));
486 reserve_alter_reality(player_ptr, randint0(21) + 15);
488 case MindMirrorMasterType::MIRROR_TUNNEL:
489 msg_print(_("鏡の世界を通り抜け… ", "You try to enter the mirror..."));
490 return SpellsMirrorMaster(player_ptr).mirror_tunnel();
491 case MindMirrorMasterType::RECALL_MIRROR:
492 return recall_player(player_ptr, randint0(21) + 15);
493 case MindMirrorMasterType::MULTI_SHADOW:
494 set_multishadow(player_ptr, 6 + randint1(6), false);
496 case MindMirrorMasterType::BINDING_FIELD:
497 if (!binding_field(player_ptr, plev * 11 + 5)) {
498 msg_print(_("適当な鏡を選べなかった!", "You were not able to choose suitable mirrors!"));
502 case MindMirrorMasterType::RUFFNOR_MIRROR:
503 (void)set_invuln(player_ptr, randint1(4) + 4, false);
506 msg_print(_("なに?", "Zap?"));