OSDN Git Service

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