OSDN Git Service

[Refactor] #40571 Separated grid-selector.c/h from targeting.c/h
[hengband/hengband.git] / src / mind / mind-mirror-master.c
1 #include "mind/mind-mirror-master.h"
2 #include "cmd-action/cmd-pet.h"
3 #include "core/disturbance.h"
4 #include "core/player-redraw-types.h"
5 #include "core/player-update-types.h"
6 #include "core/stuff-handler.h"
7 #include "effect/effect-characteristics.h"
8 #include "effect/effect-feature.h"
9 #include "effect/effect-item.h"
10 #include "effect/effect-monster.h"
11 #include "effect/spells-effect-util.h"
12 #include "floor/cave.h"
13 #include "floor/floor.h"
14 #include "game-option/disturbance-options.h"
15 #include "game-option/special-options.h"
16 #include "grid/feature.h"
17 #include "io/cursor.h"
18 #include "io/screen-util.h"
19 #include "spell-kind/spells-sight.h"
20 #include "spell-kind/spells-teleport.h"
21 #include "spell/process-effect.h"
22 #include "spell/spell-types.h"
23 #include "system/floor-type-definition.h"
24 #include "target/grid-selector.h"
25 #include "target/target-preparation.h"
26 #include "term/gameterm.h"
27 #include "util/bit-flags-calculator.h"
28 #include "view/display-messages.h"
29 #include "world/world.h"
30
31 /*
32  * @brief Multishadow effects is determined by turn
33  */
34 bool check_multishadow(player_type *creature_ptr) { return (creature_ptr->multishadow != 0) && ((current_world_ptr->game_turn & 1) != 0); }
35
36 /*!
37  * 静水
38  * @param creature_ptr プレーヤーへの参照ポインタ
39  * @return ペットを操っている場合を除きTRUE
40  */
41 bool mirror_concentration(player_type *creature_ptr)
42 {
43     if (total_friends) {
44         msg_print(_("今はペットを操ることに集中していないと。", "Your pets demand all of your attention."));
45         return FALSE;
46     }
47
48     if (!is_mirror_grid(&creature_ptr->current_floor_ptr->grid_array[creature_ptr->y][creature_ptr->x])) {
49         msg_print(_("鏡の上でないと集中できない!", "There's no mirror here!"));
50         return TRUE;
51     }
52
53     msg_print(_("少し頭がハッキリした。", "You feel your head clear a little."));
54
55     creature_ptr->csp += (5 + creature_ptr->lev * creature_ptr->lev / 100);
56     if (creature_ptr->csp >= creature_ptr->msp) {
57         creature_ptr->csp = creature_ptr->msp;
58         creature_ptr->csp_frac = 0;
59     }
60
61     creature_ptr->redraw |= PR_MANA;
62     return TRUE;
63 }
64
65 /*!
66  * @brief 全鏡の消去 / Remove all mirrors in this floor
67  * @param caster_ptr プレーヤーへの参照ポインタ
68  * @param explode 爆発処理を伴うならばTRUE
69  * @return なし
70  */
71 void remove_all_mirrors(player_type *caster_ptr, bool explode)
72 {
73     for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++) {
74         for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++) {
75             if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
76                 continue;
77
78             remove_mirror(caster_ptr, y, x);
79             if (!explode)
80                 continue;
81
82             project(caster_ptr, 0, 2, y, x, caster_ptr->lev / 2 + 5, GF_SHARDS,
83                 (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP | PROJECT_NO_HANGEKI), -1);
84         }
85     }
86 }
87
88 /*!
89  * @brief 鏡魔法「封魔結界」の効果処理
90  * @param dam ダメージ量
91  * @return 効果があったらTRUEを返す
92  */
93 bool binding_field(player_type *caster_ptr, HIT_POINT dam)
94 {
95     POSITION mirror_x[10], mirror_y[10]; /* 鏡はもっと少ない */
96     int mirror_num = 0; /* 鏡の数 */
97     int msec = delay_factor * delay_factor * delay_factor;
98
99     /* 三角形の頂点 */
100     POSITION point_x[3];
101     POSITION point_y[3];
102
103     /* Default target of monsterspell is player */
104     monster_target_y = caster_ptr->y;
105     monster_target_x = caster_ptr->x;
106
107     for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++) {
108         for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++) {
109             if (is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]) && distance(caster_ptr->y, caster_ptr->x, y, x) <= get_max_range(caster_ptr)
110                 && distance(caster_ptr->y, caster_ptr->x, y, x) != 0 && player_has_los_bold(caster_ptr, y, x)
111                 && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)) {
112                 mirror_y[mirror_num] = y;
113                 mirror_x[mirror_num] = x;
114                 mirror_num++;
115             }
116         }
117     }
118
119     if (mirror_num < 2)
120         return FALSE;
121
122     point_x[0] = randint0(mirror_num);
123     do {
124         point_x[1] = randint0(mirror_num);
125     } while (point_x[0] == point_x[1]);
126
127     point_y[0] = mirror_y[point_x[0]];
128     point_x[0] = mirror_x[point_x[0]];
129     point_y[1] = mirror_y[point_x[1]];
130     point_x[1] = mirror_x[point_x[1]];
131     point_y[2] = caster_ptr->y;
132     point_x[2] = caster_ptr->x;
133
134     POSITION x = point_x[0] + point_x[1] + point_x[2];
135     POSITION y = point_y[0] + point_y[1] + point_y[2];
136
137     POSITION centersign = (point_x[0] * 3 - x) * (point_y[1] * 3 - y) - (point_y[0] * 3 - y) * (point_x[1] * 3 - x);
138     if (centersign == 0)
139         return FALSE;
140
141     POSITION x1 = point_x[0] < point_x[1] ? point_x[0] : point_x[1];
142     x1 = x1 < point_x[2] ? x1 : point_x[2];
143     POSITION y1 = point_y[0] < point_y[1] ? point_y[0] : point_y[1];
144     y1 = y1 < point_y[2] ? y1 : point_y[2];
145
146     POSITION x2 = point_x[0] > point_x[1] ? point_x[0] : point_x[1];
147     x2 = x2 > point_x[2] ? x2 : point_x[2];
148     POSITION y2 = point_y[0] > point_y[1] ? point_y[0] : point_y[1];
149     y2 = y2 > point_y[2] ? y2 : point_y[2];
150
151     for (y = y1; y <= y2; y++) {
152         for (x = x1; x <= x2; x++) {
153             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0
154                 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0
155                 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
156                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)) {
157                     if (!(caster_ptr->blind) && panel_contains(y, x)) {
158                         u16b p = bolt_pict(y, x, y, x, GF_MANA);
159                         print_rel(caster_ptr, PICT_C(p), PICT_A(p), y, x);
160                         move_cursor_relative(y, x);
161                         term_fresh();
162                         term_xtra(TERM_XTRA_DELAY, msec);
163                     }
164                 }
165             }
166         }
167     }
168
169     for (y = y1; y <= y2; y++) {
170         for (x = x1; x <= x2; x++) {
171             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0
172                 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0
173                 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
174                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)) {
175                     (void)affect_feature(caster_ptr, 0, 0, y, x, dam, GF_MANA);
176                 }
177             }
178         }
179     }
180
181     for (y = y1; y <= y2; y++) {
182         for (x = x1; x <= x2; x++) {
183             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0
184                 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0
185                 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
186                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)) {
187                     (void)affect_item(caster_ptr, 0, 0, y, x, dam, GF_MANA);
188                 }
189             }
190         }
191     }
192
193     for (y = y1; y <= y2; y++) {
194         for (x = x1; x <= x2; x++) {
195             if (centersign * ((point_x[0] - x) * (point_y[1] - y) - (point_y[0] - y) * (point_x[1] - x)) >= 0
196                 && centersign * ((point_x[1] - x) * (point_y[2] - y) - (point_y[1] - y) * (point_x[2] - x)) >= 0
197                 && centersign * ((point_x[2] - x) * (point_y[0] - y) - (point_y[2] - y) * (point_x[0] - x)) >= 0) {
198                 if (player_has_los_bold(caster_ptr, y, x) && projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)) {
199                     (void)affect_monster(caster_ptr, 0, 0, y, x, dam, GF_MANA, (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE);
200                 }
201             }
202         }
203     }
204
205     if (one_in_(7)) {
206         msg_print(_("鏡が結界に耐えきれず、壊れてしまった。", "The field broke a mirror"));
207         remove_mirror(caster_ptr, point_y[0], point_x[0]);
208     }
209
210     return TRUE;
211 }
212
213 /*!
214  * @brief 鏡魔法「鏡の封印」の効果処理
215  * @param dam ダメージ量
216  * @return 効果があったらTRUEを返す
217  */
218 void seal_of_mirror(player_type *caster_ptr, HIT_POINT dam)
219 {
220     for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++) {
221         for (POSITION y = 0; y < caster_ptr->current_floor_ptr->height; y++) {
222             if (!is_mirror_grid(&caster_ptr->current_floor_ptr->grid_array[y][x]))
223                 continue;
224
225             if (!affect_monster(caster_ptr, 0, 0, y, x, dam, GF_GENOCIDE, (PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL | PROJECT_JUMP), TRUE))
226                 continue;
227
228             if (!caster_ptr->current_floor_ptr->grid_array[y][x].m_idx) {
229                 remove_mirror(caster_ptr, y, x);
230             }
231         }
232     }
233 }
234
235 /*!
236  * 幻惑の光 @ 鏡使いだけでなく混沌の戦士も使える
237  * @param creature_ptr プレーヤーへの参照ポインタ
238  * @return 常にTRUE
239  */
240 bool confusing_light(player_type *creature_ptr)
241 {
242     msg_print(_("辺りを睨んだ...", "You glare nearby monsters..."));
243     slow_monsters(creature_ptr, creature_ptr->lev);
244     stun_monsters(creature_ptr, creature_ptr->lev * 4);
245     confuse_monsters(creature_ptr, creature_ptr->lev * 4);
246     turn_monsters(creature_ptr, creature_ptr->lev * 4);
247     stasis_monsters(creature_ptr, creature_ptr->lev * 4);
248     return TRUE;
249 }
250
251 /*!
252  * @brief 鏡設置処理
253  * @return 実際に設置が行われた場合TRUEを返す
254  */
255 bool place_mirror(player_type *caster_ptr)
256 {
257     if (!cave_clean_bold(caster_ptr->current_floor_ptr, caster_ptr->y, caster_ptr->x)) {
258         msg_print(_("床上のアイテムが呪文を跳ね返した。", "The object resists the spell."));
259         return FALSE;
260     }
261
262     /* Create a mirror */
263     caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info |= CAVE_OBJECT;
264     caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].mimic = feat_mirror;
265
266     /* Turn on the light */
267     caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info |= CAVE_GLOW;
268
269     note_spot(caster_ptr, caster_ptr->y, caster_ptr->x);
270     lite_spot(caster_ptr, caster_ptr->y, caster_ptr->x);
271     update_local_illumination(caster_ptr, caster_ptr->y, caster_ptr->x);
272
273     return TRUE;
274 }
275
276 /*!
277  * @brief 鏡抜け処理のメインルーチン /
278  * Mirror Master's Dimension Door
279  * @param caster_ptr プレーヤーへの参照ポインタ
280  * @return ターンを消費した場合TRUEを返す
281  */
282 bool mirror_tunnel(player_type *caster_ptr)
283 {
284     POSITION x = 0, y = 0;
285     if (!tgt_pt(caster_ptr, &x, &y))
286         return FALSE;
287     if (exe_dimension_door(caster_ptr, x, y))
288         return TRUE;
289
290     msg_print(_("鏡の世界をうまく通れなかった!", "You fail to pass the mirror plane correctly!"));
291     return TRUE;
292 }
293
294 /*
295  * Set "multishadow", notice observable changes
296  */
297 bool set_multishadow(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
298 {
299     bool notice = FALSE;
300     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
301
302     if (creature_ptr->is_dead)
303         return FALSE;
304
305     if (v) {
306         if (creature_ptr->multishadow && !do_dec) {
307             if (creature_ptr->multishadow > v)
308                 return FALSE;
309         } else if (!creature_ptr->multishadow) {
310             msg_print(_("あなたの周りに幻影が生まれた。", "Your Shadow enveloped you."));
311             notice = TRUE;
312         }
313     } else {
314         if (creature_ptr->multishadow) {
315             msg_print(_("幻影が消えた。", "Your Shadow disappears."));
316             notice = TRUE;
317         }
318     }
319
320     creature_ptr->multishadow = v;
321     creature_ptr->redraw |= (PR_STATUS);
322
323     if (!notice)
324         return FALSE;
325
326     if (disturb_state)
327         disturb(creature_ptr, FALSE, FALSE);
328     creature_ptr->update |= (PU_BONUS);
329     handle_stuff(creature_ptr);
330     return TRUE;
331 }
332
333 /*!
334  * @brief 一時的破片のオーラの継続時間をセットする / Set "dustrobe", notice observable changes
335  * @param v 継続時間
336  * @param do_dec 現在の継続時間より長い値のみ上書きする
337  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
338  */
339 bool set_dustrobe(player_type *creature_ptr, TIME_EFFECT v, bool do_dec)
340 {
341     bool notice = FALSE;
342     v = (v > 10000) ? 10000 : (v < 0) ? 0 : v;
343
344     if (creature_ptr->is_dead)
345         return FALSE;
346
347     if (v) {
348         if (creature_ptr->dustrobe && !do_dec) {
349             if (creature_ptr->dustrobe > v)
350                 return FALSE;
351         } else if (!creature_ptr->dustrobe) {
352             msg_print(_("体が鏡のオーラで覆われた。", "You were enveloped by mirror shards."));
353             notice = TRUE;
354         }
355     } else {
356         if (creature_ptr->dustrobe) {
357             msg_print(_("鏡のオーラが消えた。", "The mirror shards disappear."));
358             notice = TRUE;
359         }
360     }
361
362     creature_ptr->dustrobe = v;
363     creature_ptr->redraw |= (PR_STATUS);
364
365     if (!notice)
366         return FALSE;
367
368     if (disturb_state)
369         disturb(creature_ptr, FALSE, FALSE);
370     creature_ptr->update |= (PU_BONUS);
371     handle_stuff(creature_ptr);
372     return TRUE;
373 }