OSDN Git Service

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