OSDN Git Service

[move] ソースファイルの拡張子を .c から .cpp に変更
[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/grid.h"
8 #include "monster-race/monster-race-hook.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-flags-ability1.h"
11 #include "monster-race/race-flags-ability2.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags4.h"
14 #include "monster-race/race-flags7.h"
15 #include "monster-race/race-indice-types.h"
16 #include "mspell/mspell-mask-definitions.h"
17 #include "spell/summon-types.h"
18 #include "system/alloc-entries.h"
19 #include "system/floor-type-definition.h"
20 #include "util/bit-flags-calculator.h"
21 #include "view/display-messages.h"
22
23 enum dungeon_mode_type {
24     DUNGEON_MODE_AND = 1,
25     DUNGEON_MODE_NAND = 2,
26     DUNGEON_MODE_OR = 3,
27     DUNGEON_MODE_NOR = 4,
28 };
29
30 MONSTER_IDX hack_m_idx = 0; /* Hack -- see "process_monsters()" */
31 MONSTER_IDX hack_m_idx_ii = 0;
32
33 /*!
34  * @var chameleon_change_m_idx
35  * @brief カメレオンの変身先モンスターIDを受け渡すためのグローバル変数
36  * @todo 変数渡しの問題などもあるができればchameleon_change_m_idxのグローバル変数を除去し、関数引き渡しに移行すること
37  */
38 int chameleon_change_m_idx = 0;
39
40 /*!
41  * @var summon_specific_type
42  * @brief 召喚条件を指定するグローバル変数 / Hack -- the "type" of the current "summon specific"
43  * @todo summon_specific_typeグローバル変数の除去と関数引数への代替を行う
44  */
45 summon_type summon_specific_type = SUMMON_NONE;
46
47 /*!
48  * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
49  * @param player_ptr プレーヤーへの参照ポインタ
50  * @param r_idx チェックするモンスター種族ID
51  * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
52  */
53 static bool restrict_monster_to_dungeon(player_type *player_ptr, MONRACE_IDX r_idx)
54 {
55     DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
56     dungeon_type *d_ptr = &d_info[d_idx];
57     monster_race *r_ptr = &r_info[r_idx];
58
59     if (d_ptr->flags1 & DF1_CHAMELEON) {
60         if (chameleon_change_m_idx)
61             return TRUE;
62     }
63
64     if (d_ptr->flags1 & DF1_NO_MAGIC) {
65         if (r_idx != MON_CHAMELEON && r_ptr->freq_spell && !(r_ptr->flags4 & RF4_NOMAGIC_MASK) && !(r_ptr->a_ability_flags1 & RF5_NOMAGIC_MASK)
66             && !(r_ptr->a_ability_flags2 & RF6_NOMAGIC_MASK))
67             return FALSE;
68     }
69
70     if (d_ptr->flags1 & DF1_NO_MELEE) {
71         if (r_idx == MON_CHAMELEON)
72             return TRUE;
73         if (!(r_ptr->flags4 & (RF4_BOLT_MASK | RF4_BEAM_MASK | RF4_BALL_MASK))
74             && !(r_ptr->a_ability_flags1
75                 & (RF5_BOLT_MASK | RF5_BEAM_MASK | RF5_BALL_MASK | RF5_CAUSE_1 | RF5_CAUSE_2 | RF5_CAUSE_3 | RF5_CAUSE_4 | RF5_MIND_BLAST | RF5_BRAIN_SMASH))
76             && !(r_ptr->a_ability_flags2 & (RF6_BOLT_MASK | RF6_BEAM_MASK | RF6_BALL_MASK)))
77             return FALSE;
78     }
79
80     floor_type *floor_ptr = player_ptr->current_floor_ptr;
81     if (d_ptr->flags1 & DF1_BEGINNER) {
82         if (r_ptr->level > floor_ptr->dun_level)
83             return FALSE;
84     }
85
86     if (d_ptr->special_div >= 64)
87         return TRUE;
88     if (summon_specific_type && !(d_ptr->flags1 & DF1_CHAMELEON))
89         return TRUE;
90
91     byte a;
92     switch (d_ptr->mode) {
93     case DUNGEON_MODE_AND: {
94         if (d_ptr->mflags1) {
95             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
96                 return FALSE;
97         }
98
99         if (d_ptr->mflags2) {
100             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
101                 return FALSE;
102         }
103
104         if (d_ptr->mflags3) {
105             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
106                 return FALSE;
107         }
108
109         if (d_ptr->mflags4) {
110             if ((d_ptr->mflags4 & r_ptr->flags4) != d_ptr->mflags4)
111                 return FALSE;
112         }
113
114         if (d_ptr->m_a_ability_flags1) {
115             if ((d_ptr->m_a_ability_flags1 & r_ptr->a_ability_flags1) != d_ptr->m_a_ability_flags1)
116                 return FALSE;
117         }
118
119         if (d_ptr->m_a_ability_flags2) {
120             if ((d_ptr->m_a_ability_flags2 & r_ptr->a_ability_flags2) != d_ptr->m_a_ability_flags2)
121                 return FALSE;
122         }
123
124         if (d_ptr->mflags7) {
125             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
126                 return FALSE;
127         }
128
129         if (d_ptr->mflags8) {
130             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
131                 return FALSE;
132         }
133
134         if (d_ptr->mflags9) {
135             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
136                 return FALSE;
137         }
138
139         if (d_ptr->mflagsr) {
140             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
141                 return FALSE;
142         }
143
144         for (a = 0; a < 5; a++)
145             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
146                 return FALSE;
147
148         return TRUE;
149     }
150     case DUNGEON_MODE_NAND: {
151         if (d_ptr->mflags1) {
152             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
153                 return TRUE;
154         }
155
156         if (d_ptr->mflags2) {
157             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
158                 return TRUE;
159         }
160
161         if (d_ptr->mflags3) {
162             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
163                 return TRUE;
164         }
165
166         if (d_ptr->mflags4) {
167             if ((d_ptr->mflags4 & r_ptr->flags4) != d_ptr->mflags4)
168                 return TRUE;
169         }
170
171         if (d_ptr->m_a_ability_flags1) {
172             if ((d_ptr->m_a_ability_flags1 & r_ptr->a_ability_flags1) != d_ptr->m_a_ability_flags1)
173                 return TRUE;
174         }
175
176         if (d_ptr->m_a_ability_flags2) {
177             if ((d_ptr->m_a_ability_flags2 & r_ptr->a_ability_flags2) != d_ptr->m_a_ability_flags2)
178                 return TRUE;
179         }
180
181         if (d_ptr->mflags7) {
182             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
183                 return TRUE;
184         }
185
186         if (d_ptr->mflags8) {
187             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
188                 return TRUE;
189         }
190
191         if (d_ptr->mflags9) {
192             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
193                 return TRUE;
194         }
195
196         if (d_ptr->mflagsr) {
197             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
198                 return TRUE;
199         }
200
201         for (a = 0; a < 5; a++)
202             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
203                 return TRUE;
204
205         return FALSE;
206     }
207     case DUNGEON_MODE_OR: {
208         if (r_ptr->flags1 & d_ptr->mflags1)
209             return TRUE;
210         if (r_ptr->flags2 & d_ptr->mflags2)
211             return TRUE;
212         if (r_ptr->flags3 & d_ptr->mflags3)
213             return TRUE;
214         if (r_ptr->flags4 & d_ptr->mflags4)
215             return TRUE;
216         if (r_ptr->a_ability_flags1 & d_ptr->m_a_ability_flags1)
217             return TRUE;
218         if (r_ptr->a_ability_flags2 & d_ptr->m_a_ability_flags2)
219             return TRUE;
220         if (r_ptr->flags7 & d_ptr->mflags7)
221             return TRUE;
222         if (r_ptr->flags8 & d_ptr->mflags8)
223             return TRUE;
224         if (r_ptr->flags9 & d_ptr->mflags9)
225             return TRUE;
226         if (r_ptr->flagsr & d_ptr->mflagsr)
227             return TRUE;
228         for (a = 0; a < 5; a++)
229             if (d_ptr->r_char[a] == r_ptr->d_char)
230                 return TRUE;
231
232         return FALSE;
233     }
234     case DUNGEON_MODE_NOR: {
235         if (r_ptr->flags1 & d_ptr->mflags1)
236             return FALSE;
237         if (r_ptr->flags2 & d_ptr->mflags2)
238             return FALSE;
239         if (r_ptr->flags3 & d_ptr->mflags3)
240             return FALSE;
241         if (r_ptr->flags4 & d_ptr->mflags4)
242             return FALSE;
243         if (r_ptr->a_ability_flags1 & d_ptr->m_a_ability_flags1)
244             return FALSE;
245         if (r_ptr->a_ability_flags2 & d_ptr->m_a_ability_flags2)
246             return FALSE;
247         if (r_ptr->flags7 & d_ptr->mflags7)
248             return FALSE;
249         if (r_ptr->flags8 & d_ptr->mflags8)
250             return FALSE;
251         if (r_ptr->flags9 & d_ptr->mflags9)
252             return FALSE;
253         if (r_ptr->flagsr & d_ptr->mflagsr)
254             return FALSE;
255         for (a = 0; a < 5; a++)
256             if (d_ptr->r_char[a] == r_ptr->d_char)
257                 return FALSE;
258
259         return TRUE;
260     }
261     }
262
263     return TRUE;
264 }
265
266 /*!
267  * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
268  * @param player_ptr プレーヤーへの参照ポインタ
269  * @return 地勢にあったモンスターの生成条件関数
270  */
271 monsterrace_hook_type get_monster_hook(player_type *player_ptr)
272 {
273     if ((player_ptr->current_floor_ptr->dun_level > 0) || (player_ptr->current_floor_ptr->inside_quest > 0))
274         return (monsterrace_hook_type)mon_hook_dungeon;
275
276     switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
277     case TERRAIN_TOWN:
278         return (monsterrace_hook_type)mon_hook_town;
279     case TERRAIN_DEEP_WATER:
280         return (monsterrace_hook_type)mon_hook_ocean;
281     case TERRAIN_SHALLOW_WATER:
282     case TERRAIN_SWAMP:
283         return (monsterrace_hook_type)mon_hook_shore;
284     case TERRAIN_DIRT:
285     case TERRAIN_DESERT:
286         return (monsterrace_hook_type)mon_hook_waste;
287     case TERRAIN_GRASS:
288         return (monsterrace_hook_type)mon_hook_grass;
289     case TERRAIN_TREES:
290         return (monsterrace_hook_type)mon_hook_wood;
291     case TERRAIN_SHALLOW_LAVA:
292     case TERRAIN_DEEP_LAVA:
293         return (monsterrace_hook_type)mon_hook_volcano;
294     case TERRAIN_MOUNTAIN:
295         return (monsterrace_hook_type)mon_hook_mountain;
296     default:
297         return (monsterrace_hook_type)mon_hook_dungeon;
298     }
299 }
300
301 /*!
302  * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
303  * @return 地勢にあったモンスターの生成条件関数
304  */
305 monsterrace_hook_type get_monster_hook2(player_type *player_ptr, POSITION y, POSITION x)
306 {
307     feature_type *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
308     if (has_flag(f_ptr->flags, FF_WATER))
309         return has_flag(f_ptr->flags, FF_DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
310
311     if (has_flag(f_ptr->flags, FF_LAVA))
312         return (monsterrace_hook_type)mon_hook_lava;
313
314     return (monsterrace_hook_type)mon_hook_floor;
315 }
316
317 /*!
318  * @brief モンスター生成テーブルの重みを指定条件に従って変更する。
319  * @param player_ptr
320  * @param hook1 生成制約関数1 (NULL の場合、制約なし)
321  * @param hook2 生成制約関数2 (NULL の場合、制約なし)
322  * @param restrict_to_dungeon 現在プレイヤーのいるダンジョンの制約を適用するか
323  * @return 常に 0
324  *
325  * モンスター生成テーブル alloc_race_table の各要素の基本重み prob1 を指定条件
326  * に従って変更し、結果を prob2 に書き込む。
327  */
328 static errr do_get_mon_num_prep(player_type *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2, const bool restrict_to_dungeon)
329 {
330     const floor_type *const floor_ptr = player_ptr->current_floor_ptr;
331
332     // デバッグ用統計情報。
333     int mon_num = 0; // 重み(prob2)が正の要素数
334     DEPTH lev_min = MAX_DEPTH; // 重みが正の要素のうち最小階
335     DEPTH lev_max = 0; // 重みが正の要素のうち最大階
336     int prob2_total = 0; // 重みの総和
337
338     // モンスター生成テーブルの各要素について重みを修正する。
339     for (int i = 0; i < alloc_race_size; i++) {
340         alloc_entry *const entry = &alloc_race_table[i];
341         const monster_race *const r_ptr = &r_info[entry->index];
342
343         // 生成を禁止する要素は重み 0 とする。
344         entry->prob2 = 0;
345
346         // 基本重みが 0 以下なら生成禁止。
347         // テーブル内の無効エントリもこれに該当する(alloc_race_table は生成時にゼロクリアされるため)。
348         if (entry->prob1 <= 0)
349             continue;
350
351         // いずれかの生成制約関数が偽を返したら生成禁止。
352         if ((hook1 && !hook1(player_ptr, entry->index)) || (hook2 && !hook2(player_ptr, entry->index)))
353             continue;
354
355         // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
356         if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
357             // クエストモンスターは生成禁止。
358             if (r_ptr->flags1 & RF1_QUESTOR)
359                 continue;
360
361             // ダンジョンの主は生成禁止。
362             if (r_ptr->flags7 & RF7_GUARDIAN)
363                 continue;
364
365             // RF1_FORCE_DEPTH フラグ持ちは指定階未満では生成禁止。
366             if ((r_ptr->flags1 & RF1_FORCE_DEPTH) && (r_ptr->level > floor_ptr->dun_level))
367                 continue;
368         }
369
370         // 生成を許可するものは基本重みをそのまま引き継ぐ。
371         entry->prob2 = entry->prob1;
372
373         // 引数で指定されていればさらにダンジョンによる制約を試みる。
374         if (restrict_to_dungeon) {
375             // ダンジョンによる制約を適用する条件:
376             //
377             //   * フェイズアウト状態でない
378             //   * 1階かそれより深いところにいる
379             //   * ランダムクエスト中でない
380             const bool in_random_quest = floor_ptr->inside_quest && !is_fixed_quest_idx(floor_ptr->inside_quest);
381             const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
382
383             if (cond && !restrict_monster_to_dungeon(player_ptr, entry->index)) {
384                 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
385                 // 丸めは確率的に行う。
386                 const int numer = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
387                 const int q = numer / 64;
388                 const int r = numer % 64;
389                 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
390             }
391         }
392
393         // 統計情報更新。
394         if (entry->prob2 > 0) {
395             mon_num++;
396             if (lev_min > entry->level)
397                 lev_min = entry->level;
398             if (lev_max < entry->level)
399                 lev_max = entry->level;
400             prob2_total += entry->prob2;
401         }
402     }
403
404     // チートオプションが有効なら統計情報を出力。
405     if (cheat_hear)
406         msg_format(_("モンスター第2次候補数:%d(%d-%dF)%d ", "monster second selection:%d(%d-%dF)%d "), mon_num, lev_min, lev_max, prob2_total);
407
408     return 0;
409 }
410
411 /*!
412  * @brief モンスター生成テーブルの重み修正
413  * @param player_ptr
414  * @param hook1 生成制約関数1 (NULL の場合、制約なし)
415  * @param hook2 生成制約関数2 (NULL の場合、制約なし)
416  * @return 常に 0
417  *
418  * get_mon_num() を呼ぶ前に get_mon_num_prep() 系関数のいずれかを呼ぶこと。
419  */
420 errr get_mon_num_prep(player_type *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2)
421 {
422     return do_get_mon_num_prep(player_ptr, hook1, hook2, TRUE);
423 }
424
425 /*!
426  * @brief モンスター生成テーブルの重み修正(賞金首選定用)
427  * @return 常に 0
428  *
429  * get_mon_num() を呼ぶ前に get_mon_num_prep 系関数のいずれかを呼ぶこと。
430  */
431 errr get_mon_num_prep_bounty(player_type *player_ptr) { return do_get_mon_num_prep(player_ptr, NULL, NULL, FALSE); }