OSDN Git Service

[WIP] [Refcator] #3287 PlayerType::window_flags に関わる処理を、RedrawingFlagsUpdater に集約した
[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/baseitem-info.h"
33 #include "system/dungeon-info.h"
34 #include "system/floor-type-definition.h"
35 #include "system/grid-type-definition.h"
36 #include "system/item-entity.h"
37 #include "system/monster-entity.h"
38 #include "system/monster-race-info.h"
39 #include "system/player-type-definition.h"
40 #include "system/redrawing-flags-updater.h"
41 #include "system/terrain-type-definition.h"
42 #include "util/bit-flags-calculator.h"
43 #include "view/display-messages.h"
44 #include "world/world.h"
45
46 static void update_sun_light(PlayerType *player_ptr)
47 {
48     auto &rfu = RedrawingFlagsUpdater::get_instance();
49     const auto flags_srf = {
50         StatusRedrawingFlag::MONSTER_STATUSES,
51         StatusRedrawingFlag::MONSTER_LITE,
52     };
53     rfu.set_flags(flags_srf);
54     rfu.set_flag(MainWindowRedrawingFlag::MAP);
55     const auto flags = {
56         SubWindowRedrawingFlag::OVERHEAD,
57         SubWindowRedrawingFlag::DUNGEON,
58     };
59     rfu.set_flags(flags);
60     if ((player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].info & CAVE_GLOW) != 0) {
61         set_superstealth(player_ptr, false);
62     }
63 }
64
65 void day_break(PlayerType *player_ptr)
66 {
67     msg_print(_("夜が明けた。", "The sun has risen."));
68     auto *floor_ptr = player_ptr->current_floor_ptr;
69     if (player_ptr->wild_mode) {
70         update_sun_light(player_ptr);
71         return;
72     }
73
74     for (auto y = 0; y < floor_ptr->height; y++) {
75         for (auto x = 0; x < floor_ptr->width; x++) {
76             auto *g_ptr = &floor_ptr->grid_array[y][x];
77             g_ptr->info |= CAVE_GLOW;
78             if (view_perma_grids) {
79                 g_ptr->info |= CAVE_MARK;
80             }
81
82             note_spot(player_ptr, y, x);
83         }
84     }
85
86     update_sun_light(player_ptr);
87 }
88
89 void night_falls(PlayerType *player_ptr)
90 {
91     msg_print(_("日が沈んだ。", "The sun has fallen."));
92     auto *floor_ptr = player_ptr->current_floor_ptr;
93     if (player_ptr->wild_mode) {
94         update_sun_light(player_ptr);
95         return;
96     }
97
98     for (auto y = 0; y < floor_ptr->height; y++) {
99         for (auto x = 0; x < floor_ptr->width; x++) {
100             auto *g_ptr = &floor_ptr->grid_array[y][x];
101             auto *f_ptr = &terrains_info[g_ptr->get_feat_mimic()];
102             using Tc = TerrainCharacteristics;
103             if (g_ptr->is_mirror() || f_ptr->flags.has(Tc::QUEST_ENTER) || f_ptr->flags.has(Tc::ENTRANCE)) {
104                 continue;
105             }
106
107             g_ptr->info &= ~(CAVE_GLOW);
108             if (f_ptr->flags.has_not(Tc::REMEMBER)) {
109                 g_ptr->info &= ~(CAVE_MARK);
110                 note_spot(player_ptr, y, x);
111             }
112         }
113
114         glow_deep_lava_and_bldg(player_ptr);
115     }
116
117     update_sun_light(player_ptr);
118 }
119
120 /*!
121  * ダンジョンの雰囲気を計算するための非線形基準値 / Dungeon rating is no longer linear
122  */
123 static int rating_boost(int delta)
124 {
125     return delta * delta + 50 * delta;
126 }
127
128 /*!
129  * @brief ダンジョンの雰囲気を算出する。
130  * / Examine all monsters and unidentified objects, and get the feeling of current dungeon floor
131  * @return 算出されたダンジョンの雰囲気ランク
132  */
133 static byte get_dungeon_feeling(PlayerType *player_ptr)
134 {
135     auto *floor_ptr = player_ptr->current_floor_ptr;
136     if (!floor_ptr->dun_level) {
137         return 0;
138     }
139
140     const int base = 10;
141     int rating = 0;
142     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
143         auto *m_ptr = &floor_ptr->m_list[i];
144         MonsterRaceInfo *r_ptr;
145         int delta = 0;
146         if (!m_ptr->is_valid() || m_ptr->is_pet()) {
147             continue;
148         }
149
150         r_ptr = &monraces_info[m_ptr->r_idx];
151         if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
152             if (r_ptr->level + 10 > floor_ptr->dun_level) {
153                 delta += (r_ptr->level + 10 - floor_ptr->dun_level) * 2 * base;
154             }
155         } else if (r_ptr->level > floor_ptr->dun_level) {
156             delta += (r_ptr->level - floor_ptr->dun_level) * base;
157         }
158
159         if (r_ptr->flags1 & RF1_FRIENDS) {
160             if (5 <= get_monster_crowd_number(floor_ptr, i)) {
161                 delta += 1;
162             }
163         } else if (2 <= get_monster_crowd_number(floor_ptr, i)) {
164             delta += 1;
165         }
166
167         rating += rating_boost(delta);
168     }
169
170     for (MONSTER_IDX i = 1; i < floor_ptr->o_max; i++) {
171         auto *o_ptr = &floor_ptr->o_list[i];
172         int delta = 0;
173         if (!o_ptr->is_valid() || (o_ptr->is_known() && o_ptr->marked.has(OmType::TOUCHED)) || ((o_ptr->ident & IDENT_SENSE) != 0)) {
174             continue;
175         }
176
177         if (o_ptr->is_ego()) {
178             const auto &ego = o_ptr->get_ego();
179             delta += ego.rating * base;
180         }
181
182         if (o_ptr->is_fixed_or_random_artifact()) {
183             PRICE cost = object_value_real(o_ptr);
184             delta += 10 * base;
185             if (cost > 10000L) {
186                 delta += 10 * base;
187             }
188
189             if (cost > 50000L) {
190                 delta += 10 * base;
191             }
192
193             if (cost > 100000L) {
194                 delta += 10 * base;
195             }
196
197             if (!preserve_mode) {
198                 return 1;
199             }
200         }
201
202         if (o_ptr->bi_key.tval() == ItemKindType::DRAG_ARMOR) {
203             delta += 30 * base;
204         }
205
206         if (o_ptr->bi_key == BaseitemKey(ItemKindType::SHIELD, SV_DRAGON_SHIELD)) {
207             delta += 5 * base;
208         }
209
210         if (o_ptr->bi_key == BaseitemKey(ItemKindType::GLOVES, SV_SET_OF_DRAGON_GLOVES)) {
211             delta += 5 * base;
212         }
213
214         if (o_ptr->bi_key == BaseitemKey(ItemKindType::BOOTS, SV_PAIR_OF_DRAGON_GREAVE)) {
215             delta += 5 * base;
216         }
217
218         if (o_ptr->bi_key == BaseitemKey(ItemKindType::HELM, SV_DRAGON_HELM)) {
219             delta += 5 * base;
220         }
221
222         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_SPEED) && !o_ptr->is_cursed()) {
223             delta += 25 * base;
224         }
225
226         if (o_ptr->bi_key == BaseitemKey(ItemKindType::RING, SV_RING_LORDLY) && !o_ptr->is_cursed()) {
227             delta += 15 * base;
228         }
229
230         if (o_ptr->bi_key == BaseitemKey(ItemKindType::AMULET, SV_AMULET_THE_MAGI) && !o_ptr->is_cursed()) {
231             delta += 15 * base;
232         }
233
234         const auto &baseitem = o_ptr->get_baseitem();
235         if (!o_ptr->is_cursed() && !o_ptr->is_broken() && baseitem.level > floor_ptr->dun_level) {
236             delta += (baseitem.level - floor_ptr->dun_level) * base;
237         }
238
239         rating += rating_boost(delta);
240     }
241
242     if (rating > rating_boost(1000)) {
243         return 2;
244     }
245
246     if (rating > rating_boost(800)) {
247         return 3;
248     }
249
250     if (rating > rating_boost(600)) {
251         return 4;
252     }
253
254     if (rating > rating_boost(400)) {
255         return 5;
256     }
257
258     if (rating > rating_boost(300)) {
259         return 6;
260     }
261
262     if (rating > rating_boost(200)) {
263         return 7;
264     }
265
266     if (rating > rating_boost(100)) {
267         return 8;
268     }
269
270     if (rating > rating_boost(0)) {
271         return 9;
272     }
273
274     return 10;
275 }
276
277 /*!
278  * @brief ダンジョンの雰囲気を更新し、変化があった場合メッセージを表示する
279  * / Update dungeon feeling, and announce it if changed
280  */
281 void update_dungeon_feeling(PlayerType *player_ptr)
282 {
283     const auto &floor = *player_ptr->current_floor_ptr;
284     if (!floor.dun_level) {
285         return;
286     }
287
288     if (player_ptr->phase_out) {
289         return;
290     }
291
292     int delay = std::max(10, 150 - player_ptr->skill_fos) * (150 - floor.dun_level) * TURNS_PER_TICK / 100;
293     if (w_ptr->game_turn < player_ptr->feeling_turn + delay && !cheat_xtra) {
294         return;
295     }
296
297     auto quest_num = quest_number(floor, floor.dun_level);
298     const auto &quest_list = QuestList::get_instance();
299
300     auto dungeon_quest = (quest_num == QuestId::OBERON);
301     dungeon_quest |= (quest_num == QuestId::SERPENT);
302     dungeon_quest |= !(quest_list[quest_num].flags & QUEST_FLAG_PRESET);
303
304     auto feeling_quest = inside_quest(quest_num);
305     feeling_quest &= QuestType::is_fixed(quest_num);
306     feeling_quest &= !dungeon_quest;
307     if (feeling_quest) {
308         return;
309     }
310     byte new_feeling = get_dungeon_feeling(player_ptr);
311     player_ptr->feeling_turn = w_ptr->game_turn;
312     if (player_ptr->feeling == new_feeling) {
313         return;
314     }
315
316     player_ptr->feeling = new_feeling;
317     do_cmd_feeling(player_ptr);
318     select_floor_music(player_ptr);
319     RedrawingFlagsUpdater::get_instance().set_flag(MainWindowRedrawingFlag::DEPTH);
320     if (disturb_minor) {
321         disturb(player_ptr, false, false);
322     }
323 }
324
325 /*
326  * Glow deep lava and building entrances in the floor
327  */
328 void glow_deep_lava_and_bldg(PlayerType *player_ptr)
329 {
330     auto *floor_ptr = player_ptr->current_floor_ptr;
331     if (dungeons_info[floor_ptr->dungeon_idx].flags.has(DungeonFeatureType::DARKNESS)) {
332         return;
333     }
334
335     for (POSITION y = 0; y < floor_ptr->height; y++) {
336         for (POSITION x = 0; x < floor_ptr->width; x++) {
337             grid_type *g_ptr;
338             g_ptr = &floor_ptr->grid_array[y][x];
339             if (terrains_info[g_ptr->get_feat_mimic()].flags.has_not(TerrainCharacteristics::GLOW)) {
340                 continue;
341             }
342
343             for (DIRECTION i = 0; i < 9; i++) {
344                 POSITION yy = y + ddy_ddd[i];
345                 POSITION xx = x + ddx_ddd[i];
346                 if (!in_bounds2(floor_ptr, yy, xx)) {
347                     continue;
348                 }
349
350                 floor_ptr->grid_array[yy][xx].info |= CAVE_GLOW;
351             }
352         }
353     }
354
355     auto &rfu = RedrawingFlagsUpdater::get_instance();
356     const auto flags_srf = {
357         StatusRedrawingFlag::VIEW,
358         StatusRedrawingFlag::LITE,
359         StatusRedrawingFlag::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_type *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 }