OSDN Git Service

[Refactor] #40571 Moved targeting.c/h from io/ to target/
[hengband/hengband.git] / src / spell-kind / spells-lite.c
1 #include "spell-kind/spells-lite.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "effect/effect-characteristics.h"
5 #include "floor/cave.h"
6 #include "floor/floor.h"
7 #include "game-option/map-screen-options.h"
8 #include "grid/grid.h"
9 #include "mind/mind-ninja.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-flags2.h"
12 #include "monster/monster-describer.h"
13 #include "monster/monster-status.h"
14 #include "monster/monster-update.h"
15 #include "player/special-defense-types.h"
16 #include "spell-kind/spells-launcher.h"
17 #include "spell/process-effect.h"
18 #include "spell/spell-types.h"
19 #include "system/floor-type-definition.h"
20 #include "target/targeting.h"
21 #include "util/bit-flags-calculator.h"
22 #include "view/display-messages.h"
23 #include "world/world.h"
24
25 /*!
26  * todo この辺、xとyが引数になっているが、caster_ptr->xとcaster_ptr->yで全て置き換えが効くはず……
27  * @brief 部屋全体を照らすサブルーチン
28  * @param caster_ptr プレーヤーへの参照ポインタ
29  * @return なし
30  * @details
31  * <pre>
32  * This routine clears the entire "temp" set.
33  * This routine will Perma-Lite all "temp" grids.
34  * This routine is used (only) by "lite_room()"
35  * Dark grids are illuminated.
36  * Also, process all affected monsters.
37  *
38  * SMART monsters always wake up when illuminated
39  * NORMAL monsters wake up 1/4 the time when illuminated
40  * STUPID monsters wake up 1/10 the time when illuminated
41  * </pre>
42  */
43 static void cave_temp_room_lite(player_type *caster_ptr)
44 {
45     for (int i = 0; i < tmp_pos.n; i++) {
46         POSITION y = tmp_pos.y[i];
47         POSITION x = tmp_pos.x[i];
48         grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
49         g_ptr->info &= ~(CAVE_TEMP);
50         g_ptr->info |= (CAVE_GLOW);
51         if (g_ptr->m_idx) {
52             PERCENTAGE chance = 25;
53             monster_type *m_ptr = &caster_ptr->current_floor_ptr->m_list[g_ptr->m_idx];
54             monster_race *r_ptr = &r_info[m_ptr->r_idx];
55             update_monster(caster_ptr, g_ptr->m_idx, FALSE);
56             if (r_ptr->flags2 & (RF2_STUPID))
57                 chance = 10;
58             if (r_ptr->flags2 & (RF2_SMART))
59                 chance = 100;
60
61             if (monster_csleep_remaining(m_ptr) && (randint0(100) < chance)) {
62                 (void)set_monster_csleep(caster_ptr, g_ptr->m_idx, 0);
63                 if (m_ptr->ml) {
64                     GAME_TEXT m_name[MAX_NLEN];
65                     monster_desc(caster_ptr, m_name, m_ptr, 0);
66                     msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name);
67                 }
68             }
69         }
70
71         note_spot(caster_ptr, y, x);
72         lite_spot(caster_ptr, y, x);
73         update_local_illumination(caster_ptr, y, x);
74     }
75
76     tmp_pos.n = 0;
77 }
78
79 /*!
80  * todo この辺、xとyが引数になっているが、caster_ptr->xとcaster_ptr->yで全て置き換えが効くはず……
81  * @brief 部屋全体を暗くするサブルーチン
82  * @param caster_ptr プレーヤーへの参照ポインタ
83  * @return なし
84  * @details
85  * <pre>
86  * This routine clears the entire "temp" set.
87  * This routine will "darken" all "temp" grids.
88  * In addition, some of these grids will be "unmarked".
89  * This routine is used (only) by "unlite_room()"
90  * Also, process all affected monsters
91  * </pre>
92  */
93 static void cave_temp_room_unlite(player_type *caster_ptr)
94 {
95     for (int i = 0; i < tmp_pos.n; i++) {
96         POSITION y = tmp_pos.y[i];
97         POSITION x = tmp_pos.x[i];
98         grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
99         bool do_dark = !is_mirror_grid(g_ptr);
100         g_ptr->info &= ~(CAVE_TEMP);
101         if (!do_dark)
102             continue;
103
104         if (caster_ptr->current_floor_ptr->dun_level || !is_daytime()) {
105             for (int j = 0; j < 9; j++) {
106                 POSITION by = y + ddy_ddd[j];
107                 POSITION bx = x + ddx_ddd[j];
108
109                 if (in_bounds2(caster_ptr->current_floor_ptr, by, bx)) {
110                     grid_type *cc_ptr = &caster_ptr->current_floor_ptr->grid_array[by][bx];
111
112                     if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW)) {
113                         do_dark = FALSE;
114                         break;
115                     }
116                 }
117             }
118
119             if (!do_dark)
120                 continue;
121         }
122
123         g_ptr->info &= ~(CAVE_GLOW);
124         if (!have_flag(f_info[get_feat_mimic(g_ptr)].flags, FF_REMEMBER)) {
125             if (!view_torch_grids)
126                 g_ptr->info &= ~(CAVE_MARK);
127             note_spot(caster_ptr, y, x);
128         }
129
130         if (g_ptr->m_idx) {
131             update_monster(caster_ptr, g_ptr->m_idx, FALSE);
132         }
133
134         lite_spot(caster_ptr, y, x);
135         update_local_illumination(caster_ptr, y, x);
136     }
137
138     tmp_pos.n = 0;
139 }
140
141 /*!
142  * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to
143  * @param floor_ptr 配置するフロアの参照ポインタ
144  * @param cy Y座標
145  * @param cx X座標
146  * @param pass_bold 地形条件を返す関数ポインタ
147  * @return 該当地形の数
148  */
149 static int next_to_open(floor_type *floor_ptr, POSITION cy, POSITION cx, bool (*pass_bold)(floor_type *, POSITION, POSITION))
150 {
151     int len = 0;
152     int blen = 0;
153     for (int i = 0; i < 16; i++) {
154         POSITION y = cy + ddy_cdd[i % 8];
155         POSITION x = cx + ddx_cdd[i % 8];
156         if (!pass_bold(floor_ptr, y, x)) {
157             if (len > blen) {
158                 blen = len;
159             }
160
161             len = 0;
162         } else {
163             len++;
164         }
165     }
166
167     return MAX(len, blen);
168 }
169
170 /*!
171  * @brief 周辺に関数ポインタの条件に該当する地形がいくつあるかを計算する / Determine how much contiguous open space this grid is next to
172  * @param floor_ptr 配置するフロアの参照ポインタ
173  * @param cy Y座標
174  * @param cx X座標
175  * @param pass_bold 地形条件を返す関数ポインタ
176  * @return 該当地形の数
177  */
178 static int next_to_walls_adj(floor_type *floor_ptr, POSITION cy, POSITION cx, bool (*pass_bold)(floor_type *, POSITION, POSITION))
179 {
180     POSITION y, x;
181     int c = 0;
182     for (DIRECTION i = 0; i < 8; i++) {
183         y = cy + ddy_ddd[i];
184         x = cx + ddx_ddd[i];
185
186         if (!pass_bold(floor_ptr, y, x))
187             c++;
188     }
189
190     return c;
191 }
192
193 /*!
194  * @brief 部屋内にある一点の周囲に該当する地形数かいくつあるかをグローバル変数tmp_pos.nに返す / Aux function -- see below
195  * @param caster_ptr プレーヤーへの参照ポインタ
196  * @param y 部屋内のy座標1点
197  * @param x 部屋内のx座標1点
198  * @param only_room 部屋内地形のみをチェック対象にするならば TRUE
199  * @param pass_bold 地形条件を返す関数ポインタ
200  * @return 該当地形の数
201  */
202 static void cave_temp_room_aux(player_type *caster_ptr, POSITION y, POSITION x, bool only_room, bool (*pass_bold)(floor_type *, POSITION, POSITION))
203 {
204     grid_type *g_ptr;
205     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
206     g_ptr = &floor_ptr->grid_array[y][x];
207     if (g_ptr->info & (CAVE_TEMP))
208         return;
209
210     if (!(g_ptr->info & (CAVE_ROOM))) {
211         if (only_room)
212             return;
213         if (!in_bounds2(floor_ptr, y, x))
214             return;
215         if (distance(caster_ptr->y, caster_ptr->x, y, x) > get_max_range(caster_ptr))
216             return;
217
218         /* Verify this grid */
219         /*
220          * The reason why it is ==6 instead of >5 is that 8 is impossible
221          * due to the check for cave_bold above.
222          * 7 lights dead-end corridors (you need to do this for the
223          * checkboard interesting rooms, so that the boundary is lit
224          * properly.
225          * This leaves only a check for 6 bounding walls!
226          */
227         if (in_bounds(floor_ptr, y, x) && pass_bold(floor_ptr, y, x) && (next_to_walls_adj(floor_ptr, y, x, pass_bold) == 6)
228             && (next_to_open(floor_ptr, y, x, pass_bold) <= 1))
229             return;
230     }
231
232     if (tmp_pos.n == TEMP_MAX)
233         return;
234
235     g_ptr->info |= (CAVE_TEMP);
236     tmp_pos.y[tmp_pos.n] = y;
237     tmp_pos.x[tmp_pos.n] = x;
238     tmp_pos.n++;
239 }
240
241 /*!
242  * @brief 部屋内にある一点の周囲がいくつ光を通すかをグローバル変数tmp_pos.nに返す / Aux function -- see below
243  * @param caster_ptr プレーヤーへの参照ポインタ
244  * @param y 指定Y座標
245  * @param x 指定X座標
246  * @return なし
247  */
248 static void cave_temp_lite_room_aux(player_type *caster_ptr, POSITION y, POSITION x) { cave_temp_room_aux(caster_ptr, y, x, FALSE, cave_los_bold); }
249
250 /*!
251  * @brief 指定のマスが光を通さず射線のみを通すかを返す。 / Aux function -- see below
252  * @param floor_ptr 配置するフロアの参照ポインタ
253  * @param y 指定Y座標
254  * @param x 指定X座標
255  * @return 射線を通すならばtrueを返す。
256  */
257 static bool cave_pass_dark_bold(floor_type *floor_ptr, POSITION y, POSITION x) { return cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT); }
258
259 /*!
260  * @brief 部屋内にある一点の周囲がいくつ射線を通すかをグローバル変数tmp_pos.nに返す / Aux function -- see below
261  * @param caster_ptr プレーヤーへの参照ポインタ
262  * @param y 指定Y座標
263  * @param x 指定X座標
264  * @return なし
265  */
266 static void cave_temp_unlite_room_aux(player_type *caster_ptr, POSITION y, POSITION x) { cave_temp_room_aux(caster_ptr, y, x, TRUE, cave_pass_dark_bold); }
267
268 /*!
269  * @brief 指定された部屋内を照らす / Illuminate any room containing the given location.
270  * @param caster_ptr プレーヤーへの参照ポインタ
271  * @param y1 指定Y座標
272  * @param x1 指定X座標
273  * @return なし
274  */
275 void lite_room(player_type *caster_ptr, POSITION y1, POSITION x1)
276 {
277     cave_temp_lite_room_aux(caster_ptr, y1, x1);
278     floor_type *floor_ptr = caster_ptr->current_floor_ptr;
279     for (int i = 0; i < tmp_pos.n; i++) {
280         POSITION x = tmp_pos.x[i];
281         POSITION y = tmp_pos.y[i];
282
283         if (!cave_los_bold(floor_ptr, y, x))
284             continue;
285
286         cave_temp_lite_room_aux(caster_ptr, y + 1, x);
287         cave_temp_lite_room_aux(caster_ptr, y - 1, x);
288         cave_temp_lite_room_aux(caster_ptr, y, x + 1);
289         cave_temp_lite_room_aux(caster_ptr, y, x - 1);
290
291         cave_temp_lite_room_aux(caster_ptr, y + 1, x + 1);
292         cave_temp_lite_room_aux(caster_ptr, y - 1, x - 1);
293         cave_temp_lite_room_aux(caster_ptr, y - 1, x + 1);
294         cave_temp_lite_room_aux(caster_ptr, y + 1, x - 1);
295     }
296
297     cave_temp_room_lite(caster_ptr);
298     if (caster_ptr->special_defense & NINJA_S_STEALTH) {
299         if (floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW)
300             set_superstealth(caster_ptr, FALSE);
301     }
302 }
303
304 /*!
305  * @brief 指定された部屋内を暗くする / Darken all rooms containing the given location
306  * @param caster_ptr プレーヤーへの参照ポインタ
307  * @param y1 指定Y座標
308  * @param x1 指定X座標
309  * @return なし
310  */
311 void unlite_room(player_type *caster_ptr, POSITION y1, POSITION x1)
312 {
313     cave_temp_unlite_room_aux(caster_ptr, y1, x1);
314     for (int i = 0; i < tmp_pos.n; i++) {
315         POSITION x = tmp_pos.x[i];
316         POSITION y = tmp_pos.y[i];
317         if (!cave_pass_dark_bold(caster_ptr->current_floor_ptr, y, x))
318             continue;
319
320         cave_temp_unlite_room_aux(caster_ptr, y + 1, x);
321         cave_temp_unlite_room_aux(caster_ptr, y - 1, x);
322         cave_temp_unlite_room_aux(caster_ptr, y, x + 1);
323         cave_temp_unlite_room_aux(caster_ptr, y, x - 1);
324
325         cave_temp_unlite_room_aux(caster_ptr, y + 1, x + 1);
326         cave_temp_unlite_room_aux(caster_ptr, y - 1, x - 1);
327         cave_temp_unlite_room_aux(caster_ptr, y - 1, x + 1);
328         cave_temp_unlite_room_aux(caster_ptr, y + 1, x - 1);
329     }
330
331     cave_temp_room_unlite(caster_ptr);
332 }
333
334 /*!
335  * @brief スターライトの効果を発生させる
336  * @param caster_ptr プレーヤーへの参照ポインタ
337  * @param magic 魔法による効果であればTRUE、スターライトの杖による効果であればFALSE
338  * @return 常にTRUE
339  */
340 bool starlight(player_type *caster_ptr, bool magic)
341 {
342     if (!caster_ptr->blind && !magic) {
343         msg_print(_("杖の先が明るく輝いた...", "The end of the staff glows brightly..."));
344     }
345
346     HIT_POINT num = damroll(5, 3);
347     int attempts;
348     POSITION y = 0, x = 0;
349     for (int k = 0; k < num; k++) {
350         attempts = 1000;
351
352         while (attempts--) {
353             scatter(caster_ptr, &y, &x, caster_ptr->y, caster_ptr->x, 4, PROJECT_LOS);
354             if (!cave_have_flag_bold(caster_ptr->current_floor_ptr, y, x, FF_PROJECT))
355                 continue;
356             if (!player_bold(caster_ptr, y, x))
357                 break;
358         }
359
360         project(caster_ptr, 0, 0, y, x, damroll(6 + caster_ptr->lev / 8, 10), GF_LITE_WEAK,
361             (PROJECT_BEAM | PROJECT_THRU | PROJECT_GRID | PROJECT_KILL | PROJECT_LOS), -1);
362     }
363
364     return TRUE;
365 }
366
367 /*!
368  * @brief プレイヤー位置を中心にLITE_WEAK属性を通じた照明処理を行う / Hack -- call light around the player Affect all monsters in the projection radius
369  * @param caster_ptr プレーヤーへの参照ポインタ
370  * @param dam 威力
371  * @param rad 効果半径
372  * @return 作用が実際にあった場合TRUEを返す
373  */
374 bool lite_area(player_type *caster_ptr, HIT_POINT dam, POSITION rad)
375 {
376     if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS) {
377         msg_print(_("ダンジョンが光を吸収した。", "The darkness of this dungeon absorbs your light."));
378         return FALSE;
379     }
380
381     if (!caster_ptr->blind) {
382         msg_print(_("白い光が辺りを覆った。", "You are surrounded by a white light."));
383     }
384
385     BIT_FLAGS flg = PROJECT_GRID | PROJECT_KILL;
386     (void)project(caster_ptr, 0, rad, caster_ptr->y, caster_ptr->x, dam, GF_LITE_WEAK, flg, -1);
387
388     lite_room(caster_ptr, caster_ptr->y, caster_ptr->x);
389
390     return TRUE;
391 }
392
393 /*!
394  * @brief プレイヤー位置を中心にLITE_DARK属性を通じた消灯処理を行う / Hack -- call light around the player Affect all monsters in the projection radius
395  * @param caster_ptr プレーヤーへの参照ポインタ
396  * @param dam 威力
397  * @param rad 効果半径
398  * @return 作用が実際にあった場合TRUEを返す
399  */
400 bool unlite_area(player_type *caster_ptr, HIT_POINT dam, POSITION rad)
401 {
402     if (!caster_ptr->blind) {
403         msg_print(_("暗闇が辺りを覆った。", "Darkness surrounds you."));
404     }
405
406     BIT_FLAGS flg = PROJECT_GRID | PROJECT_KILL;
407     (void)project(caster_ptr, 0, rad, caster_ptr->y, caster_ptr->x, dam, GF_DARK_WEAK, flg, -1);
408
409     unlite_room(caster_ptr, caster_ptr->y, caster_ptr->x);
410
411     return TRUE;
412 }
413
414 /*!
415  * @brief LITE_WEAK属性による光源ビーム処理
416  * @param caster_ptr プレーヤーへの参照ポインタ
417  * @param dir 方向(5ならばグローバル変数 target_col/target_row の座標を目標にする)
418  * @param dam 威力
419  * @return 作用が実際にあった場合TRUEを返す
420  */
421 bool lite_line(player_type *caster_ptr, DIRECTION dir, HIT_POINT dam)
422 {
423     BIT_FLAGS flg = PROJECT_BEAM | PROJECT_GRID | PROJECT_KILL;
424     return (project_hook(caster_ptr, GF_LITE_WEAK, dir, dam, flg));
425 }