OSDN Git Service

[Refactor] シーカーレイ、スーパーレイのコード簡略化のため PROJECT_MIRROR を追加
[hengbandforosx/hengbandosx.git] / src / monster / monster-util.cpp
1 #include "monster/monster-util.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "dungeon/quest.h"
5 #include "floor/wild.h"
6 #include "game-option/cheat-options.h"
7 #include "grid/feature.h"
8 #include "monster-race/monster-race-hook.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-ability-mask.h"
11 #include "monster-race/race-flags-resistance.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags7.h"
14 #include "monster-race/race-indice-types.h"
15 #include "spell/summon-types.h"
16 #include "system/alloc-entries.h"
17 #include "system/floor-type-definition.h"
18 #include "system/grid-type-definition.h"
19 #include "system/monster-race-definition.h"
20 #include "system/player-type-definition.h"
21 #include "util/bit-flags-calculator.h"
22 #include "view/display-messages.h"
23
24 enum dungeon_mode_type {
25     DUNGEON_MODE_AND = 1,
26     DUNGEON_MODE_NAND = 2,
27     DUNGEON_MODE_OR = 3,
28     DUNGEON_MODE_NOR = 4,
29 };
30
31 MONSTER_IDX hack_m_idx = 0; /* Hack -- see "process_monsters()" */
32 MONSTER_IDX hack_m_idx_ii = 0;
33
34 /*!
35  * @var chameleon_change_m_idx
36  * @brief カメレオンの変身先モンスターIDを受け渡すためのグローバル変数
37  * @todo 変数渡しの問題などもあるができればchameleon_change_m_idxのグローバル変数を除去し、関数引き渡しに移行すること
38  */
39 int chameleon_change_m_idx = 0;
40
41 /*!
42  * @var summon_specific_type
43  * @brief 召喚条件を指定するグローバル変数 / Hack -- the "type" of the current "summon specific"
44  * @todo summon_specific_typeグローバル変数の除去と関数引数への代替を行う
45  */
46 summon_type summon_specific_type = SUMMON_NONE;
47
48 /*!
49  * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
50  * @param player_ptr プレイヤーへの参照ポインタ
51  * @param r_idx チェックするモンスター種族ID
52  * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
53  */
54 static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_idx)
55 {
56     DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
57     dungeon_type *d_ptr = &d_info[d_idx];
58     auto *r_ptr = &r_info[r_idx];
59
60     if (d_ptr->flags.has(DungeonFeatureType::CHAMELEON)) {
61         if (chameleon_change_m_idx) {
62             return true;
63         }
64     }
65
66     if (d_ptr->flags.has(DungeonFeatureType::NO_MAGIC)) {
67         if (r_idx != MonsterRaceId::CHAMELEON && r_ptr->freq_spell && r_ptr->ability_flags.has_none_of(RF_ABILITY_NOMAGIC_MASK)) {
68             return false;
69         }
70     }
71
72     if (d_ptr->flags.has(DungeonFeatureType::NO_MELEE)) {
73         if (r_idx == MonsterRaceId::CHAMELEON) {
74             return true;
75         }
76         if (r_ptr->ability_flags.has_none_of(RF_ABILITY_BOLT_MASK | RF_ABILITY_BEAM_MASK | RF_ABILITY_BALL_MASK) && r_ptr->ability_flags.has_none_of(
77                                                                                                                         { MonsterAbilityType::CAUSE_1, MonsterAbilityType::CAUSE_2, MonsterAbilityType::CAUSE_3, MonsterAbilityType::CAUSE_4, MonsterAbilityType::MIND_BLAST, MonsterAbilityType::BRAIN_SMASH })) {
78             return false;
79         }
80     }
81
82     auto *floor_ptr = player_ptr->current_floor_ptr;
83     if (d_ptr->flags.has(DungeonFeatureType::BEGINNER)) {
84         if (r_ptr->level > floor_ptr->dun_level) {
85             return false;
86         }
87     }
88
89     if (d_ptr->special_div >= 64) {
90         return true;
91     }
92     if (summon_specific_type && d_ptr->flags.has_not(DungeonFeatureType::CHAMELEON)) {
93         return true;
94     }
95
96     byte a;
97     switch (d_ptr->mode) {
98     case DUNGEON_MODE_AND: {
99         if (d_ptr->mflags1) {
100             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1) {
101                 return false;
102             }
103         }
104
105         if (d_ptr->mflags2) {
106             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2) {
107                 return false;
108             }
109         }
110
111         if (d_ptr->mflags3) {
112             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3) {
113                 return false;
114             }
115         }
116
117         if (d_ptr->mon_ability_flags.any()) {
118             if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags)) {
119                 return false;
120             }
121         }
122
123         if (d_ptr->mon_behavior_flags.any()) {
124             if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags)) {
125                 return false;
126             }
127         }
128
129         if (d_ptr->mflags7) {
130             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7) {
131                 return false;
132             }
133         }
134
135         if (d_ptr->mflags8) {
136             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8) {
137                 return false;
138             }
139         }
140
141         if (d_ptr->mflags9) {
142             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9) {
143                 return false;
144             }
145         }
146
147         if (d_ptr->mon_resistance_flags.any()) {
148             if (!r_ptr->resistance_flags.has_all_of(d_ptr->mon_resistance_flags)) {
149                 return false;
150             }
151         }
152
153         if (d_ptr->mon_drop_flags.any()) {
154             if (!r_ptr->drop_flags.has_all_of(d_ptr->mon_drop_flags)) {
155                 return false;
156             }
157         }
158
159         if (d_ptr->mon_kind_flags.any()) {
160             if (!r_ptr->kind_flags.has_all_of(d_ptr->mon_kind_flags)) {
161                 return false;
162             }
163         }
164
165         for (a = 0; a < 5; a++) {
166             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char)) {
167                 return false;
168             }
169         }
170
171         return true;
172     }
173     case DUNGEON_MODE_NAND: {
174         if (d_ptr->mflags1) {
175             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1) {
176                 return true;
177             }
178         }
179
180         if (d_ptr->mflags2) {
181             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2) {
182                 return true;
183             }
184         }
185
186         if (d_ptr->mflags3) {
187             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3) {
188                 return true;
189             }
190         }
191
192         if (d_ptr->mon_ability_flags.any()) {
193             if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags)) {
194                 return true;
195             }
196         }
197
198         if (d_ptr->mon_behavior_flags.any()) {
199             if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags)) {
200                 return true;
201             }
202         }
203
204         if (d_ptr->mflags7) {
205             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7) {
206                 return true;
207             }
208         }
209
210         if (d_ptr->mflags8) {
211             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8) {
212                 return true;
213             }
214         }
215
216         if (d_ptr->mflags9) {
217             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9) {
218                 return true;
219             }
220         }
221
222         if (d_ptr->mon_resistance_flags.any()) {
223             if (!r_ptr->resistance_flags.has_all_of(d_ptr->mon_resistance_flags)) {
224                 return true;
225             }
226         }
227
228         if (d_ptr->mon_drop_flags.any()) {
229             if (!r_ptr->drop_flags.has_all_of(d_ptr->mon_drop_flags)) {
230                 return true;
231             }
232         }
233
234         if (d_ptr->mon_kind_flags.any()) {
235             if (!r_ptr->kind_flags.has_all_of(d_ptr->mon_kind_flags)) {
236                 return true;
237             }
238         }
239
240         for (a = 0; a < 5; a++) {
241             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char)) {
242                 return true;
243             }
244         }
245
246         return false;
247     }
248     case DUNGEON_MODE_OR: {
249         if (r_ptr->flags1 & d_ptr->mflags1) {
250             return true;
251         }
252         if (r_ptr->flags2 & d_ptr->mflags2) {
253             return true;
254         }
255         if (r_ptr->flags3 & d_ptr->mflags3) {
256             return true;
257         }
258         if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags)) {
259             return true;
260         }
261         if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags)) {
262             return true;
263         }
264         if (r_ptr->flags7 & d_ptr->mflags7) {
265             return true;
266         }
267         if (r_ptr->flags8 & d_ptr->mflags8) {
268             return true;
269         }
270         if (r_ptr->flags9 & d_ptr->mflags9) {
271             return true;
272         }
273         if (r_ptr->resistance_flags.has_any_of(d_ptr->mon_resistance_flags)) {
274             return true;
275         }
276         if (r_ptr->drop_flags.has_any_of(d_ptr->mon_drop_flags)) {
277             return true;
278         }
279         if (r_ptr->kind_flags.has_any_of(d_ptr->mon_kind_flags)) {
280             return true;
281         }
282         for (a = 0; a < 5; a++) {
283             if (d_ptr->r_char[a] == r_ptr->d_char) {
284                 return true;
285             }
286         }
287
288         return false;
289     }
290     case DUNGEON_MODE_NOR: {
291         if (r_ptr->flags1 & d_ptr->mflags1) {
292             return false;
293         }
294         if (r_ptr->flags2 & d_ptr->mflags2) {
295             return false;
296         }
297         if (r_ptr->flags3 & d_ptr->mflags3) {
298             return false;
299         }
300         if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags)) {
301             return false;
302         }
303         if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags)) {
304             return false;
305         }
306         if (r_ptr->flags7 & d_ptr->mflags7) {
307             return false;
308         }
309         if (r_ptr->flags8 & d_ptr->mflags8) {
310             return false;
311         }
312         if (r_ptr->flags9 & d_ptr->mflags9) {
313             return false;
314         }
315         if (r_ptr->resistance_flags.has_any_of(d_ptr->mon_resistance_flags)) {
316             return false;
317         }
318         if (r_ptr->drop_flags.has_any_of(d_ptr->mon_drop_flags)) {
319             return false;
320         }
321         if (r_ptr->kind_flags.has_any_of(d_ptr->mon_kind_flags)) {
322             return false;
323         }
324         for (a = 0; a < 5; a++) {
325             if (d_ptr->r_char[a] == r_ptr->d_char) {
326                 return false;
327             }
328         }
329
330         return true;
331     }
332     }
333
334     return true;
335 }
336
337 /*!
338  * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
339  * @param player_ptr プレイヤーへの参照ポインタ
340  * @return 地勢にあったモンスターの生成条件関数
341  */
342 monsterrace_hook_type get_monster_hook(PlayerType *player_ptr)
343 {
344     if ((player_ptr->current_floor_ptr->dun_level > 0) || (inside_quest(player_ptr->current_floor_ptr->quest_number))) {
345         return (monsterrace_hook_type)mon_hook_dungeon;
346     }
347
348     switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
349     case TERRAIN_TOWN:
350         return (monsterrace_hook_type)mon_hook_town;
351     case TERRAIN_DEEP_WATER:
352         return (monsterrace_hook_type)mon_hook_ocean;
353     case TERRAIN_SHALLOW_WATER:
354     case TERRAIN_SWAMP:
355         return (monsterrace_hook_type)mon_hook_shore;
356     case TERRAIN_DIRT:
357     case TERRAIN_DESERT:
358         return (monsterrace_hook_type)mon_hook_waste;
359     case TERRAIN_GRASS:
360         return (monsterrace_hook_type)mon_hook_grass;
361     case TERRAIN_TREES:
362         return (monsterrace_hook_type)mon_hook_wood;
363     case TERRAIN_SHALLOW_LAVA:
364     case TERRAIN_DEEP_LAVA:
365         return (monsterrace_hook_type)mon_hook_volcano;
366     case TERRAIN_MOUNTAIN:
367         return (monsterrace_hook_type)mon_hook_mountain;
368     default:
369         return (monsterrace_hook_type)mon_hook_dungeon;
370     }
371 }
372
373 /*!
374  * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
375  * @return 地勢にあったモンスターの生成条件関数
376  */
377 monsterrace_hook_type get_monster_hook2(PlayerType *player_ptr, POSITION y, POSITION x)
378 {
379     auto *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
380     if (f_ptr->flags.has(FloorFeatureType::WATER)) {
381         return f_ptr->flags.has(FloorFeatureType::DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
382     }
383
384     if (f_ptr->flags.has(FloorFeatureType::LAVA)) {
385         return (monsterrace_hook_type)mon_hook_lava;
386     }
387
388     return (monsterrace_hook_type)mon_hook_floor;
389 }
390
391 /*!
392  * @brief モンスター生成テーブルの重みを指定条件に従って変更する。
393  * @param player_ptr
394  * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
395  * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
396  * @param restrict_to_dungeon 現在プレイヤーのいるダンジョンの制約を適用するか
397  * @return 常に 0
398  *
399  * モンスター生成テーブル alloc_race_table の各要素の基本重み prob1 を指定条件
400  * に従って変更し、結果を prob2 に書き込む。
401  */
402 static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2, const bool restrict_to_dungeon)
403 {
404     const floor_type *const floor_ptr = player_ptr->current_floor_ptr;
405
406     // デバッグ用統計情報。
407     int mon_num = 0; // 重み(prob2)が正の要素数
408     DEPTH lev_min = MAX_DEPTH; // 重みが正の要素のうち最小階
409     DEPTH lev_max = 0; // 重みが正の要素のうち最大階
410     int prob2_total = 0; // 重みの総和
411
412     // モンスター生成テーブルの各要素について重みを修正する。
413     for (auto i = 0U; i < alloc_race_table.size(); i++) {
414         alloc_entry *const entry = &alloc_race_table[i];
415         const auto entry_r_idx = i2enum<MonsterRaceId>(entry->index);
416         const monster_race *const r_ptr = &r_info[entry_r_idx];
417
418         // 生成を禁止する要素は重み 0 とする。
419         entry->prob2 = 0;
420
421         // 基本重みが 0 以下なら生成禁止。
422         // テーブル内の無効エントリもこれに該当する(alloc_race_table は生成時にゼロクリアされるため)。
423         if (entry->prob1 <= 0) {
424             continue;
425         }
426
427         // いずれかの生成制約関数が偽を返したら生成禁止。
428         if ((hook1 && !hook1(player_ptr, entry_r_idx)) || (hook2 && !hook2(player_ptr, entry_r_idx))) {
429             continue;
430         }
431
432         // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
433         if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
434             // クエストモンスターは生成禁止。
435             if (r_ptr->flags1 & RF1_QUESTOR) {
436                 continue;
437             }
438
439             // ダンジョンの主は生成禁止。
440             if (r_ptr->flags7 & RF7_GUARDIAN) {
441                 continue;
442             }
443
444             // RF1_FORCE_DEPTH フラグ持ちは指定階未満では生成禁止。
445             if ((r_ptr->flags1 & RF1_FORCE_DEPTH) && (r_ptr->level > floor_ptr->dun_level)) {
446                 continue;
447             }
448
449             // クエスト内でRES_ALLの生成を禁止する (殲滅系クエストの詰み防止)
450             if (inside_quest(player_ptr->current_floor_ptr->quest_number) && r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
451                 continue;
452             }
453         }
454
455         // 生成を許可するものは基本重みをそのまま引き継ぐ。
456         entry->prob2 = entry->prob1;
457
458         // 引数で指定されていればさらにダンジョンによる制約を試みる。
459         if (restrict_to_dungeon) {
460             // ダンジョンによる制約を適用する条件:
461             //
462             //   * フェイズアウト状態でない
463             //   * 1階かそれより深いところにいる
464             //   * ランダムクエスト中でない
465             const bool in_random_quest = inside_quest(floor_ptr->quest_number) && !quest_type::is_fixed(floor_ptr->quest_number);
466             const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
467
468             if (cond && !restrict_monster_to_dungeon(player_ptr, entry_r_idx)) {
469                 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
470                 // 丸めは確率的に行う。
471                 const int numer = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
472                 const int q = numer / 64;
473                 const int r = numer % 64;
474                 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
475             }
476         }
477
478         // 統計情報更新。
479         if (entry->prob2 > 0) {
480             mon_num++;
481             if (lev_min > entry->level) {
482                 lev_min = entry->level;
483             }
484             if (lev_max < entry->level) {
485                 lev_max = entry->level;
486             }
487             prob2_total += entry->prob2;
488         }
489     }
490
491     // チートオプションが有効なら統計情報を出力。
492     if (cheat_hear) {
493         msg_format(_("モンスター第2次候補数:%d(%d-%dF)%d ", "monster second selection:%d(%d-%dF)%d "), mon_num, lev_min, lev_max, prob2_total);
494     }
495
496     return 0;
497 }
498
499 /*!
500  * @brief モンスター生成テーブルの重み修正
501  * @param player_ptr
502  * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
503  * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
504  * @return 常に 0
505  *
506  * get_mon_num() を呼ぶ前に get_mon_num_prep() 系関数のいずれかを呼ぶこと。
507  */
508 errr get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2)
509 {
510     return do_get_mon_num_prep(player_ptr, hook1, hook2, true);
511 }
512
513 /*!
514  * @brief モンスター生成テーブルの重み修正(賞金首選定用)
515  * @return 常に 0
516  *
517  * get_mon_num() を呼ぶ前に get_mon_num_prep 系関数のいずれかを呼ぶこと。
518  */
519 errr get_mon_num_prep_bounty(PlayerType *player_ptr)
520 {
521     return do_get_mon_num_prep(player_ptr, nullptr, nullptr, false);
522 }