OSDN Git Service

Merge pull request #3721 from daradarach/feature/nodequest
[hengbandforosx/hengbandosx.git] / src / floor / floor-events.cpp
1 #include "floor/floor-events.h"
2 #include "cmd-io/cmd-dump.h"
3 #include "core/disturbance.h"
4 #include "core/window-redrawer.h"
5 #include "dungeon/dungeon-flag-types.h"
6 #include "dungeon/quest.h"
7 #include "floor/cave.h"
8 #include "floor/geometry.h"
9 #include "game-option/birth-options.h"
10 #include "game-option/cheat-options.h"
11 #include "game-option/disturbance-options.h"
12 #include "game-option/map-screen-options.h"
13 #include "grid/feature-flag-types.h"
14 #include "grid/grid.h"
15 #include "main/sound-of-music.h"
16 #include "mind/mind-ninja.h"
17 #include "monster-race/monster-race.h"
18 #include "monster-race/race-flags1.h"
19 #include "monster/monster-info.h"
20 #include "monster/monster-list.h"
21 #include "monster/monster-status.h"
22 #include "object-enchant/object-ego.h"
23 #include "object-enchant/special-object-flags.h"
24 #include "object/object-mark-types.h"
25 #include "object/object-value.h"
26 #include "object/tval-types.h"
27 #include "perception/object-perception.h"
28 #include "player/special-defense-types.h"
29 #include "sv-definition/sv-amulet-types.h"
30 #include "sv-definition/sv-protector-types.h"
31 #include "sv-definition/sv-ring-types.h"
32 #include "system/angband-system.h"
33 #include "system/baseitem-info.h"
34 #include "system/dungeon-info.h"
35 #include "system/floor-type-definition.h"
36 #include "system/grid-type-definition.h"
37 #include "system/item-entity.h"
38 #include "system/monster-entity.h"
39 #include "system/monster-race-info.h"
40 #include "system/player-type-definition.h"
41 #include "system/redrawing-flags-updater.h"
42 #include "system/terrain-type-definition.h"
43 #include "util/bit-flags-calculator.h"
44 #include "view/display-messages.h"
45 #include "world/world.h"
46
47 static void update_sun_light(PlayerType *player_ptr)
48 {
49     auto &rfu = RedrawingFlagsUpdater::get_instance();
50     static constexpr auto flags_srf = {
51         StatusRecalculatingFlag::MONSTER_STATUSES,
52         StatusRecalculatingFlag::MONSTER_LITE,
53     };
54     rfu.set_flags(flags_srf);
55     rfu.set_flag(MainWindowRedrawingFlag::MAP);
56     static constexpr auto flags = {
57         SubWindowRedrawingFlag::OVERHEAD,
58         SubWindowRedrawingFlag::DUNGEON,
59     };
60     rfu.set_flags(flags);
61     if ((player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) != 0) {
62         set_superstealth(player_ptr, false);
63     }
64 }
65
66 void day_break(PlayerType *player_ptr)
67 {
68     msg_print(_("夜が明けた。", "The sun has risen."));
69     auto *floor_ptr = player_ptr->current_floor_ptr;
70     if (player_ptr->wild_mode) {
71         update_sun_light(player_ptr);
72         return;
73     }
74
75     for (auto y = 0; y < floor_ptr->height; y++) {
76         for (auto x = 0; x < floor_ptr->width; x++) {
77             auto *g_ptr = &floor_ptr->grid_array[y][x];
78             g_ptr->info |= CAVE_GLOW;
79             if (view_perma_grids) {
80                 g_ptr->info |= CAVE_MARK;
81             }
82
83             note_spot(player_ptr, y, x);
84         }
85     }
86
87     update_sun_light(player_ptr);
88 }
89
90 void night_falls(PlayerType *player_ptr)
91 {
92     msg_print(_("日が沈んだ。", "The sun has fallen."));
93     if (player_ptr->wild_mode) {
94         update_sun_light(player_ptr);
95         return;
96     }
97
98     auto &floor = *player_ptr->current_floor_ptr;
99     for (auto y = 0; y < floor.height; y++) {
100         for (auto x = 0; x < floor.width; x++) {
101             const Pos2D pos(y, x);
102             auto &grid = floor.get_grid(pos);
103             const auto &terrain = grid.get_terrain_mimic();
104             using Tc = TerrainCharacteristics;
105             if (grid.is_mirror() || terrain.flags.has(Tc::QUEST_ENTER) || terrain.flags.has(Tc::ENTRANCE)) {
106                 continue;
107             }
108
109             grid.info &= ~(CAVE_GLOW);
110             if (terrain.flags.has_not(Tc::REMEMBER)) {
111                 grid.info &= ~(CAVE_MARK);
112                 note_spot(player_ptr, y, x);
113             }
114         }
115
116         glow_deep_lava_and_bldg(player_ptr);
117     }
118
119     update_sun_light(player_ptr);
120 }
121
122 /*!
123  * ダンジョンの雰囲気を計算するための非線形基準値 / Dungeon rating is no longer linear
124  */
125 static int rating_boost(int delta)
126 {
127     return delta * delta + 50 * delta;
128 }
129
130 /*!
131  * @brief ダンジョンの雰囲気を算出する。
132  * / Examine all monsters and unidentified objects, and get the feeling of current dungeon floor
133  * @return 算出されたダンジョンの雰囲気ランク
134  */
135 static byte get_dungeon_feeling(PlayerType *player_ptr)
136 {
137     auto *floor_ptr = player_ptr->current_floor_ptr;
138     if (!floor_ptr->dun_level) {
139         return 0;
140     }
141
142     const int base = 10;
143     int rating = 0;
144     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
145         auto *m_ptr = &floor_ptr->m_list[i];
146         MonsterRaceInfo *r_ptr;
147         int delta = 0;
148         if (!m_ptr->is_valid() || m_ptr->is_pet()) {
149             continue;
150         }
151
152         r_ptr = &m_ptr->get_monrace();
153         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
154             if (r_ptr->level + 10 > floor_ptr->dun_level) {
155                 delta += (r_ptr->level + 10 - floor_ptr->dun_level) * 2 * base;
156             }
157         } else if (r_ptr->level > floor_ptr->dun_level) {
158             delta += (r_ptr->level - floor_ptr->dun_level) * base;
159         }
160
161         if (r_ptr->flags1 & RF1_FRIENDS) {
162             if (5 <= get_monster_crowd_number(floor_ptr, i)) {
163                 delta += 1;
164             }
165         } else if (2 <= get_monster_crowd_number(floor_ptr, i)) {
166             delta += 1;
167         }
168
169         rating += rating_boost(delta);
170     }
171
172     for (MONSTER_IDX i = 1; i < floor_ptr->o_max; i++) {
173         auto *o_ptr = &floor_ptr->o_list[i];
174         int delta = 0;
175         if (!o_ptr->is_valid() || (o_ptr->is_known() && o_ptr->marked.has(OmType::TOUCHED)) || ((o_ptr->ident & IDENT_SENSE) != 0)) {
176             continue;
177         }
178
179         if (o_ptr->is_ego()) {
180             const auto &ego = o_ptr->get_ego();
181             delta += ego.rating * base;
182         }
183
184         if (o_ptr->is_fixed_or_random_artifact()) {
185             PRICE cost = object_value_real(o_ptr);
186             delta += 10 * base;
187             if (cost > 10000L) {
188                 delta += 10 * base;
189             }
190
191             if (cost > 50000L) {
192                 delta += 10 * base;
193             }
194
195             if (cost > 100000L) {
196                 delta += 10 * base;
197             }
198
199             if (!preserve_mode) {
200                 return 1;
201             }
202         }
203
204         if (o_ptr->bi_key.tval() == ItemKindType::DRAG_ARMOR) {
205             delta += 30 * base;
206         }
207
208         if (o_ptr->bi_key == BaseitemKey(ItemKindType::SHIELD, SV_DRAGON_SHIELD)) {
209             delta += 5 * base;
210         }
211
212         if (o_ptr->bi_key == BaseitemKey(ItemKindType::GLOVES, SV_SET_OF_DRAGON_GLOVES)) {
213             delta += 5 * base;
214         }
215
216         if (o_ptr->bi_key == BaseitemKey(ItemKindType::BOOTS, SV_PAIR_OF_DRAGON_GREAVE)) {
217             delta += 5 * base;
218         }
219
220         if (o_ptr->bi_key == BaseitemKey(ItemKindType::HELM, SV_DRAGON_HELM)) {
221             delta += 5 * base;
222         }
223
224         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_SPEED) && !o_ptr->is_cursed()) {
225             delta += 25 * base;
226         }
227
228         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_LORDLY) && !o_ptr->is_cursed()) {
229             delta += 15 * base;
230         }
231
232         if (o_ptr->bi_key == BaseitemKey(ItemKindType::AMULET, SV_AMULET_THE_MAGI) && !o_ptr->is_cursed()) {
233             delta += 15 * base;
234         }
235
236         const auto &baseitem = o_ptr->get_baseitem();
237         if (!o_ptr->is_cursed() && !o_ptr->is_broken() && baseitem.level > floor_ptr->dun_level) {
238             delta += (baseitem.level - floor_ptr->dun_level) * base;
239         }
240
241         rating += rating_boost(delta);
242     }
243
244     if (rating > rating_boost(1000)) {
245         return 2;
246     }
247
248     if (rating > rating_boost(800)) {
249         return 3;
250     }
251
252     if (rating > rating_boost(600)) {
253         return 4;
254     }
255
256     if (rating > rating_boost(400)) {
257         return 5;
258     }
259
260     if (rating > rating_boost(300)) {
261         return 6;
262     }
263
264     if (rating > rating_boost(200)) {
265         return 7;
266     }
267
268     if (rating > rating_boost(100)) {
269         return 8;
270     }
271
272     if (rating > rating_boost(0)) {
273         return 9;
274     }
275
276     return 10;
277 }
278
279 /*!
280  * @brief ダンジョンの雰囲気を更新し、変化があった場合メッセージを表示する
281  * / Update dungeon feeling, and announce it if changed
282  */
283 void update_dungeon_feeling(PlayerType *player_ptr)
284 {
285     const auto &floor = *player_ptr->current_floor_ptr;
286     if (!floor.dun_level) {
287         return;
288     }
289
290     if (AngbandSystem::get_instance().is_phase_out()) {
291         return;
292     }
293
294     int delay = std::max(10, 150 - player_ptr->skill_fos) * (150 - floor.dun_level) * TURNS_PER_TICK / 100;
295     if (w_ptr->game_turn < player_ptr->feeling_turn + delay && !cheat_xtra) {
296         return;
297     }
298
299     auto quest_num = floor.get_quest_id();
300     const auto &quest_list = QuestList::get_instance();
301
302     auto dungeon_quest = (quest_num == QuestId::OBERON);
303     dungeon_quest |= (quest_num == QuestId::SERPENT);
304     dungeon_quest |= !(quest_list[quest_num].flags & QUEST_FLAG_PRESET);
305
306     auto feeling_quest = inside_quest(quest_num);
307     feeling_quest &= QuestType::is_fixed(quest_num);
308     feeling_quest &= !dungeon_quest;
309     if (feeling_quest) {
310         return;
311     }
312     byte new_feeling = get_dungeon_feeling(player_ptr);
313     player_ptr->feeling_turn = w_ptr->game_turn;
314     if (player_ptr->feeling == new_feeling) {
315         return;
316     }
317
318     player_ptr->feeling = new_feeling;
319     do_cmd_feeling(player_ptr);
320     select_floor_music(player_ptr);
321     RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::DEPTH);
322     if (disturb_minor) {
323         disturb(player_ptr, false, false);
324     }
325 }
326
327 /*
328  * Glow deep lava and building entrances in the floor
329  */
330 void glow_deep_lava_and_bldg(PlayerType *player_ptr)
331 {
332     auto &floor = *player_ptr->current_floor_ptr;
333     if (floor.get_dungeon_definition().flags.has(DungeonFeatureType::DARKNESS)) {
334         return;
335     }
336
337     for (auto y = 0; y < floor.height; y++) {
338         for (auto x = 0; x < floor.width; x++) {
339             const auto &grid = floor.get_grid({ y, x });
340             if (grid.get_terrain_mimic().flags.has_not(TerrainCharacteristics::GLOW)) {
341                 continue;
342             }
343
344             for (auto i = 0; i < 9; i++) {
345                 const Pos2D pos(y + ddy_ddd[i], x + ddx_ddd[i]);
346                 if (!in_bounds2(&floor, pos.y, pos.x)) {
347                     continue;
348                 }
349
350                 floor.get_grid(pos).info |= CAVE_GLOW;
351             }
352         }
353     }
354
355     auto &rfu = RedrawingFlagsUpdater::get_instance();
356     static constexpr auto flags_srf = {
357         StatusRecalculatingFlag::VIEW,
358         StatusRecalculatingFlag::LITE,
359         StatusRecalculatingFlag::MONSTER_LITE,
360     };
361     rfu.set_flags(flags_srf);
362     rfu.set_flag(MainWindowRedrawingFlag::MAP);
363 }
364
365 /*
366  * Actually erase the entire "lite" array, redrawing every grid
367  */
368 void forget_lite(FloorType *floor_ptr)
369 {
370     if (!floor_ptr->lite_n) {
371         return;
372     }
373
374     for (int i = 0; i < floor_ptr->lite_n; i++) {
375         POSITION y = floor_ptr->lite_y[i];
376         POSITION x = floor_ptr->lite_x[i];
377         floor_ptr->grid_array[y][x].info &= ~(CAVE_LITE);
378     }
379
380     floor_ptr->lite_n = 0;
381 }
382
383 /*
384  * Clear the viewable space
385  */
386 void forget_view(FloorType *floor_ptr)
387 {
388     if (!floor_ptr->view_n) {
389         return;
390     }
391
392     for (int i = 0; i < floor_ptr->view_n; i++) {
393         POSITION y = floor_ptr->view_y[i];
394         POSITION x = floor_ptr->view_x[i];
395         Grid *g_ptr;
396         g_ptr = &floor_ptr->grid_array[y][x];
397         g_ptr->info &= ~(CAVE_VIEW);
398     }
399
400     floor_ptr->view_n = 0;
401 }