OSDN Git Service

[Refactor] #40569 Separated floor-type-definition.h from floor.h
[hengband/hengband.git] / src / monster / monster-util.c
1 #include "monster/monster-util.h"
2 #include "dungeon/dungeon.h"
3 #include "dungeon/quest.h"
4 #include "floor/floor.h"
5 #include "grid/grid.h"
6 #include "floor/wild.h"
7 #include "monster-race/monster-race.h"
8 #include "monster-race/race-flags-ability1.h"
9 #include "monster-race/race-flags-ability2.h"
10 #include "monster-race/race-flags1.h"
11 #include "monster-race/race-flags4.h"
12 #include "monster-race/race-flags7.h"
13 #include "monster-race/monster-race-hook.h"
14 #include "monster-race/race-indice-types.h"
15 #include "mspell/mspell-mask-definitions.h"
16 #include "spell/spells-summon.h"
17 #include "system/alloc-entries.h"
18 #include "system/floor-type-definition.h"
19 #include "util/bit-flags-calculator.h"
20
21 MONSTER_IDX hack_m_idx = 0; /* Hack -- see "process_monsters()" */
22 MONSTER_IDX hack_m_idx_ii = 0;
23
24 /*!
25  * @var chameleon_change_m_idx
26  * @brief カメレオンの変身先モンスターIDを受け渡すためのグローバル変数
27  * @todo 変数渡しの問題などもあるができればchameleon_change_m_idxのグローバル変数を除去し、関数引き渡しに移行すること
28  */
29 int chameleon_change_m_idx = 0;
30
31 /*!
32  * @var summon_specific_type
33  * @brief 召喚条件を指定するグローバル変数 / Hack -- the "type" of the current "summon specific"
34  * @todo summon_specific_typeグローバル変数の除去と関数引数への代替を行う
35  */
36 int summon_specific_type = 0;
37
38 static monsterrace_hook_type get_mon_num_hook;
39 static monsterrace_hook_type get_mon_num2_hook;
40
41 /*!
42  * todo ここには本来floor_type*を追加したいが、monster.hにfloor.hの参照を追加するとコンパイルエラーが出るので保留
43  * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
44  * @param player_ptr プレーヤーへの参照ポインタ
45  * @param r_idx チェックするモンスター種族ID
46  * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
47  */
48 static bool restrict_monster_to_dungeon(player_type *player_ptr, MONRACE_IDX r_idx)
49 {
50     DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
51     dungeon_type *d_ptr = &d_info[d_idx];
52     monster_race *r_ptr = &r_info[r_idx];
53
54     if (d_ptr->flags1 & DF1_CHAMELEON) {
55         if (chameleon_change_m_idx)
56             return TRUE;
57     }
58
59     if (d_ptr->flags1 & DF1_NO_MAGIC) {
60         if (r_idx != MON_CHAMELEON && r_ptr->freq_spell && !(r_ptr->flags4 & RF4_NOMAGIC_MASK) && !(r_ptr->a_ability_flags1 & RF5_NOMAGIC_MASK)
61             && !(r_ptr->a_ability_flags2 & RF6_NOMAGIC_MASK))
62             return FALSE;
63     }
64
65     if (d_ptr->flags1 & DF1_NO_MELEE) {
66         if (r_idx == MON_CHAMELEON)
67             return TRUE;
68         if (!(r_ptr->flags4 & (RF4_BOLT_MASK | RF4_BEAM_MASK | RF4_BALL_MASK))
69             && !(r_ptr->a_ability_flags1
70                 & (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))
71             && !(r_ptr->a_ability_flags2 & (RF6_BOLT_MASK | RF6_BEAM_MASK | RF6_BALL_MASK)))
72             return FALSE;
73     }
74
75     floor_type *floor_ptr = player_ptr->current_floor_ptr;
76     if (d_ptr->flags1 & DF1_BEGINNER) {
77         if (r_ptr->level > floor_ptr->dun_level)
78             return FALSE;
79     }
80
81     if (d_ptr->special_div >= 64)
82         return TRUE;
83     if (summon_specific_type && !(d_ptr->flags1 & DF1_CHAMELEON))
84         return TRUE;
85
86     byte a;
87     switch (d_ptr->mode) {
88     case DUNGEON_MODE_AND: {
89         if (d_ptr->mflags1) {
90             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
91                 return FALSE;
92         }
93
94         if (d_ptr->mflags2) {
95             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
96                 return FALSE;
97         }
98
99         if (d_ptr->mflags3) {
100             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
101                 return FALSE;
102         }
103
104         if (d_ptr->mflags4) {
105             if ((d_ptr->mflags4 & r_ptr->flags4) != d_ptr->mflags4)
106                 return FALSE;
107         }
108
109         if (d_ptr->m_a_ability_flags1) {
110             if ((d_ptr->m_a_ability_flags1 & r_ptr->a_ability_flags1) != d_ptr->m_a_ability_flags1)
111                 return FALSE;
112         }
113
114         if (d_ptr->m_a_ability_flags2) {
115             if ((d_ptr->m_a_ability_flags2 & r_ptr->a_ability_flags2) != d_ptr->m_a_ability_flags2)
116                 return FALSE;
117         }
118
119         if (d_ptr->mflags7) {
120             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
121                 return FALSE;
122         }
123
124         if (d_ptr->mflags8) {
125             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
126                 return FALSE;
127         }
128
129         if (d_ptr->mflags9) {
130             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
131                 return FALSE;
132         }
133
134         if (d_ptr->mflagsr) {
135             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
136                 return FALSE;
137         }
138
139         for (a = 0; a < 5; a++)
140             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
141                 return FALSE;
142
143         return TRUE;
144     }
145     case DUNGEON_MODE_NAND: {
146         if (d_ptr->mflags1) {
147             if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
148                 return TRUE;
149         }
150
151         if (d_ptr->mflags2) {
152             if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
153                 return TRUE;
154         }
155
156         if (d_ptr->mflags3) {
157             if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
158                 return TRUE;
159         }
160
161         if (d_ptr->mflags4) {
162             if ((d_ptr->mflags4 & r_ptr->flags4) != d_ptr->mflags4)
163                 return TRUE;
164         }
165
166         if (d_ptr->m_a_ability_flags1) {
167             if ((d_ptr->m_a_ability_flags1 & r_ptr->a_ability_flags1) != d_ptr->m_a_ability_flags1)
168                 return TRUE;
169         }
170
171         if (d_ptr->m_a_ability_flags2) {
172             if ((d_ptr->m_a_ability_flags2 & r_ptr->a_ability_flags2) != d_ptr->m_a_ability_flags2)
173                 return TRUE;
174         }
175
176         if (d_ptr->mflags7) {
177             if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
178                 return TRUE;
179         }
180
181         if (d_ptr->mflags8) {
182             if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
183                 return TRUE;
184         }
185
186         if (d_ptr->mflags9) {
187             if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
188                 return TRUE;
189         }
190
191         if (d_ptr->mflagsr) {
192             if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
193                 return TRUE;
194         }
195
196         for (a = 0; a < 5; a++)
197             if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
198                 return TRUE;
199
200         return FALSE;
201     }
202     case DUNGEON_MODE_OR: {
203         if (r_ptr->flags1 & d_ptr->mflags1)
204             return TRUE;
205         if (r_ptr->flags2 & d_ptr->mflags2)
206             return TRUE;
207         if (r_ptr->flags3 & d_ptr->mflags3)
208             return TRUE;
209         if (r_ptr->flags4 & d_ptr->mflags4)
210             return TRUE;
211         if (r_ptr->a_ability_flags1 & d_ptr->m_a_ability_flags1)
212             return TRUE;
213         if (r_ptr->a_ability_flags2 & d_ptr->m_a_ability_flags2)
214             return TRUE;
215         if (r_ptr->flags7 & d_ptr->mflags7)
216             return TRUE;
217         if (r_ptr->flags8 & d_ptr->mflags8)
218             return TRUE;
219         if (r_ptr->flags9 & d_ptr->mflags9)
220             return TRUE;
221         if (r_ptr->flagsr & d_ptr->mflagsr)
222             return TRUE;
223         for (a = 0; a < 5; a++)
224             if (d_ptr->r_char[a] == r_ptr->d_char)
225                 return TRUE;
226
227         return FALSE;
228     }
229     case DUNGEON_MODE_NOR: {
230         if (r_ptr->flags1 & d_ptr->mflags1)
231             return FALSE;
232         if (r_ptr->flags2 & d_ptr->mflags2)
233             return FALSE;
234         if (r_ptr->flags3 & d_ptr->mflags3)
235             return FALSE;
236         if (r_ptr->flags4 & d_ptr->mflags4)
237             return FALSE;
238         if (r_ptr->a_ability_flags1 & d_ptr->m_a_ability_flags1)
239             return FALSE;
240         if (r_ptr->a_ability_flags2 & d_ptr->m_a_ability_flags2)
241             return FALSE;
242         if (r_ptr->flags7 & d_ptr->mflags7)
243             return FALSE;
244         if (r_ptr->flags8 & d_ptr->mflags8)
245             return FALSE;
246         if (r_ptr->flags9 & d_ptr->mflags9)
247             return FALSE;
248         if (r_ptr->flagsr & d_ptr->mflagsr)
249             return FALSE;
250         for (a = 0; a < 5; a++)
251             if (d_ptr->r_char[a] == r_ptr->d_char)
252                 return FALSE;
253
254         return TRUE;
255     }
256     }
257
258     return TRUE;
259 }
260
261 /*!
262  * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
263  * @param player_ptr プレーヤーへの参照ポインタ
264  * @return 地勢にあったモンスターの生成条件関数
265  */
266 monsterrace_hook_type get_monster_hook(player_type *player_ptr)
267 {
268     if ((player_ptr->current_floor_ptr->dun_level > 0) || (player_ptr->current_floor_ptr->inside_quest > 0))
269         return (monsterrace_hook_type)mon_hook_dungeon;
270
271     switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
272     case TERRAIN_TOWN:
273         return (monsterrace_hook_type)mon_hook_town;
274     case TERRAIN_DEEP_WATER:
275         return (monsterrace_hook_type)mon_hook_ocean;
276     case TERRAIN_SHALLOW_WATER:
277     case TERRAIN_SWAMP:
278         return (monsterrace_hook_type)mon_hook_shore;
279     case TERRAIN_DIRT:
280     case TERRAIN_DESERT:
281         return (monsterrace_hook_type)mon_hook_waste;
282     case TERRAIN_GRASS:
283         return (monsterrace_hook_type)mon_hook_grass;
284     case TERRAIN_TREES:
285         return (monsterrace_hook_type)mon_hook_wood;
286     case TERRAIN_SHALLOW_LAVA:
287     case TERRAIN_DEEP_LAVA:
288         return (monsterrace_hook_type)mon_hook_volcano;
289     case TERRAIN_MOUNTAIN:
290         return (monsterrace_hook_type)mon_hook_mountain;
291     default:
292         return (monsterrace_hook_type)mon_hook_dungeon;
293     }
294 }
295
296 /*!
297  * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
298  * @return 地勢にあったモンスターの生成条件関数
299  */
300 monsterrace_hook_type get_monster_hook2(player_type *player_ptr, POSITION y, POSITION x)
301 {
302     feature_type *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
303     if (have_flag(f_ptr->flags, FF_WATER)) {
304         if (have_flag(f_ptr->flags, FF_DEEP)) {
305             return (monsterrace_hook_type)mon_hook_deep_water;
306         } else {
307             return (monsterrace_hook_type)mon_hook_shallow_water;
308         }
309     }
310
311     if (have_flag(f_ptr->flags, FF_LAVA)) {
312         return (monsterrace_hook_type)mon_hook_lava;
313     }
314
315     return (monsterrace_hook_type)mon_hook_floor;
316 }
317
318 /*!
319  * @brief モンスター生成制限関数最大2つから / Apply a "monster restriction function" to the "monster allocation table"
320  * @param player_ptr プレーヤーへの参照ポインタ
321  * @param monster_hook 制限関数1
322  * @param monster_hook2 制限関数2
323  * @return エラーコード
324  */
325 errr get_mon_num_prep(player_type *player_ptr, monsterrace_hook_type monster_hook, monsterrace_hook_type monster_hook2)
326 {
327     /* Todo: Check the hooks for non-changes */
328     get_mon_num_hook = monster_hook;
329     get_mon_num2_hook = monster_hook2;
330
331     floor_type *floor_ptr = player_ptr->current_floor_ptr;
332     for (int i = 0; i < alloc_race_size; i++) {
333         monster_race *r_ptr;
334         alloc_entry *entry = &alloc_race_table[i];
335         entry->prob2 = 0;
336         r_ptr = &r_info[entry->index];
337
338         if ((get_mon_num_hook && !((*get_mon_num_hook)(player_ptr, entry->index))) || (get_mon_num2_hook && !((*get_mon_num2_hook)(player_ptr, entry->index))))
339             continue;
340
341         if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
342             if (r_ptr->flags1 & RF1_QUESTOR)
343                 continue;
344
345             if (r_ptr->flags7 & RF7_GUARDIAN)
346                 continue;
347
348             if ((r_ptr->flags1 & (RF1_FORCE_DEPTH)) && (r_ptr->level > floor_ptr->dun_level))
349                 continue;
350         }
351
352         entry->prob2 = entry->prob1;
353         if (floor_ptr->dun_level && (!floor_ptr->inside_quest || is_fixed_quest_idx(floor_ptr->inside_quest))
354             && !restrict_monster_to_dungeon(player_ptr, entry->index) && !player_ptr->phase_out) {
355             int hoge = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
356             entry->prob2 = hoge / 64;
357             if (randint0(64) < (hoge & 0x3f))
358                 entry->prob2++;
359         }
360     }
361
362     return 0;
363 }