OSDN Git Service

[Refactor] struct player_type を class PlayerType に置換。
[hengbandforosx/hengbandosx.git] / src / specific-object / torch.cpp
1 #include "specific-object/torch.h"
2 #include "core/player-update-types.h"
3 #include "dungeon/dungeon-flag-types.h"
4 #include "dungeon/dungeon.h"
5 #include "floor/cave.h"
6 #include "grid/grid.h"
7 #include "inventory/inventory-slot-types.h"
8 #include "mind/mind-ninja.h"
9 #include "object-enchant/object-ego.h"
10 #include "object-enchant/tr-types.h"
11 #include "object/object-flags.h"
12 #include "player/special-defense-types.h"
13 #include "sv-definition/sv-lite-types.h"
14 #include "system/floor-type-definition.h"
15 #include "system/grid-type-definition.h"
16 #include "system/object-type-definition.h"
17 #include "system/player-type-definition.h"
18 #include "util/bit-flags-calculator.h"
19 #include "util/point-2d.h"
20 #include <vector>
21
22 /*!
23  * @brief 該当オブジェクトが残量アリの松明か否かを判定。
24  * @param o_ptr オブジェクトの構造体参照ポインタ
25  * @return 残量アリの松明ならtrue
26  */
27 bool is_active_torch(object_type *o_ptr)
28 {
29     return (o_ptr->tval == ItemKindType::LITE) && (o_ptr->sval == SV_LITE_TORCH) && (o_ptr->xtra4 > 0);
30 }
31
32 /*!
33  * @brief 投擲時たいまつに投げやすい/焼棄/アンデッドスレイの特別効果を返す。
34  * Torches have special abilities when they are flaming.
35  * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
36  * @param flgs 特別に追加するフラグを返す参照ポインタ
37  */
38 void torch_flags(object_type *o_ptr, TrFlags &flgs)
39 {
40     if (!is_active_torch(o_ptr))
41         return;
42
43     flgs.set(TR_BRAND_FIRE);
44     flgs.set(TR_KILL_UNDEAD);
45     flgs.set(TR_THROW);
46 }
47
48 /*!
49  * @brief 投擲時たいまつにダイスを与える。
50  * Torches have special abilities when they are flaming.
51  * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
52  * @param dd 特別なダイス数を返す参照ポインタ
53  * @param ds 特別なダイス面数を返す参照ポインタ
54  */
55 void torch_dice(object_type *o_ptr, DICE_NUMBER *dd, DICE_SID *ds)
56 {
57     if (!is_active_torch(o_ptr))
58         return;
59
60     *dd = 1;
61     *ds = 6;
62 }
63
64 /*!
65  * @brief 投擲時命中したたいまつの寿命を縮める。
66  * Torches have special abilities when they are flaming.
67  * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
68  */
69 void torch_lost_fuel(object_type *o_ptr)
70 {
71     if (!is_active_torch(o_ptr))
72         return;
73
74     o_ptr->xtra4 -= (FUEL_TORCH / 25);
75     if (o_ptr->xtra4 < 0)
76         o_ptr->xtra4 = 0;
77 }
78
79 /*!
80  * @brief プレイヤーの光源半径を計算する / Extract and set the current "lite radius"
81  * @details
82  * SWD: Experimental modification: multiple light sources have additive effect.
83  */
84 void update_lite_radius(PlayerType *player_ptr)
85 {
86     player_ptr->cur_lite = 0;
87     for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
88         object_type *o_ptr;
89         o_ptr = &player_ptr->inventory_list[i];
90         auto flgs = object_flags(o_ptr);
91
92         if (!o_ptr->k_idx)
93             continue;
94
95         if (o_ptr->name2 == EGO_LITE_SHINE)
96             player_ptr->cur_lite++;
97
98         if (flgs.has_not(TR_DARK_SOURCE)) {
99             if (o_ptr->tval == ItemKindType::LITE) {
100                 if ((o_ptr->sval == SV_LITE_TORCH) && !(o_ptr->xtra4 > 0))
101                     continue;
102
103                 if ((o_ptr->sval == SV_LITE_LANTERN) && !(o_ptr->xtra4 > 0))
104                     continue;
105             }
106         }
107
108         POSITION rad = 0;
109         if (flgs.has(TR_LITE_1) && flgs.has_not(TR_DARK_SOURCE))
110             rad += 1;
111
112         if (flgs.has(TR_LITE_2) && flgs.has_not(TR_DARK_SOURCE))
113             rad += 2;
114
115         if (flgs.has(TR_LITE_3) && flgs.has_not(TR_DARK_SOURCE))
116             rad += 3;
117
118         if (flgs.has(TR_LITE_M1))
119             rad -= 1;
120
121         if (flgs.has(TR_LITE_M2))
122             rad -= 2;
123
124         if (flgs.has(TR_LITE_M3))
125             rad -= 3;
126
127         player_ptr->cur_lite += rad;
128     }
129
130     if (d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS) && player_ptr->cur_lite > 1)
131         player_ptr->cur_lite = 1;
132
133     if (player_ptr->cur_lite <= 0 && player_ptr->lite)
134         player_ptr->cur_lite++;
135
136     if (player_ptr->cur_lite > 14)
137         player_ptr->cur_lite = 14;
138
139     if (player_ptr->cur_lite < 0)
140         player_ptr->cur_lite = 0;
141
142     if (player_ptr->old_lite == player_ptr->cur_lite)
143         return;
144
145     player_ptr->update |= PU_LITE | PU_MON_LITE | PU_MONSTERS;
146     player_ptr->old_lite = player_ptr->cur_lite;
147
148     if (player_ptr->cur_lite > 0) {
149         set_superstealth(player_ptr, false);
150     }
151 }
152
153 /*
154  * Update the set of grids "illuminated" by the player's lite.
155  *
156  * This routine needs to use the results of "update_view()"
157  *
158  * Note that "blindness" does NOT affect "torch lite".  Be careful!
159  *
160  * We optimize most lites (all non-artifact lites) by using "obvious"
161  * facts about the results of "small" lite radius, and we attempt to
162  * list the "nearby" grids before the more "distant" ones in the
163  * array of torch-lit grids.
164  *
165  * We assume that "radius zero" lite is in fact no lite at all.
166  *
167  *     Torch     Lantern     Artifacts
168  *     (etc)
169  *                              ***
170  *                 ***         *****
171  *      ***       *****       *******
172  *      *@*       **@**       ***@***
173  *      ***       *****       *******
174  *                 ***         *****
175  *                              ***
176  */
177 void update_lite(PlayerType *player_ptr)
178 {
179     // 前回照らされていた座標たちを格納する配列。
180     std::vector<Pos2D> points;
181
182     POSITION p = player_ptr->cur_lite;
183     floor_type *const floor_ptr = player_ptr->current_floor_ptr;
184
185     // 前回照らされていた座標たちを記録。
186     for (int i = 0; i < floor_ptr->lite_n; i++) {
187         const POSITION y = floor_ptr->lite_y[i];
188         const POSITION x = floor_ptr->lite_x[i];
189
190         floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
191         floor_ptr->grid_array[y][x].info |= CAVE_TEMP;
192
193         points.emplace_back(y, x);
194     }
195
196     floor_ptr->lite_n = 0;
197     if (p >= 1) {
198         cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x);
199         cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x);
200         cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x);
201         cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x + 1);
202         cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x - 1);
203         cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x + 1);
204         cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x - 1);
205         cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x + 1);
206         cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x - 1);
207     }
208
209     if (p >= 2) {
210         if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x)) {
211             cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x);
212             cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x + 1);
213             cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x - 1);
214         }
215
216         if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x)) {
217             cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x);
218             cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x + 1);
219             cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x - 1);
220         }
221
222         if (cave_los_bold(floor_ptr, player_ptr->y, player_ptr->x + 1)) {
223             cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x + 2);
224             cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x + 2);
225             cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x + 2);
226         }
227
228         if (cave_los_bold(floor_ptr, player_ptr->y, player_ptr->x - 1)) {
229             cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x - 2);
230             cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x - 2);
231             cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x - 2);
232         }
233     }
234
235     if (p >= 3) {
236         int d;
237         if (p > 14)
238             p = 14;
239
240         if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x + 1))
241             cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x + 2);
242
243         if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x - 1))
244             cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x - 2);
245
246         if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x + 1))
247             cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x + 2);
248
249         if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x - 1))
250             cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x - 2);
251
252         POSITION min_y = player_ptr->y - p;
253         if (min_y < 0)
254             min_y = 0;
255
256         POSITION max_y = player_ptr->y + p;
257         if (max_y > floor_ptr->height - 1)
258             max_y = floor_ptr->height - 1;
259
260         POSITION min_x = player_ptr->x - p;
261         if (min_x < 0)
262             min_x = 0;
263
264         POSITION max_x = player_ptr->x + p;
265         if (max_x > floor_ptr->width - 1)
266             max_x = floor_ptr->width - 1;
267
268         for (POSITION y = min_y; y <= max_y; y++) {
269             for (POSITION x = min_x; x <= max_x; x++) {
270                 int dy = (player_ptr->y > y) ? (player_ptr->y - y) : (y - player_ptr->y);
271                 int dx = (player_ptr->x > x) ? (player_ptr->x - x) : (x - player_ptr->x);
272                 if ((dy <= 2) && (dx <= 2))
273                     continue;
274
275                 d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
276                 if (d > p)
277                     continue;
278
279                 if (floor_ptr->grid_array[y][x].info & CAVE_VIEW)
280                     cave_lite_hack(floor_ptr, y, x);
281             }
282         }
283     }
284
285     for (int i = 0; i < floor_ptr->lite_n; i++) {
286         POSITION y = floor_ptr->lite_y[i];
287         POSITION x = floor_ptr->lite_x[i];
288         grid_type *g_ptr = &floor_ptr->grid_array[y][x];
289         if (g_ptr->info & CAVE_TEMP)
290             continue;
291
292         cave_note_and_redraw_later(floor_ptr, y, x);
293     }
294
295     // 前回照らされていた座標たちのうち、状態が変わったものについて再描画フラグを立てる。
296     for (const auto &[y, x] : points) {
297         grid_type *g_ptr = &floor_ptr->grid_array[y][x];
298         g_ptr->info &= ~(CAVE_TEMP);
299         if (g_ptr->info & CAVE_LITE)
300             continue;
301
302         cave_redraw_later(floor_ptr, y, x);
303     }
304
305     player_ptr->update |= PU_DELAY_VIS;
306 }