OSDN Git Service

[Refactor] monster_idxと0との比較を関数化する
[hengbandforosx/hengbandosx.git] / src / spell-realm / spells-crusade.cpp
1 /*!
2  * @brief 破邪魔法処理
3  * @date 2020/06/05
4  * @author Hourier
5  */
6
7 #include "spell-realm/spells-crusade.h"
8 #include "core/disturbance.h"
9 #include "core/stuff-handler.h"
10 #include "effect/attribute-types.h"
11 #include "effect/effect-characteristics.h"
12 #include "effect/effect-processor.h"
13 #include "floor/cave.h"
14 #include "floor/geometry.h"
15 #include "game-option/disturbance-options.h"
16 #include "grid/feature-flag-types.h"
17 #include "monster/monster-util.h"
18 #include "spell-realm/spells-crusade.h"
19 #include "spell/range-calc.h"
20 #include "system/angband-system.h"
21 #include "system/floor-type-definition.h"
22 #include "system/grid-type-definition.h"
23 #include "system/player-type-definition.h"
24 #include "system/redrawing-flags-updater.h"
25 #include "target/projection-path-calculator.h"
26 #include "target/target-checker.h"
27 #include "target/target-getter.h"
28 #include "util/bit-flags-calculator.h"
29 #include "view/display-messages.h"
30
31 /*!
32  * @brief 破邪魔法「神の怒り」の処理としてターゲットを指定した後分解のボールを最大20回発生させる。
33  * @param player_ptr プレイヤーへの参照ポインタ
34  * @param dam ダメージ
35  * @param rad 効力の半径
36  * @return ターゲットを指定し、実行したならばTRUEを返す。
37  */
38 bool cast_wrath_of_the_god(PlayerType *player_ptr, int dam, POSITION rad)
39 {
40     int dir;
41     if (!get_aim_dir(player_ptr, &dir)) {
42         return false;
43     }
44
45     Pos2D pos_target(player_ptr->y + 99 * ddy[dir], player_ptr->x + 99 * ddx[dir]);
46     if ((dir == 5) && target_okay(player_ptr)) {
47         pos_target.x = target_col;
48         pos_target.y = target_row;
49     }
50
51     Pos2D pos = player_ptr->get_position();
52     auto &floor = *player_ptr->current_floor_ptr;
53     while (true) {
54         if (pos == pos_target) {
55             break;
56         }
57
58         const auto pos_to = mmove2(pos, player_ptr->get_position(), pos_target);
59         if (AngbandSystem::get_instance().get_max_range() <= distance(player_ptr->y, player_ptr->x, pos_to.y, pos_to.x)) {
60             break;
61         }
62         if (!cave_has_flag_bold(&floor, pos_to.y, pos_to.x, TerrainCharacteristics::PROJECT)) {
63             break;
64         }
65         if ((dir != 5) && is_monster(floor.get_grid(pos_to).m_idx)) {
66             break;
67         }
68
69         pos = pos_to;
70     }
71
72     pos_target = pos;
73     const auto b = 10 + randint1(10);
74     for (auto i = 0; i < b; i++) {
75         auto count = 20;
76         Pos2D pos_explode(pos_target.x, pos_target.y);
77         while (count--) {
78             const auto x = pos_target.x - 5 + randint0(11);
79             const auto y = pos_target.y - 5 + randint0(11);
80             const auto dx = (pos_target.x > x) ? (pos_target.x - x) : (x - pos_target.x);
81             const auto dy = (pos_target.y > y) ? (pos_target.y - y) : (y - pos_target.y);
82             const auto d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
83             if (d < 5) {
84                 pos_explode.x = x;
85                 pos_explode.y = y;
86                 break;
87             }
88         }
89
90         if (count < 0) {
91             continue;
92         }
93
94         auto should_cast = in_bounds(&floor, pos_explode.y, pos_explode.x);
95         should_cast &= !cave_stop_disintegration(&floor, pos_explode.y, pos_explode.x);
96         should_cast &= in_disintegration_range(&floor, pos_target.y, pos_target.x, pos_explode.y, pos_explode.x);
97         if (!should_cast) {
98             continue;
99         }
100
101         constexpr auto mode = PROJECT_JUMP | PROJECT_GRID | PROJECT_ITEM | PROJECT_KILL;
102         project(player_ptr, 0, rad, pos_explode.y, pos_explode.x, dam, AttributeType::DISINTEGRATE, mode);
103     }
104
105     return true;
106 }
107
108 /*!
109  * @brief 一時的聖なるのオーラの継続時間をセットする / Set "tim_sh_holy", notice observable changes
110  * @param v 継続時間
111  * @param do_dec 現在の継続時間より長い値のみ上書きする
112  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
113  */
114 bool set_tim_sh_holy(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
115 {
116     bool notice = false;
117     v = (v > 10000) ? 10000 : (v < 0) ? 0
118                                       : v;
119
120     if (player_ptr->is_dead) {
121         return false;
122     }
123
124     if (v) {
125         if (player_ptr->tim_sh_holy && !do_dec) {
126             if (player_ptr->tim_sh_holy > v) {
127                 return false;
128             }
129         } else if (!player_ptr->tim_sh_holy) {
130             msg_print(_("体が聖なるオーラで覆われた。", "You are enveloped by a holy aura!"));
131             notice = true;
132         }
133     } else {
134         if (player_ptr->tim_sh_holy) {
135             msg_print(_("聖なるオーラが消えた。", "The holy aura disappeared."));
136             notice = true;
137         }
138     }
139
140     auto &rfu = RedrawingFlagsUpdater::get_instance();
141     player_ptr->tim_sh_holy = v;
142     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
143
144     if (!notice) {
145         return false;
146     }
147
148     if (disturb_state) {
149         disturb(player_ptr, false, false);
150     }
151
152     rfu.set_flag(StatusRecalculatingFlag::BONUS);
153     handle_stuff(player_ptr);
154     return true;
155 }
156
157 /*!
158  * @brief 目には目をの残り時間をセットする / Set "tim_eyeeye", notice observable changes
159  * @param v 継続時間
160  * @param do_dec 現在の継続時間より長い値のみ上書きする
161  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す
162  * @details 呪術領域でも使えるが、汎用性と行数の兼ね合いを考えて破邪側に入れた
163  */
164 bool set_tim_eyeeye(PlayerType *player_ptr, TIME_EFFECT v, bool do_dec)
165 {
166     bool notice = false;
167     v = (v > 10000) ? 10000 : (v < 0) ? 0
168                                       : v;
169
170     if (player_ptr->is_dead) {
171         return false;
172     }
173
174     if (v) {
175         if (player_ptr->tim_eyeeye && !do_dec) {
176             if (player_ptr->tim_eyeeye > v) {
177                 return false;
178             }
179         } else if (!player_ptr->tim_eyeeye) {
180             msg_print(_("法の守り手になった気がした!", "You feel like a keeper of commandments!"));
181             notice = true;
182         }
183     } else {
184         if (player_ptr->tim_eyeeye) {
185             msg_print(_("懲罰を執行することができなくなった。", "You lost your aura of retribution."));
186             notice = true;
187         }
188     }
189
190     auto &rfu = RedrawingFlagsUpdater::get_instance();
191     player_ptr->tim_eyeeye = v;
192     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
193
194     if (!notice) {
195         return false;
196     }
197
198     if (disturb_state) {
199         disturb(player_ptr, false, false);
200     }
201
202     rfu.set_flag(StatusRecalculatingFlag::BONUS);
203     handle_stuff(player_ptr);
204     return true;
205 }