1 #include "specific-object/torch.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "floor/cave.h"
5 #include "inventory/inventory-slot-types.h"
6 #include "mind/mind-ninja.h"
7 #include "object-enchant/object-ego.h"
8 #include "object-enchant/tr-types.h"
9 #include "object/tval-types.h"
10 #include "player/special-defense-types.h"
11 #include "sv-definition/sv-lite-types.h"
12 #include "system/dungeon-info.h"
13 #include "system/floor-type-definition.h"
14 #include "system/grid-type-definition.h"
15 #include "system/item-entity.h"
16 #include "system/player-type-definition.h"
17 #include "system/redrawing-flags-updater.h"
18 #include "util/bit-flags-calculator.h"
19 #include "util/point-2d.h"
23 * @brief 該当オブジェクトが残量アリの松明か否かを判定。
24 * @param o_ptr オブジェクトの構造体参照ポインタ
25 * @return 残量アリの松明ならtrue
27 bool is_active_torch(ItemEntity *o_ptr)
29 return (o_ptr->bi_key == BaseitemKey(ItemKindType::LITE, SV_LITE_TORCH)) && (o_ptr->fuel > 0);
33 * @brief 投擲時たいまつに投げやすい/焼棄/アンデッドスレイの特別効果を返す。
34 * Torches have special abilities when they are flaming.
35 * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
36 * @param flags 特別に追加するフラグを返す参照ポインタ
38 void torch_flags(ItemEntity *o_ptr, TrFlags &flags)
40 if (!is_active_torch(o_ptr)) {
44 flags.set(TR_BRAND_FIRE);
45 flags.set(TR_KILL_UNDEAD);
50 * @brief 投擲時たいまつにダイスを与える。
51 * Torches have special abilities when they are flaming.
52 * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
53 * @param dd 特別なダイス数を返す参照ポインタ
54 * @param ds 特別なダイス面数を返す参照ポインタ
56 void torch_dice(ItemEntity *o_ptr, DICE_NUMBER *dd, DICE_SID *ds)
58 if (!is_active_torch(o_ptr)) {
67 * @brief 投擲時命中したたいまつの寿命を縮める。
68 * Torches have special abilities when they are flaming.
69 * @param o_ptr 投擲するオブジェクトの構造体参照ポインタ
71 void torch_lost_fuel(ItemEntity *o_ptr)
73 if (!is_active_torch(o_ptr)) {
77 o_ptr->fuel -= FUEL_TORCH / 25;
78 if (o_ptr->fuel < 0) {
84 * @brief プレイヤーの光源半径を計算する / Extract and set the current "lite radius"
86 * SWD: Experimental modification: multiple light sources have additive effect.
88 void update_lite_radius(PlayerType *player_ptr)
90 player_ptr->cur_lite = 0;
91 for (int i = INVEN_MAIN_HAND; i < INVEN_TOTAL; i++) {
92 const auto *o_ptr = &player_ptr->inventory_list[i];
93 if (!o_ptr->is_valid()) {
97 if (o_ptr->ego_idx == EgoType::LITE_SHINE) {
98 player_ptr->cur_lite++;
101 const auto flags = o_ptr->get_flags();
102 if (flags.has_not(TR_DARK_SOURCE)) {
103 if (o_ptr->bi_key.tval() == ItemKindType::LITE) {
104 const auto sval = o_ptr->bi_key.sval();
105 if ((sval == SV_LITE_TORCH) && (o_ptr->fuel <= 0)) {
109 if ((sval == SV_LITE_LANTERN) && (o_ptr->fuel <= 0)) {
116 if (flags.has(TR_LITE_1) && flags.has_not(TR_DARK_SOURCE)) {
120 if (flags.has(TR_LITE_2) && flags.has_not(TR_DARK_SOURCE)) {
124 if (flags.has(TR_LITE_3) && flags.has_not(TR_DARK_SOURCE)) {
128 if (flags.has(TR_LITE_M1)) {
132 if (flags.has(TR_LITE_M2)) {
136 if (flags.has(TR_LITE_M3)) {
140 player_ptr->cur_lite += rad;
143 if (player_ptr->current_floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS) && player_ptr->cur_lite > 1) {
144 player_ptr->cur_lite = 1;
147 if (player_ptr->cur_lite <= 0 && player_ptr->lite) {
148 player_ptr->cur_lite++;
151 if (player_ptr->cur_lite > 14) {
152 player_ptr->cur_lite = 14;
155 if (player_ptr->cur_lite < 0) {
156 player_ptr->cur_lite = 0;
159 if (player_ptr->old_lite == player_ptr->cur_lite) {
163 static constexpr auto flags = {
164 StatusRecalculatingFlag::LITE,
165 StatusRecalculatingFlag::MONSTER_LITE,
166 StatusRecalculatingFlag::MONSTER_STATUSES,
168 RedrawingFlagsUpdater::get_instance().set_flags(flags);
169 player_ptr->old_lite = player_ptr->cur_lite;
170 if (player_ptr->cur_lite > 0) {
171 set_superstealth(player_ptr, false);
176 * Update the set of grids "illuminated" by the player's lite.
178 * This routine needs to use the results of "update_view()"
180 * Note that "blindness" does NOT affect "torch lite". Be careful!
182 * We optimize most lites (all non-artifact lites) by using "obvious"
183 * facts about the results of "small" lite radius, and we attempt to
184 * list the "nearby" grids before the more "distant" ones in the
185 * array of torch-lit grids.
187 * We assume that "radius zero" lite is in fact no lite at all.
189 * Torch Lantern Artifacts
199 void update_lite(PlayerType *player_ptr)
201 // 前回照らされていた座標たちを格納する配列。
202 std::vector<Pos2D> points;
204 POSITION p = player_ptr->cur_lite;
205 FloorType *const floor_ptr = player_ptr->current_floor_ptr;
208 for (int i = 0; i < floor_ptr->lite_n; i++) {
209 const POSITION y = floor_ptr->lite_y[i];
210 const POSITION x = floor_ptr->lite_x[i];
212 floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
213 floor_ptr->grid_array[y][x].info |= CAVE_TEMP;
215 points.emplace_back(y, x);
218 floor_ptr->lite_n = 0;
220 cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x);
221 cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x);
222 cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x);
223 cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x + 1);
224 cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x - 1);
225 cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x + 1);
226 cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x - 1);
227 cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x + 1);
228 cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x - 1);
232 if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x)) {
233 cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x);
234 cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x + 1);
235 cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x - 1);
238 if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x)) {
239 cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x);
240 cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x + 1);
241 cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x - 1);
244 if (cave_los_bold(floor_ptr, player_ptr->y, player_ptr->x + 1)) {
245 cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x + 2);
246 cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x + 2);
247 cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x + 2);
250 if (cave_los_bold(floor_ptr, player_ptr->y, player_ptr->x - 1)) {
251 cave_lite_hack(floor_ptr, player_ptr->y, player_ptr->x - 2);
252 cave_lite_hack(floor_ptr, player_ptr->y + 1, player_ptr->x - 2);
253 cave_lite_hack(floor_ptr, player_ptr->y - 1, player_ptr->x - 2);
263 if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x + 1)) {
264 cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x + 2);
267 if (cave_los_bold(floor_ptr, player_ptr->y + 1, player_ptr->x - 1)) {
268 cave_lite_hack(floor_ptr, player_ptr->y + 2, player_ptr->x - 2);
271 if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x + 1)) {
272 cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x + 2);
275 if (cave_los_bold(floor_ptr, player_ptr->y - 1, player_ptr->x - 1)) {
276 cave_lite_hack(floor_ptr, player_ptr->y - 2, player_ptr->x - 2);
279 POSITION min_y = player_ptr->y - p;
284 POSITION max_y = player_ptr->y + p;
285 if (max_y > floor_ptr->height - 1) {
286 max_y = floor_ptr->height - 1;
289 POSITION min_x = player_ptr->x - p;
294 POSITION max_x = player_ptr->x + p;
295 if (max_x > floor_ptr->width - 1) {
296 max_x = floor_ptr->width - 1;
299 for (POSITION y = min_y; y <= max_y; y++) {
300 for (POSITION x = min_x; x <= max_x; x++) {
301 int dy = (player_ptr->y > y) ? (player_ptr->y - y) : (y - player_ptr->y);
302 int dx = (player_ptr->x > x) ? (player_ptr->x - x) : (x - player_ptr->x);
303 if ((dy <= 2) && (dx <= 2)) {
307 d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
312 if (floor_ptr->grid_array[y][x].info & CAVE_VIEW) {
313 cave_lite_hack(floor_ptr, y, x);
319 for (int i = 0; i < floor_ptr->lite_n; i++) {
320 POSITION y = floor_ptr->lite_y[i];
321 POSITION x = floor_ptr->lite_x[i];
322 auto *g_ptr = &floor_ptr->grid_array[y][x];
323 if (g_ptr->info & CAVE_TEMP) {
327 cave_note_and_redraw_later(floor_ptr, y, x);
330 // 前回照らされていた座標たちのうち、状態が変わったものについて再描画フラグを立てる。
331 for (const auto &[y, x] : points) {
332 auto *g_ptr = &floor_ptr->grid_array[y][x];
333 g_ptr->info &= ~(CAVE_TEMP);
334 if (g_ptr->info & CAVE_LITE) {
338 cave_redraw_later(floor_ptr, y, x);
341 RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::DELAY_VISIBILITY);