OSDN Git Service

[Refactor] #1766 Changed ItemPrimaryType from enum to enum class
[hengbandforosx/hengbandosx.git] / src / spell-realm / spells-chaos.cpp
1 #include "spell-realm/spells-chaos.h"
2 #include "core/player-redraw-types.h"
3 #include "core/player-update-types.h"
4 #include "core/window-redrawer.h"
5 #include "dungeon/quest.h"
6 #include "effect/effect-characteristics.h"
7 #include "effect/effect-processor.h"
8 #include "floor/cave.h"
9 #include "floor/geometry.h"
10 #include "grid/feature.h"
11 #include "grid/grid.h"
12 #include "monster/monster-describer.h"
13 #include "monster/monster-status-setter.h"
14 #include "monster/monster-status.h"
15 #include "player-info/class-info.h"
16 #include "player/player-damage.h"
17 #include "spell-kind/spells-floor.h"
18 #include "spell-kind/spells-launcher.h"
19 #include "spell/spell-types.h"
20 #include "system/floor-type-definition.h"
21 #include "system/grid-type-definition.h"
22 #include "system/monster-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "target/projection-path-calculator.h"
25 #include "util/bit-flags-calculator.h"
26 #include "view/display-messages.h"
27
28 /*!
29  * @brief 虚無招来処理 /
30  * @param player_ptr プレイヤーへの参照ポインタ
31  * @details
32  * Sorry, it becomes not (void)...
33  */
34 void call_the_void(player_type *player_ptr)
35 {
36     bool do_call = true;
37     auto *floor_ptr = player_ptr->current_floor_ptr;
38     for (int i = 0; i < 9; i++) {
39         auto *g_ptr = &floor_ptr->grid_array[player_ptr->y + ddy_ddd[i]][player_ptr->x + ddx_ddd[i]];
40
41         if (!g_ptr->cave_has_flag(FF::PROJECT)) {
42             if (!g_ptr->mimic || f_info[g_ptr->mimic].flags.has_not(FF::PROJECT) || !permanent_wall(&f_info[g_ptr->feat])) {
43                 do_call = false;
44                 break;
45             }
46         }
47     }
48
49     if (do_call) {
50         for (int i = 1; i < 10; i++) {
51             if (i - 5)
52                 fire_ball(player_ptr, GF_ROCKET, i, 175, 2);
53         }
54
55         for (int i = 1; i < 10; i++) {
56             if (i - 5)
57                 fire_ball(player_ptr, GF_MANA, i, 175, 3);
58         }
59
60         for (int i = 1; i < 10; i++) {
61             if (i - 5)
62                 fire_ball(player_ptr, GF_NUKE, i, 175, 4);
63         }
64
65         return;
66     }
67
68     bool is_special_fllor = floor_ptr->inside_quest && quest_type::is_fixed(floor_ptr->inside_quest);
69     is_special_fllor |= floor_ptr->dun_level > 0;
70     if (is_special_fllor) {
71         msg_print(_("地面が揺れた。", "The ground trembles."));
72         return;
73     }
74
75 #ifdef JP
76     msg_format("あなたは%sを壁に近すぎる場所で唱えてしまった!", ((mp_ptr->spell_book == ItemPrimaryType::TV_LIFE_BOOK) ? "祈り" : "呪文"));
77 #else
78     msg_format("You %s the %s too close to a wall!", ((mp_ptr->spell_book == ItemPrimaryType::TV_LIFE_BOOK) ? "recite" : "cast"),
79         ((mp_ptr->spell_book == ItemPrimaryType::TV_LIFE_BOOK) ? "prayer" : "spell"));
80 #endif
81     msg_print(_("大きな爆発音があった!", "There is a loud explosion!"));
82
83     if (one_in_(666)) {
84         if (!vanish_dungeon(player_ptr))
85             msg_print(_("ダンジョンは一瞬静まり返った。", "The dungeon becomes quiet for a moment."));
86         take_hit(player_ptr, DAMAGE_NOESCAPE, 100 + randint1(150), _("自殺的な虚無招来", "a suicidal Call the Void"));
87         return;
88     }
89
90     if (destroy_area(player_ptr, player_ptr->y, player_ptr->x, 15 + player_ptr->lev + randint0(11), false))
91         msg_print(_("ダンジョンが崩壊した...", "The dungeon collapses..."));
92     else
93         msg_print(_("ダンジョンは大きく揺れた。", "The dungeon trembles."));
94     take_hit(player_ptr, DAMAGE_NOESCAPE, 100 + randint1(150), _("自殺的な虚無招来", "a suicidal Call the Void"));
95 }
96
97 /*!
98  * @brief 虚無招来によるフロア中の全壁除去処理 /
99  * Vanish all walls in this floor
100  * @param player_ptr プレイヤーへの参照ポインタ
101  * @param player_ptr 術者の参照ポインタ
102  * @return 実際に処理が反映された場合TRUE
103  */
104 bool vanish_dungeon(player_type *player_ptr)
105 {
106     auto *floor_ptr = player_ptr->current_floor_ptr;
107     bool is_special_floor = floor_ptr->inside_quest && quest_type::is_fixed(floor_ptr->inside_quest);
108     is_special_floor |= floor_ptr->dun_level > 0;
109     if (is_special_floor)
110         return false;
111
112     GAME_TEXT m_name[MAX_NLEN];
113     for (POSITION y = 1; y < floor_ptr->height - 1; y++) {
114         for (POSITION x = 1; x < floor_ptr->width - 1; x++) {
115             auto *g_ptr = &floor_ptr->grid_array[y][x];
116
117             auto *f_ptr = &f_info[g_ptr->feat];
118             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
119             auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
120             if (g_ptr->m_idx && monster_csleep_remaining(m_ptr)) {
121                 (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
122                 if (m_ptr->ml) {
123                     monster_desc(player_ptr, m_name, m_ptr, 0);
124                     msg_format(_("%^sが目を覚ました。", "%^s wakes up."), m_name);
125                 }
126             }
127
128             if (f_ptr->flags.has(FF::HURT_DISI))
129                 cave_alter_feat(player_ptr, y, x, FF::HURT_DISI);
130         }
131     }
132
133     for (POSITION x = 0; x < floor_ptr->width; x++) {
134         auto *g_ptr = &floor_ptr->grid_array[0][x];
135         auto *f_ptr = &f_info[g_ptr->mimic];
136         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
137
138         if (g_ptr->mimic && f_ptr->flags.has(FF::HURT_DISI)) {
139             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, FF::HURT_DISI);
140             if (f_info[g_ptr->mimic].flags.has_not(FF::REMEMBER))
141                 g_ptr->info &= ~(CAVE_MARK);
142         }
143
144         g_ptr = &floor_ptr->grid_array[floor_ptr->height - 1][x];
145         f_ptr = &f_info[g_ptr->mimic];
146         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
147
148         if (g_ptr->mimic && f_ptr->flags.has(FF::HURT_DISI)) {
149             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, FF::HURT_DISI);
150             if (f_info[g_ptr->mimic].flags.has_not(FF::REMEMBER))
151                 g_ptr->info &= ~(CAVE_MARK);
152         }
153     }
154
155     /* Special boundary walls -- Left and right */
156     for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
157         auto *g_ptr = &floor_ptr->grid_array[y][0];
158         auto *f_ptr = &f_info[g_ptr->mimic];
159         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
160
161         if (g_ptr->mimic && f_ptr->flags.has(FF::HURT_DISI)) {
162             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, FF::HURT_DISI);
163             if (f_info[g_ptr->mimic].flags.has_not(FF::REMEMBER))
164                 g_ptr->info &= ~(CAVE_MARK);
165         }
166
167         g_ptr = &floor_ptr->grid_array[y][floor_ptr->width - 1];
168         f_ptr = &f_info[g_ptr->mimic];
169         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
170
171         if (g_ptr->mimic && f_ptr->flags.has(FF::HURT_DISI)) {
172             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, FF::HURT_DISI);
173             if (f_info[g_ptr->mimic].flags.has_not(FF::REMEMBER))
174                 g_ptr->info &= ~(CAVE_MARK);
175         }
176     }
177
178     player_ptr->update |= (PU_UN_VIEW | PU_UN_LITE | PU_VIEW | PU_LITE | PU_FLOW | PU_MON_LITE | PU_MONSTERS);
179     player_ptr->redraw |= (PR_MAP);
180     player_ptr->window_flags |= (PW_OVERHEAD | PW_DUNGEON);
181     return true;
182 }
183
184 /*!
185  * @brief カオス魔法「流星群」/トランプ魔法「隕石のカード」の処理としてプレイヤーを中心に隕石落下処理を10+1d10回繰り返す。
186  * / Drop 10+1d10 meteor ball at random places near the player
187  * @param player_ptr プレイヤーへの参照ポインタ
188  * @param dam ダメージ
189  * @param rad 効力の半径
190  * @details このファイルにいるのは、spells-trump.c と比べて行数が少なかったため。それ以上の意図はない
191  */
192 void cast_meteor(player_type *player_ptr, HIT_POINT dam, POSITION rad)
193 {
194     int b = 10 + randint1(10);
195     for (int i = 0; i < b; i++) {
196         POSITION y = 0, x = 0;
197         int count;
198
199         for (count = 0; count <= 20; count++) {
200             int dy, dx, d;
201
202             x = player_ptr->x - 8 + randint0(17);
203             y = player_ptr->y - 8 + randint0(17);
204             dx = (player_ptr->x > x) ? (player_ptr->x - x) : (x - player_ptr->x);
205             dy = (player_ptr->y > y) ? (player_ptr->y - y) : (y - player_ptr->y);
206             d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
207
208             if (d >= 9)
209                 continue;
210
211             floor_type *floor_ptr = player_ptr->current_floor_ptr;
212             if (!in_bounds(floor_ptr, y, x) || !projectable(player_ptr, player_ptr->y, player_ptr->x, y, x)
213                 || !cave_has_flag_bold(floor_ptr, y, x, FF::PROJECT))
214                 continue;
215
216             break;
217         }
218
219         if (count > 20)
220             continue;
221
222         project(player_ptr, 0, rad, y, x, dam, GF_METEOR, PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM);
223     }
224 }