OSDN Git Service

[Refactor] #40014 Separated monster-describer.c/h from monster2.c/h
[hengband/hengband.git] / src / spell-kind / spells-floor.c
1 /*!
2  * @brief フロアに影響のある魔法の処理
3  * @date 2019/02/21
4  * @author deskull
5  */
6
7 #include "spell-kind/spells-floor.h"
8 #include "cmd-io/cmd-dump.h"
9 #include "cmd/cmd-basic.h"
10 #include "dungeon/dungeon.h"
11 #include "dungeon/quest.h"
12 #include "effect/effect-characteristics.h"
13 #include "floor/floor-events.h"
14 #include "floor/floor-object.h"
15 #include "floor/floor-save.h"
16 #include "floor/floor.h"
17 #include "grid/feature.h"
18 #include "grid/grid.h"
19 #include "io/write-diary.h"
20 #include "monster-race/race-flags1.h"
21 #include "monster/monster-describer.h"
22 #include "monster/monster-description-types.h"
23 #include "monster/monster-status.h"
24 #include "monster/monster2.h"
25 #include "monster/smart-learn-types.h"
26 #include "object-enchant/artifact.h"
27 #include "object-enchant/special-object-flags.h"
28 #include "object/object-flavor.h"
29 #include "object/object-hook.h"
30 #include "object/object-mark-types.h"
31 #include "perception/object-perception.h"
32 #include "player/player-effects.h"
33 #include "spell-kind/spells-teleport.h"
34 #include "spell/process-effect.h"
35 #include "spell/spells-type.h"
36 #include "util/util.h"
37 #include "view/display-main-window.h"
38
39 /*
40  * @brief 啓蒙/陽光召喚処理
41  * @param caster_ptr プレーヤーへの参照ポインタ
42  * @param ninja 忍者かどうか
43  * @return なし
44  */
45 void wiz_lite(player_type *caster_ptr, bool ninja)
46 {
47         /* Memorize objects */
48         for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++)
49         {
50                 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
51                 if (!OBJECT_IS_VALID(o_ptr)) continue;
52                 if (OBJECT_IS_HELD_MONSTER(o_ptr)) continue;
53                 o_ptr->marked |= OM_FOUND;
54         }
55
56         /* Scan all normal grids */
57         for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++)
58         {
59                 /* Scan all normal grids */
60                 for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++)
61                 {
62                         grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
63
64                         /* Memorize terrain of the grid */
65                         g_ptr->info |= (CAVE_KNOWN);
66
67                         /* Feature code (applying "mimic" field) */
68                         FEAT_IDX feat = get_feat_mimic(g_ptr);
69                         feature_type *f_ptr;
70                         f_ptr = &f_info[feat];
71
72                         /* Process all non-walls */
73                         if (have_flag(f_ptr->flags, FF_WALL)) continue;
74
75                         /* Scan all neighbors */
76                         for (OBJECT_IDX i = 0; i < 9; i++)
77                         {
78                                 POSITION yy = y + ddy_ddd[i];
79                                 POSITION xx = x + ddx_ddd[i];
80                                 g_ptr = &caster_ptr->current_floor_ptr->grid_array[yy][xx];
81
82                                 /* Feature code (applying "mimic" field) */
83                                 f_ptr = &f_info[get_feat_mimic(g_ptr)];
84
85                                 /* Perma-lite the grid */
86                                 if (!(d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS) && !ninja)
87                                 {
88                                         g_ptr->info |= (CAVE_GLOW);
89                                 }
90
91                                 /* Memorize normal features */
92                                 if (have_flag(f_ptr->flags, FF_REMEMBER))
93                                 {
94                                         /* Memorize the grid */
95                                         g_ptr->info |= (CAVE_MARK);
96                                 }
97
98                                 /* Perma-lit grids (newly and previously) */
99                                 else if (g_ptr->info & CAVE_GLOW)
100                                 {
101                                         /* Normally, memorize floors (see above) */
102                                         if (view_perma_grids && !view_torch_grids)
103                                         {
104                                                 /* Memorize the grid */
105                                                 g_ptr->info |= (CAVE_MARK);
106                                         }
107                                 }
108                         }
109                 }
110         }
111
112         caster_ptr->update |= (PU_MONSTERS);
113         caster_ptr->redraw |= (PR_MAP);
114         caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
115
116         if (caster_ptr->special_defense & NINJA_S_STEALTH)
117         {
118                 if (caster_ptr->current_floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW) set_superstealth(caster_ptr, FALSE);
119         }
120 }
121
122
123 /*
124  * Forget the dungeon map (ala "Thinking of Maud...").
125  */
126 void wiz_dark(player_type *caster_ptr)
127 {
128         /* Forget every grid */
129         for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++)
130         {
131                 for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++)
132                 {
133                         grid_type *g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
134
135                         /* Process the grid */
136                         g_ptr->info &= ~(CAVE_MARK | CAVE_IN_DETECT | CAVE_KNOWN);
137                         g_ptr->info |= (CAVE_UNSAFE);
138                 }
139         }
140
141         /* Forget every grid on horizontal edge */
142         for (POSITION x = 0; x < caster_ptr->current_floor_ptr->width; x++)
143         {
144                 caster_ptr->current_floor_ptr->grid_array[0][x].info &= ~(CAVE_MARK);
145                 caster_ptr->current_floor_ptr->grid_array[caster_ptr->current_floor_ptr->height - 1][x].info &= ~(CAVE_MARK);
146         }
147
148         /* Forget every grid on vertical edge */
149         for (POSITION y = 1; y < (caster_ptr->current_floor_ptr->height - 1); y++)
150         {
151                 caster_ptr->current_floor_ptr->grid_array[y][0].info &= ~(CAVE_MARK);
152                 caster_ptr->current_floor_ptr->grid_array[y][caster_ptr->current_floor_ptr->width - 1].info &= ~(CAVE_MARK);
153         }
154
155         /* Forget all objects */
156         for (OBJECT_IDX i = 1; i < caster_ptr->current_floor_ptr->o_max; i++)
157         {
158                 object_type *o_ptr = &caster_ptr->current_floor_ptr->o_list[i];
159
160                 if (!OBJECT_IS_VALID(o_ptr)) continue;
161                 if (OBJECT_IS_HELD_MONSTER(o_ptr)) continue;
162
163                 /* Forget the object */
164                 o_ptr->marked &= OM_TOUCHED;
165         }
166
167         /* Forget travel route when we have forgotten map */
168         forget_travel_flow(caster_ptr->current_floor_ptr);
169
170         caster_ptr->update |= (PU_UN_VIEW | PU_UN_LITE);
171         caster_ptr->update |= (PU_VIEW | PU_LITE | PU_MON_LITE);
172         caster_ptr->update |= (PU_MONSTERS);
173         caster_ptr->redraw |= (PR_MAP);
174         caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
175 }
176
177
178 /*
179  * Hack -- map the current panel (plus some) ala "magic mapping"
180  */
181 void map_area(player_type *caster_ptr, POSITION range)
182 {
183         if (d_info[caster_ptr->dungeon_idx].flags1 & DF1_DARKNESS) range /= 3;
184
185         /* Scan that area */
186         for (POSITION y = 1; y < caster_ptr->current_floor_ptr->height - 1; y++)
187         {
188                 for (POSITION x = 1; x < caster_ptr->current_floor_ptr->width - 1; x++)
189                 {
190                         if (distance(caster_ptr->y, caster_ptr->x, y, x) > range) continue;
191
192                         grid_type *g_ptr;
193                         g_ptr = &caster_ptr->current_floor_ptr->grid_array[y][x];
194
195                         /* Memorize terrain of the grid */
196                         g_ptr->info |= (CAVE_KNOWN);
197
198                         /* Feature code (applying "mimic" field) */
199                         FEAT_IDX feat = get_feat_mimic(g_ptr);
200                         feature_type *f_ptr;
201                         f_ptr = &f_info[feat];
202
203                         /* All non-walls are "checked" */
204                         if (have_flag(f_ptr->flags, FF_WALL)) continue;
205
206                         /* Memorize normal features */
207                         if (have_flag(f_ptr->flags, FF_REMEMBER))
208                         {
209                                 /* Memorize the object */
210                                 g_ptr->info |= (CAVE_MARK);
211                         }
212
213                         /* Memorize known walls */
214                         for (int i = 0; i < 8; i++)
215                         {
216                                 g_ptr = &caster_ptr->current_floor_ptr->grid_array[y + ddy_ddd[i]][x + ddx_ddd[i]];
217
218                                 /* Feature code (applying "mimic" field) */
219                                 feat = get_feat_mimic(g_ptr);
220                                 f_ptr = &f_info[feat];
221
222                                 /* Memorize walls (etc) */
223                                 if (have_flag(f_ptr->flags, FF_REMEMBER))
224                                 {
225                                         /* Memorize the walls */
226                                         g_ptr->info |= (CAVE_MARK);
227                                 }
228                         }
229                 }
230         }
231
232         caster_ptr->redraw |= (PR_MAP);
233         caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
234 }
235
236
237
238 /*!
239  * @brief *破壊*処理を行う / The spell of destruction
240  * @param y1 破壊の中心Y座標
241  * @param x1 破壊の中心X座標
242  * @param r 破壊の半径
243  * @param in_generate ダンジョンフロア生成中の処理ならばTRUE
244  * @return 効力があった場合TRUEを返す
245  * @details
246  * <pre>
247  * This spell "deletes" monsters (instead of "killing" them).
248  *
249  * Later we may use one function for both "destruction" and
250  * "earthquake" by using the "full" to select "destruction".
251  * </pre>
252  */
253 bool destroy_area(player_type *caster_ptr, POSITION y1, POSITION x1, POSITION r, bool in_generate)
254 {
255         /* Prevent destruction of quest levels and town */
256         floor_type *floor_ptr = caster_ptr->current_floor_ptr;
257         if ((floor_ptr->inside_quest && is_fixed_quest_idx(floor_ptr->inside_quest)) || !floor_ptr->dun_level)
258         {
259                 return FALSE;
260         }
261
262         /* Lose monster light */
263         if (!in_generate) clear_mon_lite(floor_ptr);
264
265         /* Big area of affect */
266         bool flag = FALSE;
267         for (POSITION y = (y1 - r); y <= (y1 + r); y++)
268         {
269                 for (POSITION x = (x1 - r); x <= (x1 + r); x++)
270                 {
271                         if (!in_bounds(floor_ptr, y, x)) continue;
272
273                         /* Extract the distance */
274                         int k = distance(y1, x1, y, x);
275
276                         /* Stay in the circle of death */
277                         if (k > r) continue;
278                         grid_type *g_ptr;
279                         g_ptr = &floor_ptr->grid_array[y][x];
280
281                         /* Lose room and vault */
282                         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
283
284                         /* Lose light and knowledge */
285                         g_ptr->info &= ~(CAVE_MARK | CAVE_GLOW | CAVE_KNOWN);
286
287                         if (!in_generate) /* Normal */
288                         {
289                                 /* Lose unsafety */
290                                 g_ptr->info &= ~(CAVE_UNSAFE);
291
292                                 /* Hack -- Notice player affect */
293                                 if (player_bold(caster_ptr, y, x))
294                                 {
295                                         /* Hurt the player later */
296                                         flag = TRUE;
297
298                                         /* Do not hurt this grid */
299                                         continue;
300                                 }
301                         }
302
303                         /* Hack -- Skip the epicenter */
304                         if ((y == y1) && (x == x1)) continue;
305
306                         if (g_ptr->m_idx)
307                         {
308                                 monster_type *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
309                                 monster_race *r_ptr = &r_info[m_ptr->r_idx];
310
311                                 if (in_generate) /* In generation */
312                                 {
313                                         /* Delete the monster (if any) */
314                                         delete_monster(caster_ptr, y, x);
315                                 }
316                                 else if (r_ptr->flags1 & RF1_QUESTOR)
317                                 {
318                                         /* Heal the monster */
319                                         m_ptr->hp = m_ptr->maxhp;
320
321                                         /* Try to teleport away quest monsters */
322                                         if (!teleport_away(caster_ptr, g_ptr->m_idx, (r * 2) + 1, TELEPORT_DEC_VALOUR)) continue;
323                                 }
324                                 else
325                                 {
326                                         if (record_named_pet && is_pet(m_ptr) && m_ptr->nickname)
327                                         {
328                                                 GAME_TEXT m_name[MAX_NLEN];
329
330                                                 monster_desc(caster_ptr, m_name, m_ptr, MD_INDEF_VISIBLE);
331                                                 exe_write_diary(caster_ptr, DIARY_NAMED_PET, RECORD_NAMED_PET_DESTROY, m_name);
332                                         }
333
334                                         /* Delete the monster (if any) */
335                                         delete_monster(caster_ptr, y, x);
336                                 }
337                         }
338
339                         /* During generation, destroyed artifacts are "preserved" */
340                         if (preserve_mode || in_generate)
341                         {
342                                 OBJECT_IDX this_o_idx, next_o_idx = 0;
343
344                                 /* Scan all objects in the grid */
345                                 for (this_o_idx = g_ptr->o_idx; this_o_idx; this_o_idx = next_o_idx)
346                                 {
347                                         object_type *o_ptr;
348                                         o_ptr = &floor_ptr->o_list[this_o_idx];
349                                         next_o_idx = o_ptr->next_o_idx;
350
351                                         /* Hack -- Preserve unknown artifacts */
352                                         if (object_is_fixed_artifact(o_ptr) && (!object_is_known(o_ptr) || in_generate))
353                                         {
354                                                 /* Mega-Hack -- Preserve the artifact */
355                                                 a_info[o_ptr->name1].cur_num = 0;
356
357                                                 if (in_generate && cheat_peek)
358                                                 {
359                                                         GAME_TEXT o_name[MAX_NLEN];
360                                                         object_desc(caster_ptr, o_name, o_ptr, (OD_NAME_ONLY | OD_STORE));
361                                                         msg_format(_("伝説のアイテム (%s) は生成中に*破壊*された。", "Artifact (%s) was *destroyed* during generation."), o_name);
362                                                 }
363                                         }
364                                         else if (in_generate && cheat_peek && o_ptr->art_name)
365                                         {
366                                                 msg_print(_("ランダム・アーティファクトの1つは生成中に*破壊*された。",
367                                                         "One of the random artifacts was *destroyed* during generation."));
368                                         }
369                                 }
370                         }
371
372                         delete_all_items_from_floor(caster_ptr, y, x);
373
374                         /* Destroy "non-permanent" grids */
375                         if (cave_perma_grid(g_ptr)) continue;
376
377                         /* Wall (or floor) type */
378                         int t = randint0(200);
379
380                         if (!in_generate) /* Normal */
381                         {
382                                 if (t < 20)
383                                 {
384                                         /* Create granite wall */
385                                         cave_set_feat(caster_ptr, y, x, feat_granite);
386                                 }
387                                 else if (t < 70)
388                                 {
389                                         /* Create quartz vein */
390                                         cave_set_feat(caster_ptr, y, x, feat_quartz_vein);
391                                 }
392                                 else if (t < 100)
393                                 {
394                                         /* Create magma vein */
395                                         cave_set_feat(caster_ptr, y, x, feat_magma_vein);
396                                 }
397                                 else
398                                 {
399                                         /* Create floor */
400                                         cave_set_feat(caster_ptr, y, x, feat_ground_type[randint0(100)]);
401                                 }
402
403                                 continue;
404                         }
405                         
406                         if (t < 20)
407                         {
408                                 /* Create granite wall */
409                                 place_grid(caster_ptr, g_ptr, GB_EXTRA);
410                         }
411                         else if (t < 70)
412                         {
413                                 /* Create quartz vein */
414                                 g_ptr->feat = feat_quartz_vein;
415                         }
416                         else if (t < 100)
417                         {
418                                 /* Create magma vein */
419                                 g_ptr->feat = feat_magma_vein;
420                         }
421                         else
422                         {
423                                 /* Create floor */
424                                 place_grid(caster_ptr, g_ptr, GB_FLOOR);
425                         }
426
427                         /* Clear garbage of hidden trap or door */
428                         g_ptr->mimic = 0;
429                 }
430         }
431
432         if (in_generate) return TRUE;
433
434         /* Process "re-glowing" */
435         for (POSITION y = (y1 - r); y <= (y1 + r); y++)
436         {
437                 for (POSITION x = (x1 - r); x <= (x1 + r); x++)
438                 {
439                         if (!in_bounds(floor_ptr, y, x)) continue;
440
441                         /* Extract the distance */
442                         int k = distance(y1, x1, y, x);
443
444                         /* Stay in the circle of death */
445                         if (k > r) continue;
446                         grid_type *g_ptr;
447                         g_ptr = &floor_ptr->grid_array[y][x];
448
449                         if (is_mirror_grid(g_ptr))
450                         {
451                                 g_ptr->info |= CAVE_GLOW;
452                                 continue;
453                         }
454                         
455                         if ((d_info[floor_ptr->dungeon_idx].flags1 & DF1_DARKNESS)) continue;
456
457                         DIRECTION i;
458                         POSITION yy, xx;
459                         grid_type *cc_ptr;
460
461                         for (i = 0; i < 9; i++)
462                         {
463                                 yy = y + ddy_ddd[i];
464                                 xx = x + ddx_ddd[i];
465                                 if (!in_bounds2(floor_ptr, yy, xx)) continue;
466                                 cc_ptr = &floor_ptr->grid_array[yy][xx];
467                                 if (have_flag(f_info[get_feat_mimic(cc_ptr)].flags, FF_GLOW))
468                                 {
469                                         g_ptr->info |= CAVE_GLOW;
470                                         break;
471                                 }
472                         }
473                 }
474         }
475
476         /* Hack -- Affect player */
477         if (flag)
478         {
479                 msg_print(_("燃えるような閃光が発生した!", "There is a searing blast of light!"));
480
481                 /* Blind the player */
482                 if (!caster_ptr->resist_blind && !caster_ptr->resist_lite)
483                 {
484                         /* Become blind */
485                         (void)set_blind(caster_ptr, caster_ptr->blind + 10 + randint1(10));
486                 }
487         }
488
489         forget_flow(floor_ptr);
490
491         /* Mega-Hack -- Forget the view and lite */
492         caster_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
493         caster_ptr->redraw |= (PR_MAP);
494         caster_ptr->window |= (PW_OVERHEAD | PW_DUNGEON);
495
496         if (caster_ptr->special_defense & NINJA_S_STEALTH)
497         {
498                 if (floor_ptr->grid_array[caster_ptr->y][caster_ptr->x].info & CAVE_GLOW) set_superstealth(caster_ptr, FALSE);
499         }
500
501         return TRUE;
502 }
503
504
505 /*!
506  * @brief カオス魔法「流星群」の処理としてプレイヤーを中心に隕石落下処理を10+1d10回繰り返す。
507  * / Drop 10+1d10 meteor ball at random places near the player
508  * @param caster_ptr プレーヤーへの参照ポインタ
509  * @param dam ダメージ
510  * @param rad 効力の半径
511  * @return なし
512  */
513 void cast_meteor(player_type *caster_ptr, HIT_POINT dam, POSITION rad)
514 {
515     int b = 10 + randint1(10);
516     for (int i = 0; i < b; i++) {
517         POSITION y = 0, x = 0;
518         int count;
519
520         for (count = 0; count <= 20; count++) {
521             int dy, dx, d;
522
523             x = caster_ptr->x - 8 + randint0(17);
524             y = caster_ptr->y - 8 + randint0(17);
525             dx = (caster_ptr->x > x) ? (caster_ptr->x - x) : (x - caster_ptr->x);
526             dy = (caster_ptr->y > y) ? (caster_ptr->y - y) : (y - caster_ptr->y);
527             d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
528
529             if (d >= 9)
530                 continue;
531
532             floor_type *floor_ptr = caster_ptr->current_floor_ptr;
533             if (!in_bounds(floor_ptr, y, x) || !projectable(caster_ptr, caster_ptr->y, caster_ptr->x, y, x)
534                 || !cave_have_flag_bold(floor_ptr, y, x, FF_PROJECT))
535                 continue;
536
537             break;
538         }
539
540         if (count > 20)
541             continue;
542
543         project(caster_ptr, 0, rad, y, x, dam, GF_METEOR, PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM, -1);
544     }
545 }