OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / spell-realm / spells-chaos.cpp
1 #include "spell-realm/spells-chaos.h"
2 #include "core/window-redrawer.h"
3 #include "dungeon/quest.h"
4 #include "effect/attribute-types.h"
5 #include "effect/effect-characteristics.h"
6 #include "effect/effect-processor.h"
7 #include "floor/cave.h"
8 #include "floor/geometry.h"
9 #include "grid/feature.h"
10 #include "grid/grid.h"
11 #include "monster/monster-describer.h"
12 #include "monster/monster-status-setter.h"
13 #include "monster/monster-status.h"
14 #include "player-info/class-info.h"
15 #include "player/player-damage.h"
16 #include "spell-kind/spells-floor.h"
17 #include "spell-kind/spells-launcher.h"
18 #include "system/floor-type-definition.h"
19 #include "system/grid-type-definition.h"
20 #include "system/monster-entity.h"
21 #include "system/player-type-definition.h"
22 #include "system/redrawing-flags-updater.h"
23 #include "system/terrain-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(PlayerType *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(TerrainCharacteristics::PROJECT)) {
42             if (!g_ptr->mimic || terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::PROJECT) || !permanent_wall(&terrains_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, AttributeType::ROCKET, i, 175, 2);
53             }
54         }
55
56         for (int i = 1; i < 10; i++) {
57             if (i - 5) {
58                 fire_ball(player_ptr, AttributeType::MANA, i, 175, 3);
59             }
60         }
61
62         for (int i = 1; i < 10; i++) {
63             if (i - 5) {
64                 fire_ball(player_ptr, AttributeType::NUKE, i, 175, 4);
65             }
66         }
67
68         return;
69     }
70
71     bool is_special_fllor = inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number);
72     is_special_fllor |= floor_ptr->dun_level == 0;
73     if (is_special_fllor) {
74         msg_print(_("地面が揺れた。", "The ground trembles."));
75         return;
76     }
77
78 #ifdef JP
79     msg_format("あなたは%sを壁に近すぎる場所で唱えてしまった!", ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "祈り" : "呪文"));
80 #else
81     msg_format("You %s the %s too close to a wall!", ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "recite" : "cast"),
82         ((mp_ptr->spell_book == ItemKindType::LIFE_BOOK) ? "prayer" : "spell"));
83 #endif
84     msg_print(_("大きな爆発音があった!", "There is a loud explosion!"));
85
86     if (one_in_(666)) {
87         if (!vanish_dungeon(player_ptr)) {
88             msg_print(_("ダンジョンは一瞬静まり返った。", "The dungeon becomes quiet for a moment."));
89         }
90         take_hit(player_ptr, DAMAGE_NOESCAPE, 100 + randint1(150), _("自殺的な虚無招来", "a suicidal Call the Void"));
91         return;
92     }
93
94     if (destroy_area(player_ptr, player_ptr->y, player_ptr->x, 15 + player_ptr->lev + randint0(11), false)) {
95         msg_print(_("ダンジョンが崩壊した...", "The dungeon collapses..."));
96     } else {
97         msg_print(_("ダンジョンは大きく揺れた。", "The dungeon trembles."));
98     }
99     take_hit(player_ptr, DAMAGE_NOESCAPE, 100 + randint1(150), _("自殺的な虚無招来", "a suicidal Call the Void"));
100 }
101
102 /*!
103  * @brief 虚無招来によるフロア中の全壁除去処理 /
104  * Vanish all walls in this floor
105  * @param player_ptr プレイヤーへの参照ポインタ
106  * @param player_ptr 術者の参照ポインタ
107  * @return 実際に処理が反映された場合TRUE
108  */
109 bool vanish_dungeon(PlayerType *player_ptr)
110 {
111     auto *floor_ptr = player_ptr->current_floor_ptr;
112     bool is_special_floor = inside_quest(floor_ptr->quest_number) && QuestType::is_fixed(floor_ptr->quest_number);
113     is_special_floor |= (floor_ptr->dun_level == 0);
114     if (is_special_floor) {
115         return false;
116     }
117
118     for (POSITION y = 1; y < floor_ptr->height - 1; y++) {
119         for (POSITION x = 1; x < floor_ptr->width - 1; x++) {
120             auto *g_ptr = &floor_ptr->grid_array[y][x];
121
122             auto *f_ptr = &terrains_info[g_ptr->feat];
123             g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
124             auto *m_ptr = &floor_ptr->m_list[g_ptr->m_idx];
125             if (g_ptr->m_idx && m_ptr->is_asleep()) {
126                 (void)set_monster_csleep(player_ptr, g_ptr->m_idx, 0);
127                 if (m_ptr->ml) {
128                     const auto m_name = monster_desc(player_ptr, m_ptr, 0);
129                     msg_format(_("%s^が目を覚ました。", "%s^ wakes up."), m_name.data());
130                 }
131             }
132
133             if (f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
134                 cave_alter_feat(player_ptr, y, x, TerrainCharacteristics::HURT_DISI);
135             }
136         }
137     }
138
139     for (POSITION x = 0; x < floor_ptr->width; x++) {
140         auto *g_ptr = &floor_ptr->grid_array[0][x];
141         auto *f_ptr = &terrains_info[g_ptr->mimic];
142         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
143
144         if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
145             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
146             if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
147                 g_ptr->info &= ~(CAVE_MARK);
148             }
149         }
150
151         g_ptr = &floor_ptr->grid_array[floor_ptr->height - 1][x];
152         f_ptr = &terrains_info[g_ptr->mimic];
153         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
154
155         if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
156             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
157             if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
158                 g_ptr->info &= ~(CAVE_MARK);
159             }
160         }
161     }
162
163     /* Special boundary walls -- Left and right */
164     for (POSITION y = 1; y < (floor_ptr->height - 1); y++) {
165         auto *g_ptr = &floor_ptr->grid_array[y][0];
166         auto *f_ptr = &terrains_info[g_ptr->mimic];
167         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
168
169         if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
170             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
171             if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
172                 g_ptr->info &= ~(CAVE_MARK);
173             }
174         }
175
176         g_ptr = &floor_ptr->grid_array[y][floor_ptr->width - 1];
177         f_ptr = &terrains_info[g_ptr->mimic];
178         g_ptr->info &= ~(CAVE_ROOM | CAVE_ICKY);
179
180         if (g_ptr->mimic && f_ptr->flags.has(TerrainCharacteristics::HURT_DISI)) {
181             g_ptr->mimic = feat_state(floor_ptr, g_ptr->mimic, TerrainCharacteristics::HURT_DISI);
182             if (terrains_info[g_ptr->mimic].flags.has_not(TerrainCharacteristics::REMEMBER)) {
183                 g_ptr->info &= ~(CAVE_MARK);
184             }
185         }
186     }
187
188     auto &rfu = RedrawingFlagsUpdater::get_instance();
189     static constexpr auto flags_srf = {
190         StatusRecalculatingFlag::UN_VIEW,
191         StatusRecalculatingFlag::UN_LITE,
192         StatusRecalculatingFlag::VIEW,
193         StatusRecalculatingFlag::LITE,
194         StatusRecalculatingFlag::FLOW,
195         StatusRecalculatingFlag::MONSTER_LITE,
196         StatusRecalculatingFlag::MONSTER_STATUSES,
197     };
198     rfu.set_flags(flags_srf);
199     rfu.set_flag(MainWindowRedrawingFlag::MAP);
200     static constexpr auto flags_swrf = {
201         SubWindowRedrawingFlag::OVERHEAD,
202         SubWindowRedrawingFlag::DUNGEON,
203     };
204     rfu.set_flags(flags_swrf);
205     return true;
206 }
207
208 /*!
209  * @brief カオス魔法「流星群」/トランプ魔法「隕石のカード」の処理としてプレイヤーを中心に隕石落下処理を10+1d10回繰り返す。
210  * / Drop 10+1d10 meteor ball at random places near the player
211  * @param player_ptr プレイヤーへの参照ポインタ
212  * @param dam ダメージ
213  * @param rad 効力の半径
214  * @details このファイルにいるのは、spells-trump.c と比べて行数が少なかったため。それ以上の意図はない
215  */
216 void cast_meteor(PlayerType *player_ptr, int dam, POSITION rad)
217 {
218     int b = 10 + randint1(10);
219     for (int i = 0; i < b; i++) {
220         POSITION y = 0, x = 0;
221         int count;
222
223         for (count = 0; count <= 20; count++) {
224             int dy, dx, d;
225
226             x = player_ptr->x - 8 + randint0(17);
227             y = player_ptr->y - 8 + randint0(17);
228             dx = (player_ptr->x > x) ? (player_ptr->x - x) : (x - player_ptr->x);
229             dy = (player_ptr->y > y) ? (player_ptr->y - y) : (y - player_ptr->y);
230             d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
231
232             if (d >= 9) {
233                 continue;
234             }
235
236             auto *floor_ptr = player_ptr->current_floor_ptr;
237             if (!in_bounds(floor_ptr, y, x)) {
238                 continue;
239             }
240
241             const auto is_projectable = projectable(player_ptr, player_ptr->y, player_ptr->x, y, x);
242             if (!is_projectable || !cave_has_flag_bold(floor_ptr, y, x, TerrainCharacteristics::PROJECT)) {
243                 continue;
244             }
245
246             break;
247         }
248
249         if (count > 20) {
250             continue;
251         }
252
253         project(player_ptr, 0, rad, y, x, dam, AttributeType::METEOR, PROJECT_KILL | PROJECT_JUMP | PROJECT_ITEM);
254     }
255 }