OSDN Git Service

[Refactor] #2523 PlayerType::blind をPlayerBlindnessの呼び出しに差し替えた
[hengbandforosx/hengbandosx.git] / src / mind / mind-mirror-master.cpp
1 /*!
2  * @brief 鏡使いの鏡魔法コマンド処理
3  * @date 2022/03/07
4  * @author Hourier
5  * @todo 作りかけの部分複数あり
6  */
7
8 #include "mind/mind-mirror-master.h"
9 #include "core/disturbance.h"
10 #include "core/player-redraw-types.h"
11 #include "core/player-update-types.h"
12 #include "core/stuff-handler.h"
13 #include "effect/attribute-types.h"
14 #include "effect/effect-characteristics.h"
15 #include "effect/effect-feature.h"
16 #include "effect/effect-item.h"
17 #include "effect/effect-monster.h"
18 #include "effect/effect-processor.h"
19 #include "effect/spells-effect-util.h"
20 #include "floor/cave.h"
21 #include "floor/geometry.h"
22 #include "game-option/disturbance-options.h"
23 #include "game-option/map-screen-options.h"
24 #include "game-option/special-options.h"
25 #include "grid/feature.h"
26 #include "grid/grid.h"
27 #include "io/cursor.h"
28 #include "io/screen-util.h"
29 #include "mind/mind-magic-resistance.h"
30 #include "mind/mind-numbers.h"
31 #include "pet/pet-util.h"
32 #include "spell-class/spells-mirror-master.h"
33 #include "spell-kind/spells-detection.h"
34 #include "spell-kind/spells-floor.h"
35 #include "spell-kind/spells-launcher.h"
36 #include "spell-kind/spells-lite.h"
37 #include "spell-kind/spells-sight.h"
38 #include "spell-kind/spells-teleport.h"
39 #include "spell-kind/spells-world.h"
40 #include "status/body-improvement.h"
41 #include "status/buff-setter.h"
42 #include "status/sight-setter.h"
43 #include "system/floor-type-definition.h"
44 #include "system/grid-type-definition.h"
45 #include "system/player-type-definition.h"
46 #include "target/grid-selector.h"
47 #include "target/projection-path-calculator.h"
48 #include "target/target-getter.h"
49 #include "timed-effect/player-blindness.h"
50 #include "timed-effect/timed-effects.h"
51 #include "util/bit-flags-calculator.h"
52 #include "view/display-messages.h"
53 #include "world/world.h"
54
55 /*
56  * @brief Multishadow effects is determined by turn
57  */
58 bool check_multishadow(PlayerType *player_ptr)
59 {
60     return (player_ptr->multishadow != 0) && ((w_ptr->game_turn & 1) != 0);
61 }
62
63 /*!
64  * @brief 鏡魔法「封魔結界」の効果処理
65  * @param dam ダメージ量
66  * @return 効果があったらTRUEを返す
67  */
68 bool binding_field(PlayerType *player_ptr, int dam)
69 {
70     POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
71     int mirror_num = 0; /* 鏡の数 */
72
73     /* 三角形の頂点 */
74     POSITION point_x[3];
75     POSITION point_y[3];
76
77     /* Default target of monsterspell is player */
78     monster_target_y = player_ptr->y;
79     monster_target_x = player_ptr->x;
80
81     for (POSITION x = 0; x < player_ptr->current_floor_ptr->width; x++) {
82         for (POSITION y = 0; y < player_ptr->current_floor_ptr->height; y++) {
83             if (player_ptr->current_floor_ptr->grid_array[y][x].is_mirror() && distance(player_ptr->y, player_ptr->x, y, x) <= get_max_range(player_ptr) && distance(player_ptr->y, player_ptr->x, y, x) != 0 && player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
84                 mirror_y[mirror_num] = y;
85                 mirror_x[mirror_num] = x;
86                 mirror_num++;
87             }
88         }
89     }
90
91     if (mirror_num < 2) {
92         return false;
93     }
94
95     point_x[0] = randint0(mirror_num);
96     do {
97         point_x[1] = randint0(mirror_num);
98     } while (point_x[0] == point_x[1]);
99
100     point_y[0] = mirror_y[point_x[0]];
101     point_x[0] = mirror_x[point_x[0]];
102     point_y[1] = mirror_y[point_x[1]];
103     point_x[1] = mirror_x[point_x[1]];
104     point_y[2] = player_ptr->y;
105     point_x[2] = player_ptr->x;
106
107     POSITION x = point_x[0] + point_x[1] + point_x[2];
108     POSITION y = point_y[0] + point_y[1] + point_y[2];
109
110     POSITION centersign = (point_x[0] * 3 - x) * (point_y[1] * 3 - y) - (point_y[0] * 3 - y) * (point_x[1] * 3 - x);
111     if (centersign == 0) {
112         return false;
113     }
114
115     POSITION x1 = point_x[0] < point_x[1] ? point_x[0] : point_x[1];
116     x1 = x1 < point_x[2] ? x1 : point_x[2];
117     POSITION y1 = point_y[0] < point_y[1] ? point_y[0] : point_y[1];
118     y1 = y1 < point_y[2] ? y1 : point_y[2];
119
120     POSITION x2 = point_x[0] > point_x[1] ? point_x[0] : point_x[1];
121     x2 = x2 > point_x[2] ? x2 : point_x[2];
122     POSITION y2 = point_y[0] > point_y[1] ? point_y[0] : point_y[1];
123     y2 = y2 > point_y[2] ? y2 : point_y[2];
124
125     for (y = y1; y <= y2; y++) {
126         for (x = x1; x <= x2; x++) {
127             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
128                 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
129                     if (!(player_ptr->effects()->blindness()->is_blind()) && panel_contains(y, x)) {
130                         print_bolt_pict(player_ptr, y, x, y, x, AttributeType::MANA);
131                         move_cursor_relative(y, x);
132                         term_fresh();
133                         term_xtra(TERM_XTRA_DELAY, delay_factor);
134                     }
135                 }
136             }
137         }
138     }
139
140     for (y = y1; y <= y2; y++) {
141         for (x = x1; x <= x2; x++) {
142             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
143                 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
144                     (void)affect_feature(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
145                 }
146             }
147         }
148     }
149
150     for (y = y1; y <= y2; y++) {
151         for (x = x1; x <= x2; x++) {
152             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
153                 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
154                     (void)affect_item(player_ptr, 0, 0, y, x, dam, AttributeType::MANA);
155                 }
156             }
157         }
158     }
159
160     for (y = y1; y <= y2; y++) {
161         for (x = x1; x <= x2; x++) {
162             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
163                 if (player_has_los_bold(player_ptr, y, x) && projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)) {
164                     (void)affect_monster(player_ptr, 0, 0, y, x, dam, AttributeType::MANA, (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), true);
165                 }
166             }
167         }
168     }
169
170     if (one_in_(7)) {
171         msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
172         SpellsMirrorMaster(player_ptr).remove_mirror(point_y[0], point_x[0]);
173     }
174
175     return true;
176 }
177
178 /*!
179  * 幻惑の光 @ 鏡使いだけでなく混沌の戦士も使える
180  * @param player_ptr プレイヤーへの参照ポインタ
181  * @return 常にTRUE
182  */
183 bool confusing_light(PlayerType *player_ptr)
184 {
185     msg_print(_("辺りを睨んだ...", "You glare at nearby monsters..."));
186     slow_monsters(player_ptr, player_ptr->lev);
187     stun_monsters(player_ptr, player_ptr->lev * 4);
188     confuse_monsters(player_ptr, player_ptr->lev * 4);
189     turn_monsters(player_ptr, player_ptr->lev * 4);
190     stasis_monsters(player_ptr, player_ptr->lev * 4);
191     return true;
192 }
193
194 /*
195  * Set "multishadow", notice observable changes
196  */
197 bool set_multishadow(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
198 {
199     bool notice = false;
200     v = (v > 10000) ? 10000 : (v < 0) ? 0
201                                       : v;
202
203     if (player_ptr->is_dead) {
204         return false;
205     }
206
207     if (v) {
208         if (player_ptr->multishadow && !do_dec) {
209             if (player_ptr->multishadow > v) {
210                 return false;
211             }
212         } else if (!player_ptr->multishadow) {
213             msg_print(_("あなたの周りに幻影が生まれた。", "Your Shadow enveloped you."));
214             notice = true;
215         }
216     } else {
217         if (player_ptr->multishadow) {
218             msg_print(_("幻影が消えた。", "Your Shadow disappears."));
219             notice = true;
220         }
221     }
222
223     player_ptr->multishadow = v;
224     player_ptr->redraw |= (PR_STATUS);
225
226     if (!notice) {
227         return false;
228     }
229
230     if (disturb_state) {
231         disturb(player_ptr, false, false);
232     }
233     player_ptr->update |= (PU_BONUS);
234     handle_stuff(player_ptr);
235     return true;
236 }
237
238 /*!
239  * @brief 一時的破片のオーラの継続時間をセットする / Set "dustrobe", notice observable changes
240  * @param v 継続時間
241  * @param do_dec 現在の継続時間より長い値のみ上書きする
242  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
243  */
244 bool set_dustrobe(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
245 {
246     bool notice = false;
247     v = (v > 10000) ? 10000 : (v < 0) ? 0
248                                       : v;
249
250     if (player_ptr->is_dead) {
251         return false;
252     }
253
254     if (v) {
255         if (player_ptr->dustrobe && !do_dec) {
256             if (player_ptr->dustrobe > v) {
257                 return false;
258             }
259         } else if (!player_ptr->dustrobe) {
260             msg_print(_("体が鏡のオーラで覆われた。", "You are enveloped by mirror shards."));
261             notice = true;
262         }
263     } else {
264         if (player_ptr->dustrobe) {
265             msg_print(_("鏡のオーラが消えた。", "The mirror shards disappear."));
266             notice = true;
267         }
268     }
269
270     player_ptr->dustrobe = v;
271     player_ptr->redraw |= (PR_STATUS);
272
273     if (!notice) {
274         return false;
275     }
276
277     if (disturb_state) {
278         disturb(player_ptr, false, false);
279     }
280     player_ptr->update |= (PU_BONUS);
281     handle_stuff(player_ptr);
282     return true;
283 }
284
285 /*!
286  * @brief 現在フロアに存在している鏡の数を数える / calculate mirrors
287  * @return 鏡の枚数
288  */
289 static int number_of_mirrors(floor_type *floor_ptr)
290 {
291     int val = 0;
292     for (POSITION x = 0; x < floor_ptr->width; x++) {
293         for (POSITION y = 0; y < floor_ptr->height; y++) {
294             if (floor_ptr->grid_array[y][x].is_mirror()) {
295                 val++;
296             }
297         }
298     }
299
300     return val;
301 }
302
303 /*!
304  * @brief 鏡魔法の発動 /
305  * do_cmd_cast calls this function if the player's class is 'Mirror magic'.
306  * @param spell 発動する特殊技能のID
307  * @return 処理を実行したらTRUE、キャンセルした場合FALSEを返す。
308  */
309 bool cast_mirror_spell(PlayerType *player_ptr, MindMirrorMasterType spell)
310 {
311     DIRECTION dir;
312     PLAYER_LEVEL plev = player_ptr->lev;
313     int tmp;
314     TIME_EFFECT t;
315     POSITION x, y;
316     auto *g_ptr = &player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x];
317     switch (spell) {
318     case MindMirrorMasterType::MIRROR_SEEING:
319         tmp = g_ptr->is_mirror() ? 4 : 0;
320         if (plev + tmp > 4) {
321             detect_monsters_normal(player_ptr, DETECT_RAD_DEFAULT);
322         }
323         if (plev + tmp > 18) {
324             detect_monsters_invis(player_ptr, DETECT_RAD_DEFAULT);
325         }
326         if (plev + tmp > 28) {
327             set_tim_esp(player_ptr, (TIME_EFFECT)plev, false);
328         }
329         if (plev + tmp > 38) {
330             map_area(player_ptr, DETECT_RAD_MAP);
331         }
332         if (tmp == 0 && plev < 5) {
333             msg_print(_("鏡がなくて集中できなかった!", "You need a mirror to concentrate!"));
334         }
335         break;
336     case MindMirrorMasterType::MAKE_MIRROR:
337         if (number_of_mirrors(player_ptr->current_floor_ptr) < 4 + plev / 10) {
338             SpellsMirrorMaster(player_ptr).place_mirror();
339         } else {
340             msg_format(_("これ以上鏡は制御できない!", "There are too many mirrors to control!"));
341         }
342
343         break;
344     case MindMirrorMasterType::DRIP_LIGHT:
345         if (!get_aim_dir(player_ptr, &dir)) {
346             return false;
347         }
348
349         if (plev > 9 && g_ptr->is_mirror()) {
350             fire_beam(player_ptr, AttributeType::LITE, dir, damroll(3 + ((plev - 1) / 5), 4));
351         } else {
352             fire_bolt(player_ptr, AttributeType::LITE, dir, damroll(3 + ((plev - 1) / 5), 4));
353         }
354
355         break;
356     case MindMirrorMasterType::WRAPPED_MIRROR:
357         teleport_player(player_ptr, 10, TELEPORT_SPONTANEOUS);
358         break;
359     case MindMirrorMasterType::MIRROR_LIGHT:
360         (void)lite_area(player_ptr, damroll(2, (plev / 2)), (plev / 10) + 1);
361         break;
362     case MindMirrorMasterType::WANDERING_MIRROR:
363         teleport_player(player_ptr, plev * 5, TELEPORT_SPONTANEOUS);
364         break;
365     case MindMirrorMasterType::ROBE_DUST:
366         set_dustrobe(player_ptr, 20 + randint1(20), false);
367         break;
368     case MindMirrorMasterType::BANISHING_MIRROR:
369         if (!get_aim_dir(player_ptr, &dir)) {
370             return false;
371         }
372
373         (void)fire_beam(player_ptr, AttributeType::AWAY_ALL, dir, plev);
374         break;
375     case MindMirrorMasterType::MIRROR_CRASHING:
376         if (!get_aim_dir(player_ptr, &dir)) {
377             return false;
378         }
379
380         fire_ball(player_ptr, AttributeType::SHARDS, dir, damroll(8 + ((plev - 5) / 4), 8), (plev > 20 ? (plev - 20) / 8 + 1 : 0));
381         break;
382     case MindMirrorMasterType::SLEEPING_MIRROR:
383         for (x = 0; x < player_ptr->current_floor_ptr->width; x++) {
384             for (y = 0; y < player_ptr->current_floor_ptr->height; y++) {
385                 if (player_ptr->current_floor_ptr->grid_array[y][x].is_mirror()) {
386                     project(player_ptr, 0, 2, y, x, (int)plev, AttributeType::OLD_SLEEP,
387                         (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI));
388                 }
389             }
390         }
391
392         break;
393     case MindMirrorMasterType::SEEKER_RAY:
394         if (!get_aim_dir(player_ptr, &dir)) {
395             return false;
396         }
397
398         SpellsMirrorMaster(player_ptr).seeker_ray(dir, damroll(11 + (plev - 5) / 4, 8));
399         break;
400     case MindMirrorMasterType::SEALING_MIRROR:
401         SpellsMirrorMaster(player_ptr).seal_of_mirror(plev * 4 + 100);
402         break;
403     case MindMirrorMasterType::WATER_SHIELD:
404         t = 20 + randint1(20);
405         set_shield(player_ptr, t, false);
406         if (plev > 31) {
407             set_tim_reflect(player_ptr, t, false);
408         }
409
410         if (plev > 39) {
411             set_resist_magic(player_ptr, t, false);
412         }
413
414         break;
415     case MindMirrorMasterType::SUPER_RAY:
416         if (!get_aim_dir(player_ptr, &dir)) {
417             return false;
418         }
419
420         SpellsMirrorMaster(player_ptr).super_ray(dir, damroll(11 + (plev - 5) / 4, 8));
421         break;
422     case MindMirrorMasterType::ILLUSION_LIGHT:
423         tmp = g_ptr->is_mirror() ? 4 : 3;
424         slow_monsters(player_ptr, plev);
425         stun_monsters(player_ptr, plev * tmp * 2);
426         confuse_monsters(player_ptr, plev * tmp);
427         turn_monsters(player_ptr, plev * tmp);
428         stasis_monsters(player_ptr, plev * tmp);
429         break;
430     case MindMirrorMasterType::MIRROR_SHIFT:
431         if (!g_ptr->is_mirror()) {
432             msg_print(_("鏡の国の場所がわからない!", "You cannot find out where the mirror is!"));
433             break;
434         }
435
436         reserve_alter_reality(player_ptr, randint0(21) + 15);
437         break;
438     case MindMirrorMasterType::MIRROR_TUNNEL:
439         msg_print(_("鏡の世界を通り抜け…  ", "You try to enter the mirror..."));
440         return SpellsMirrorMaster(player_ptr).mirror_tunnel();
441     case MindMirrorMasterType::RECALL_MIRROR:
442         return recall_player(player_ptr, randint0(21) + 15);
443     case MindMirrorMasterType::MULTI_SHADOW:
444         set_multishadow(player_ptr, 6 + randint1(6), false);
445         break;
446     case MindMirrorMasterType::BINDING_FIELD:
447         if (!binding_field(player_ptr, plev * 11 + 5)) {
448             msg_print(_("適当な鏡を選べなかった!", "You were not able to choose suitable mirrors!"));
449         }
450
451         break;
452     case MindMirrorMasterType::RUFFNOR_MIRROR:
453         (void)set_invuln(player_ptr, randint1(4) + 4, false);
454         break;
455     default:
456         msg_print(_("なに?", "Zap?"));
457         break;
458     }
459
460     return true;
461 }