OSDN Git Service

[Refactor] #2141 floor_type *floor_ptrの宣言をautoに差し替えた
[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, MONRACE_IDX r_idx)
55 {
56     DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
57     dungeon_type *d_ptr = &d_info[d_idx];
58     monster_race *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     if (d_ptr->flags.has(DungeonFeatureType::NO_MAGIC)) {
66         if (r_idx != MON_CHAMELEON && r_ptr->freq_spell && r_ptr->ability_flags.has_none_of(RF_ABILITY_NOMAGIC_MASK))
67             return false;
68     }
69
70     if (d_ptr->flags.has(DungeonFeatureType::NO_MELEE)) {
71         if (r_idx == MON_CHAMELEON)
72             return true;
73         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(
74                                                                                                                         { MonsterAbilityType::CAUSE_1, MonsterAbilityType::CAUSE_2, MonsterAbilityType::CAUSE_3, MonsterAbilityType::CAUSE_4, MonsterAbilityType::MIND_BLAST, MonsterAbilityType::BRAIN_SMASH }))
75             return false;
76     }
77
78     auto *floor_ptr = player_ptr->current_floor_ptr;
79     if (d_ptr->flags.has(DungeonFeatureType::BEGINNER)) {
80         if (r_ptr->level > floor_ptr->dun_level)
81             return false;
82     }
83
84     if (d_ptr->special_div >= 64)
85         return true;
86     if (summon_specific_type && d_ptr->flags.has_not(DungeonFeatureType::CHAMELEON))
87         return true;
88
89     byte a;
90     switch (d_ptr->mode) {
91     case DUNGEON_MODE_AND: {
92         if (d_ptr->mflags1) {
93             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
94                 return false;
95         }
96
97         if (d_ptr->mflags2) {
98             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
99                 return false;
100         }
101
102         if (d_ptr->mflags3) {
103             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
104                 return false;
105         }
106
107         if (d_ptr->mon_ability_flags.any()) {
108             if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags))
109                 return false;
110         }
111
112         if (d_ptr->mon_behavior_flags.any()) {
113             if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags))
114                 return false;
115         }
116
117         if (d_ptr->mflags7) {
118             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
119                 return false;
120         }
121
122         if (d_ptr->mflags8) {
123             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
124                 return false;
125         }
126
127         if (d_ptr->mflags9) {
128             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
129                 return false;
130         }
131
132         if (d_ptr->mflagsr) {
133             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
134                 return false;
135         }
136
137         for (a = 0; a < 5; a++)
138             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
139                 return false;
140
141         return true;
142     }
143     case DUNGEON_MODE_NAND: {
144         if (d_ptr->mflags1) {
145             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
146                 return true;
147         }
148
149         if (d_ptr->mflags2) {
150             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
151                 return true;
152         }
153
154         if (d_ptr->mflags3) {
155             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
156                 return true;
157         }
158
159         if (d_ptr->mon_ability_flags.any()) {
160             if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags))
161                 return true;
162         }
163
164         if (d_ptr->mon_behavior_flags.any()) {
165             if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags))
166                 return true;
167         }
168
169         if (d_ptr->mflags7) {
170             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
171                 return true;
172         }
173
174         if (d_ptr->mflags8) {
175             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
176                 return true;
177         }
178
179         if (d_ptr->mflags9) {
180             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
181                 return true;
182         }
183
184         if (d_ptr->mflagsr) {
185             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
186                 return true;
187         }
188
189         for (a = 0; a < 5; a++)
190             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
191                 return true;
192
193         return false;
194     }
195     case DUNGEON_MODE_OR: {
196         if (r_ptr->flags1 & d_ptr->mflags1)
197             return true;
198         if (r_ptr->flags2 & d_ptr->mflags2)
199             return true;
200         if (r_ptr->flags3 & d_ptr->mflags3)
201             return true;
202         if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags))
203             return true;
204         if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags))
205             return true;
206         if (r_ptr->flags7 & d_ptr->mflags7)
207             return true;
208         if (r_ptr->flags8 & d_ptr->mflags8)
209             return true;
210         if (r_ptr->flags9 & d_ptr->mflags9)
211             return true;
212         if (r_ptr->flagsr & d_ptr->mflagsr)
213             return true;
214         for (a = 0; a < 5; a++)
215             if (d_ptr->r_char[a] == r_ptr->d_char)
216                 return true;
217
218         return false;
219     }
220     case DUNGEON_MODE_NOR: {
221         if (r_ptr->flags1 & d_ptr->mflags1)
222             return false;
223         if (r_ptr->flags2 & d_ptr->mflags2)
224             return false;
225         if (r_ptr->flags3 & d_ptr->mflags3)
226             return false;
227         if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags))
228             return false;
229         if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags))
230             return false;
231         if (r_ptr->flags7 & d_ptr->mflags7)
232             return false;
233         if (r_ptr->flags8 & d_ptr->mflags8)
234             return false;
235         if (r_ptr->flags9 & d_ptr->mflags9)
236             return false;
237         if (r_ptr->flagsr & d_ptr->mflagsr)
238             return false;
239         for (a = 0; a < 5; a++)
240             if (d_ptr->r_char[a] == r_ptr->d_char)
241                 return false;
242
243         return true;
244     }
245     }
246
247     return true;
248 }
249
250 /*!
251  * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
252  * @param player_ptr プレイヤーへの参照ポインタ
253  * @return 地勢にあったモンスターの生成条件関数
254  */
255 monsterrace_hook_type get_monster_hook(PlayerType *player_ptr)
256 {
257     if ((player_ptr->current_floor_ptr->dun_level > 0) || (inside_quest(player_ptr->current_floor_ptr->quest_number)))
258         return (monsterrace_hook_type)mon_hook_dungeon;
259
260     switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
261     case TERRAIN_TOWN:
262         return (monsterrace_hook_type)mon_hook_town;
263     case TERRAIN_DEEP_WATER:
264         return (monsterrace_hook_type)mon_hook_ocean;
265     case TERRAIN_SHALLOW_WATER:
266     case TERRAIN_SWAMP:
267         return (monsterrace_hook_type)mon_hook_shore;
268     case TERRAIN_DIRT:
269     case TERRAIN_DESERT:
270         return (monsterrace_hook_type)mon_hook_waste;
271     case TERRAIN_GRASS:
272         return (monsterrace_hook_type)mon_hook_grass;
273     case TERRAIN_TREES:
274         return (monsterrace_hook_type)mon_hook_wood;
275     case TERRAIN_SHALLOW_LAVA:
276     case TERRAIN_DEEP_LAVA:
277         return (monsterrace_hook_type)mon_hook_volcano;
278     case TERRAIN_MOUNTAIN:
279         return (monsterrace_hook_type)mon_hook_mountain;
280     default:
281         return (monsterrace_hook_type)mon_hook_dungeon;
282     }
283 }
284
285 /*!
286  * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
287  * @return 地勢にあったモンスターの生成条件関数
288  */
289 monsterrace_hook_type get_monster_hook2(PlayerType *player_ptr, POSITION y, POSITION x)
290 {
291     feature_type *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
292     if (f_ptr->flags.has(FloorFeatureType::WATER))
293         return f_ptr->flags.has(FloorFeatureType::DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
294
295     if (f_ptr->flags.has(FloorFeatureType::LAVA))
296         return (monsterrace_hook_type)mon_hook_lava;
297
298     return (monsterrace_hook_type)mon_hook_floor;
299 }
300
301 /*!
302  * @brief モンスター生成テーブルの重みを指定条件に従って変更する。
303  * @param player_ptr
304  * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
305  * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
306  * @param restrict_to_dungeon 現在プレイヤーのいるダンジョンの制約を適用するか
307  * @return 常に 0
308  *
309  * モンスター生成テーブル alloc_race_table の各要素の基本重み prob1 を指定条件
310  * に従って変更し、結果を prob2 に書き込む。
311  */
312 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)
313 {
314     const floor_type *const floor_ptr = player_ptr->current_floor_ptr;
315
316     // デバッグ用統計情報。
317     int mon_num = 0; // 重み(prob2)が正の要素数
318     DEPTH lev_min = MAX_DEPTH; // 重みが正の要素のうち最小階
319     DEPTH lev_max = 0; // 重みが正の要素のうち最大階
320     int prob2_total = 0; // 重みの総和
321
322     // モンスター生成テーブルの各要素について重みを修正する。
323     for (auto i = 0U; i < alloc_race_table.size(); i++) {
324         alloc_entry *const entry = &alloc_race_table[i];
325         const monster_race *const r_ptr = &r_info[entry->index];
326
327         // 生成を禁止する要素は重み 0 とする。
328         entry->prob2 = 0;
329
330         // 基本重みが 0 以下なら生成禁止。
331         // テーブル内の無効エントリもこれに該当する(alloc_race_table は生成時にゼロクリアされるため)。
332         if (entry->prob1 <= 0)
333             continue;
334
335         // いずれかの生成制約関数が偽を返したら生成禁止。
336         if ((hook1 && !hook1(player_ptr, entry->index)) || (hook2 && !hook2(player_ptr, entry->index)))
337             continue;
338
339         // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
340         if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
341             // クエストモンスターは生成禁止。
342             if (r_ptr->flags1 & RF1_QUESTOR)
343                 continue;
344
345             // ダンジョンの主は生成禁止。
346             if (r_ptr->flags7 & RF7_GUARDIAN)
347                 continue;
348
349             // RF1_FORCE_DEPTH フラグ持ちは指定階未満では生成禁止。
350             if ((r_ptr->flags1 & RF1_FORCE_DEPTH) && (r_ptr->level > floor_ptr->dun_level))
351                 continue;
352
353             // クエスト内でRES_ALLの生成を禁止する (殲滅系クエストの詰み防止)
354             if (inside_quest(player_ptr->current_floor_ptr->quest_number) && any_bits(r_ptr->flagsr, RFR_RES_ALL))
355                 continue;
356         }
357
358         // 生成を許可するものは基本重みをそのまま引き継ぐ。
359         entry->prob2 = entry->prob1;
360
361         // 引数で指定されていればさらにダンジョンによる制約を試みる。
362         if (restrict_to_dungeon) {
363             // ダンジョンによる制約を適用する条件:
364             //
365             //   * フェイズアウト状態でない
366             //   * 1階かそれより深いところにいる
367             //   * ランダムクエスト中でない
368             const bool in_random_quest = inside_quest(floor_ptr->quest_number) && !quest_type::is_fixed(floor_ptr->quest_number);
369             const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
370
371             if (cond && !restrict_monster_to_dungeon(player_ptr, entry->index)) {
372                 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
373                 // 丸めは確率的に行う。
374                 const int numer = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
375                 const int q = numer / 64;
376                 const int r = numer % 64;
377                 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
378             }
379         }
380
381         // 統計情報更新。
382         if (entry->prob2 > 0) {
383             mon_num++;
384             if (lev_min > entry->level)
385                 lev_min = entry->level;
386             if (lev_max < entry->level)
387                 lev_max = entry->level;
388             prob2_total += entry->prob2;
389         }
390     }
391
392     // チートオプションが有効なら統計情報を出力。
393     if (cheat_hear)
394         msg_format(_("モンスター第2次候補数:%d(%d-%dF)%d ", "monster second selection:%d(%d-%dF)%d "), mon_num, lev_min, lev_max, prob2_total);
395
396     return 0;
397 }
398
399 /*!
400  * @brief モンスター生成テーブルの重み修正
401  * @param player_ptr
402  * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
403  * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
404  * @return 常に 0
405  *
406  * get_mon_num() を呼ぶ前に get_mon_num_prep() 系関数のいずれかを呼ぶこと。
407  */
408 errr get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2)
409 {
410     return do_get_mon_num_prep(player_ptr, hook1, hook2, true);
411 }
412
413 /*!
414  * @brief モンスター生成テーブルの重み修正(賞金首選定用)
415  * @return 常に 0
416  *
417  * get_mon_num() を呼ぶ前に get_mon_num_prep 系関数のいずれかを呼ぶこと。
418  */
419 errr get_mon_num_prep_bounty(PlayerType *player_ptr)
420 {
421     return do_get_mon_num_prep(player_ptr, nullptr, nullptr, false);
422 }