OSDN Git Service

Merge branch 'develop' into feature/Monster-Sweep-Grid-Adjustment
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-lite.cpp
1 /*!
2  * @brief モンスターの魔法によってフロアを明るくする処理及びその判定
3  * @date 2020/07/23
4  * @author Hourier
5  */
6
7 #include "mspell/mspell-lite.h"
8 #include "dungeon/dungeon-flag-types.h"
9 #include "dungeon/dungeon.h"
10 #include "floor/cave.h"
11 #include "floor/geometry.h"
12 #include "floor/line-of-sight.h"
13 #include "grid/feature.h"
14 #include "monster-race/monster-race.h"
15 #include "monster-race/race-ability-mask.h"
16 #include "monster-race/race-flags2.h"
17 #include "monster-race/race-flags3.h"
18 #include "monster-race/race-flags7.h"
19 #include "mspell/mspell-attack-util.h"
20 #include "mspell/mspell-judgement.h"
21 #include "spell/range-calc.h"
22 #include "system/floor-type-definition.h"
23 #include "system/grid-type-definition.h"
24 #include "system/monster-race-definition.h"
25 #include "system/monster-type-definition.h"
26 #include "system/player-type-definition.h"
27 #include "target/projection-path-calculator.h"
28 #include "util/bit-flags-calculator.h"
29
30 /*!
31  * @brief モンスターがプレイヤーにダメージを与えるための最適な座標を算出する /
32  * @param target_ptr プレーヤーへの参照ポインタ
33  * @param m_ptr 技能を使用するモンスター構造体の参照ポインタ
34  * @param yp 最適な目標地点のY座標を返す参照ポインタ
35  * @param xp 最適な目標地点のX座標を返す参照ポインタ
36  * @param f_flag 射線に入れるのを避ける地形の所持フラグ
37  * @param path_check 射線を判定するための関数ポインタ
38  * @return 有効な座標があった場合TRUEを返す
39  */
40 bool adjacent_grid_check(player_type *target_ptr, monster_type *m_ptr, POSITION *yp, POSITION *xp, int f_flag, path_check_pf path_check)
41 {
42     static int tonari_y[4][8] = { { -1, -1, -1, 0, 0, 1, 1, 1 }, { -1, -1, -1, 0, 0, 1, 1, 1 }, { 1, 1, 1, 0, 0, -1, -1, -1 }, { 1, 1, 1, 0, 0, -1, -1, -1 } };
43     static int tonari_x[4][8] = { { -1, 0, 1, -1, 1, -1, 0, 1 }, { 1, 0, -1, 1, -1, 1, 0, -1 }, { -1, 0, 1, -1, 1, -1, 0, 1 }, { 1, 0, -1, 1, -1, 1, 0, -1 } };
44
45     int next;
46     if (m_ptr->fy < target_ptr->y && m_ptr->fx < target_ptr->x)
47         next = 0;
48     else if (m_ptr->fy < target_ptr->y)
49         next = 1;
50     else if (m_ptr->fx < target_ptr->x)
51         next = 2;
52     else
53         next = 3;
54
55     for (int i = 0; i < 8; i++) {
56         int next_x = *xp + tonari_x[next][i];
57         int next_y = *yp + tonari_y[next][i];
58         grid_type *g_ptr;
59         g_ptr = &target_ptr->current_floor_ptr->grid_array[next_y][next_x];
60         if (!g_ptr->cave_has_flag(f_flag))
61             continue;
62
63         if (path_check(target_ptr, m_ptr->fy, m_ptr->fx, next_y, next_x)) {
64             *yp = next_y;
65             *xp = next_x;
66             return true;
67         }
68     }
69
70     return false;
71 }
72
73 void decide_lite_range(player_type *target_ptr, msa_type *msa_ptr)
74 {
75     if (msa_ptr->ability_flags.has_not(RF_ABILITY::BR_LITE))
76         return;
77
78     msa_ptr->y_br_lite = msa_ptr->y;
79     msa_ptr->x_br_lite = msa_ptr->x;
80     if (los(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y_br_lite, msa_ptr->x_br_lite)) {
81         feature_type *f_ptr = &f_info[target_ptr->current_floor_ptr->grid_array[msa_ptr->y_br_lite][msa_ptr->x_br_lite].feat];
82         if (!has_flag(f_ptr->flags, FF_LOS) && has_flag(f_ptr->flags, FF_PROJECT) && one_in_(2))
83             msa_ptr->ability_flags.reset(RF_ABILITY::BR_LITE);
84     } else if (!adjacent_grid_check(target_ptr, msa_ptr->m_ptr, &msa_ptr->y_br_lite, &msa_ptr->x_br_lite, FF_LOS, los))
85         msa_ptr->ability_flags.reset(RF_ABILITY::BR_LITE);
86
87     if (msa_ptr->ability_flags.has(RF_ABILITY::BR_LITE))
88         return;
89
90     msa_ptr->y_br_lite = 0;
91     msa_ptr->x_br_lite = 0;
92 }
93
94 static void feature_projection(floor_type *floor_ptr, msa_type *msa_ptr)
95 {
96     feature_type *f_ptr = &f_info[floor_ptr->grid_array[msa_ptr->y][msa_ptr->x].feat];
97     if (has_flag(f_ptr->flags, FF_PROJECT))
98         return;
99
100     if (msa_ptr->ability_flags.has(RF_ABILITY::BR_DISI) && has_flag(f_ptr->flags, FF_HURT_DISI) && one_in_(2)) {
101         msa_ptr->do_spell = DO_SPELL_BR_DISI;
102         return;
103     }
104
105     if (msa_ptr->ability_flags.has(RF_ABILITY::BR_LITE) && has_flag(f_ptr->flags, FF_LOS) && one_in_(2))
106         msa_ptr->do_spell = DO_SPELL_BR_LITE;
107 }
108
109 static void check_lite_area_by_mspell(player_type *target_ptr, msa_type *msa_ptr)
110 {
111     if (msa_ptr->ability_flags.has(RF_ABILITY::BR_DISI) && (msa_ptr->m_ptr->cdis < get_max_range(target_ptr) / 2)
112         && in_disintegration_range(target_ptr->current_floor_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x)
113         && (one_in_(10) || (projectable(target_ptr, msa_ptr->y, msa_ptr->x, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx) && one_in_(2)))) {
114         msa_ptr->do_spell = DO_SPELL_BR_DISI;
115         msa_ptr->success = true;
116         return;
117     }
118
119     if (msa_ptr->ability_flags.has(RF_ABILITY::BR_LITE) && (msa_ptr->m_ptr->cdis < get_max_range(target_ptr) / 2)
120         && los(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
121         msa_ptr->do_spell = DO_SPELL_BR_LITE;
122         msa_ptr->success = true;
123         return;
124     }
125
126     if (msa_ptr->ability_flags.has_not(RF_ABILITY::BA_LITE) || (msa_ptr->m_ptr->cdis > get_max_range(target_ptr)))
127         return;
128
129     POSITION by = msa_ptr->y, bx = msa_ptr->x;
130     get_project_point(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, &by, &bx, 0L);
131     if ((distance(by, bx, msa_ptr->y, msa_ptr->x) <= 3) && los(target_ptr, by, bx, msa_ptr->y, msa_ptr->x) && one_in_(5)) {
132         msa_ptr->do_spell = DO_SPELL_BA_LITE;
133         msa_ptr->success = true;
134     }
135 }
136
137 static void decide_lite_breath(player_type *target_ptr, msa_type *msa_ptr)
138 {
139     if (msa_ptr->success)
140         return;
141
142     if (msa_ptr->m_ptr->target_y && msa_ptr->m_ptr->target_x) {
143         msa_ptr->y = msa_ptr->m_ptr->target_y;
144         msa_ptr->x = msa_ptr->m_ptr->target_x;
145         msa_ptr->ability_flags &= RF_ABILITY_INDIRECT_MASK;
146         msa_ptr->success = true;
147     }
148
149     if ((msa_ptr->y_br_lite == 0) || (msa_ptr->x_br_lite == 0) || (msa_ptr->m_ptr->cdis > get_max_range(target_ptr) / 2) || !one_in_(5))
150         return;
151
152     if (msa_ptr->success) {
153         msa_ptr->ability_flags.set(RF_ABILITY::BR_LITE);
154         return;
155     }
156
157     msa_ptr->y = msa_ptr->y_br_lite;
158     msa_ptr->x = msa_ptr->x_br_lite;
159     msa_ptr->do_spell = DO_SPELL_BR_LITE;
160     msa_ptr->success = true;
161 }
162
163 bool decide_lite_projection(player_type *target_ptr, msa_type *msa_ptr)
164 {
165     if (projectable(target_ptr, msa_ptr->m_ptr->fy, msa_ptr->m_ptr->fx, msa_ptr->y, msa_ptr->x)) {
166         feature_projection(target_ptr->current_floor_ptr, msa_ptr);
167         return true;
168     }
169
170     msa_ptr->success = false;
171     check_lite_area_by_mspell(target_ptr, msa_ptr);
172     if (!msa_ptr->success)
173         msa_ptr->success = adjacent_grid_check(target_ptr, msa_ptr->m_ptr, &msa_ptr->y, &msa_ptr->x, FF_PROJECT, projectable);
174
175     decide_lite_breath(target_ptr, msa_ptr);
176     return msa_ptr->success;
177 }
178
179 void decide_lite_area(player_type *target_ptr, msa_type *msa_ptr)
180 {
181     if (msa_ptr->ability_flags.has_not(RF_ABILITY::DARKNESS))
182         return;
183
184     bool can_use_lite_area = (target_ptr->pclass == CLASS_NINJA) && ((msa_ptr->r_ptr->flags3 & (RF3_UNDEAD | RF3_HURT_LITE)) == 0)
185         && ((msa_ptr->r_ptr->flags7 & RF7_DARK_MASK) == 0);
186
187     if ((msa_ptr->r_ptr->flags2 & RF2_STUPID) != 0)
188         return;
189
190     if (d_info[target_ptr->dungeon_idx].flags.has(DF::DARKNESS)) {
191         msa_ptr->ability_flags.reset(RF_ABILITY::DARKNESS);
192         return;
193     }
194
195     if ((target_ptr->pclass == CLASS_NINJA) && !can_use_lite_area)
196         msa_ptr->ability_flags.reset(RF_ABILITY::DARKNESS);
197 }