OSDN Git Service

Merge pull request #716 from sikabane-works/release/3.0.0Alpha16
[hengbandforosx/hengbandosx.git] / src / mspell / mspell-selector.cpp
1 /*!
2  * @brief モンスターが詠唱する魔法を選択する処理
3  * @date 2020/07/23
4  * @author Hourier
5  * @details ba-no-ru/rupa-toの特殊処理はここで実施
6  */
7
8 #include "mspell/mspell-selector.h"
9 #include "floor/geometry.h"
10 #include "monster-race/monster-race.h"
11 #include "monster-race/race-flags-ability2.h"
12 #include "monster-race/race-flags2.h"
13 #include "monster-race/race-indice-types.h"
14 #include "monster/monster-status.h"
15 #include "mspell/mspell-attack-util.h"
16 #include "mspell/mspell-judgement.h"
17 #include "system/monster-type-definition.h"
18 #include "system/floor-type-definition.h"
19 #include "world/world.h"
20
21 /*!
22  * @brief ID値が正しいモンスター魔法IDかどうかを返す /
23  * Return TRUE if a spell is good for hurting the player (directly).
24  * @param spell 判定対象のID
25  * @return 正しいIDならばTRUEを返す。
26  */
27 static bool spell_attack(byte spell)
28 {
29     /* All RF4 spells hurt (except for shriek and dispel) */
30     if (spell < 128 && spell > 98)
31         return TRUE;
32
33     /* Various "ball" spells */
34     if (spell >= 128 && spell <= 128 + 8)
35         return TRUE;
36
37     /* "Cause wounds" and "bolt" spells */
38     if (spell >= 128 + 12 && spell < 128 + 27)
39         return TRUE;
40
41     /* Hand of Doom */
42     if (spell == 160 + 1)
43         return TRUE;
44
45     /* Psycho-Spear */
46     if (spell == 160 + 11)
47         return TRUE;
48
49     /* Doesn't hurt */
50     return FALSE;
51 }
52
53 /*!
54  * @brief ID値が退避目的に適したモンスター魔法IDかどうかを返す /
55  * Return TRUE if a spell is good for escaping.
56  * @param spell 判定対象のID
57  * @return 適した魔法のIDならばTRUEを返す。
58  */
59 static bool spell_escape(byte spell)
60 {
61     /* Blink or Teleport */
62     if (spell == 160 + 4 || spell == 160 + 5)
63         return TRUE;
64
65     /* Teleport the player away */
66     if (spell == 160 + 9 || spell == 160 + 10)
67         return TRUE;
68
69     /* Isn't good for escaping */
70     return FALSE;
71 }
72
73 /*!
74  * @brief ID値が妨害目的に適したモンスター魔法IDかどうかを返す /
75  * Return TRUE if a spell is good for annoying the player.
76  * @param spell 判定対象のID
77  * @return 適した魔法のIDならばTRUEを返す。
78  */
79 static bool spell_annoy(byte spell)
80 {
81     /* Shriek */
82     if (spell == 96 + 0)
83         return TRUE;
84
85     /* Brain smash, et al (added curses) */
86     if (spell >= 128 + 9 && spell <= 128 + 14)
87         return TRUE;
88
89     /* Scare, confuse, blind, slow, paralyze */
90     if (spell >= 128 + 27 && spell <= 128 + 31)
91         return TRUE;
92
93     /* Teleport to */
94     if (spell == 160 + 8)
95         return TRUE;
96
97     /* Teleport level */
98     if (spell == 160 + 10)
99         return TRUE;
100
101     /* Darkness, make traps, cause amnesia */
102     if (spell >= 160 + 12 && spell <= 160 + 14)
103         return TRUE;
104
105     /* Doesn't annoy */
106     return FALSE;
107 }
108
109 /*!
110  * @brief ID値が召喚型のモンスター魔法IDかどうかを返す /
111  * Return TRUE if a spell is good for annoying the player.
112  * @param spell 判定対象のID
113  * @return 召喚型魔法のIDならばTRUEを返す。
114  */
115 static bool spell_summon(byte spell) { return spell >= 160 + 16; }
116
117 /*!
118  * @brief ID値が死者復活処理かどうかを返す /
119  * Return TRUE if a spell is good for annoying the player.
120  * @param spell 判定対象のID
121  * @return 死者復活の処理ならばTRUEを返す。
122  */
123 static bool spell_raise(byte spell) { return spell == 160 + 15; }
124
125 /*!
126  * @brief ID値が戦術的なモンスター魔法IDかどうかを返す /
127  * Return TRUE if a spell is good in a tactical situation.
128  * @param spell 判定対象のID
129  * @return 戦術的な魔法のIDならばTRUEを返す。
130  */
131 static bool spell_tactic(byte spell) { return spell == 160 + 4; }
132
133 /*!
134  * @brief ID値が無敵化するモンスター魔法IDかどうかを返す /
135  * Return TRUE if a spell makes invulnerable.
136  * @param spell 判定対象のID
137  * @return 召喚型魔法のIDならばTRUEを返す。
138  */
139 static bool spell_invulner(byte spell) { return spell == 160 + 3; }
140
141 /*!
142  * @brief ID値が加速するモンスター魔法IDかどうかを返す /
143  * Return TRUE if a spell hastes.
144  * @param spell 判定対象のID
145  * @return 召喚型魔法のIDならばTRUEを返す。
146  */
147 static bool spell_haste(byte spell) { return spell == 160 + 0; }
148
149 /*!
150  * @brief ID値が時間停止を行うモンスター魔法IDかどうかを返す /
151  * Return TRUE if a spell world.
152  * @param spell 判定対象のID
153  * @return 時間停止魔法のIDならばTRUEを返す。
154  */
155 static bool spell_world(byte spell) { return spell == 160 + 6; }
156
157 /*!
158  * @brief ID値が特別効果のモンスター魔法IDかどうかを返す /
159  * Return TRUE if a spell special.
160  * @param target_ptr プレーヤーへの参照ポインタ
161  * @param spell 判定対象のID
162  * @return 特別効果魔法のIDならばTRUEを返す。
163  */
164 static bool spell_special(player_type *target_ptr, byte spell)
165 {
166     if (target_ptr->phase_out)
167         return FALSE;
168
169     return spell == 160 + 7;
170 }
171
172 /*!
173  * @brief ID値が光の剣のモンスター魔法IDかどうかを返す /
174  * Return TRUE if a spell psycho-spear.
175  * @param spell 判定対象のID
176  * @return 光の剣のIDならばTRUEを返す。
177  */
178 static bool spell_psy_spe(byte spell) { return spell == 160 + 11; }
179
180 /*!
181  * @brief ID値が治癒魔法かどうかを返す /
182  * Return TRUE if a spell is good for healing.
183  * @param spell 判定対象のID
184  * @return 治癒魔法のIDならばTRUEを返す。
185  */
186 static bool spell_heal(byte spell) { return spell == 160 + 2; }
187
188 /*!
189  * @brief ID値が魔力消去かどうかを返す /
190  * Return TRUE if a spell is good for dispel.
191  * @param spell 判定対象のID
192  * @return 魔力消去のIDならばTRUEを返す。
193  */
194 static bool spell_dispel(byte spell) { return spell == 96 + 2; }
195
196 /*!
197  * @brief モンスターの魔法選択ルーチン
198  * Have a monster choose a spell from a list of "useful" spells.
199  * @param target_ptr プレーヤーへの参照ポインタ
200  * @param m_idx モンスターの構造体配列ID
201  * @param spells 候補魔法IDをまとめた配列
202  * @param num spellsの長さ
203  * @return 選択したモンスター魔法のID
204  * @details
205  * Note that this list does NOT include spells that will just hit\n
206  * other monsters, and the list is restricted when the monster is\n
207  * "desperate".  Should that be the job of this function instead?\n
208  *\n
209  * Stupid monsters will just pick a spell randomly.  Smart monsters\n
210  * will choose more "intelligently".\n
211  *\n
212  * Use the helper functions above to put spells into categories.\n
213  *\n
214  * This function may well be an efficiency bottleneck.\n
215  * @todo 長過ぎる。切り分けが必要
216  */
217 int choose_attack_spell(player_type *target_ptr, msa_type *msa_ptr)
218 {
219     byte escape[96], escape_num = 0;
220     byte attack[96], attack_num = 0;
221     byte summon[96], summon_num = 0;
222     byte tactic[96], tactic_num = 0;
223     byte annoy[96], annoy_num = 0;
224     byte invul[96], invul_num = 0;
225     byte haste[96], haste_num = 0;
226     byte world[96], world_num = 0;
227     byte special[96], special_num = 0;
228     byte psy_spe[96], psy_spe_num = 0;
229     byte raise[96], raise_num = 0;
230     byte heal[96], heal_num = 0;
231     byte dispel[96], dispel_num = 0;
232
233     monster_type *m_ptr = &target_ptr->current_floor_ptr->m_list[msa_ptr->m_idx];
234     monster_race *r_ptr = &r_info[m_ptr->r_idx];
235     if (r_ptr->flags2 & RF2_STUPID)
236         return (msa_ptr->mspells[randint0(msa_ptr->num)]);
237
238     for (int i = 0; i < msa_ptr->num; i++) {
239         if (spell_escape(msa_ptr->mspells[i]))
240             escape[escape_num++] = msa_ptr->mspells[i];
241
242         if (spell_attack(msa_ptr->mspells[i]))
243             attack[attack_num++] = msa_ptr->mspells[i];
244
245         if (spell_summon(msa_ptr->mspells[i]))
246             summon[summon_num++] = msa_ptr->mspells[i];
247
248         if (spell_tactic(msa_ptr->mspells[i]))
249             tactic[tactic_num++] = msa_ptr->mspells[i];
250
251         if (spell_annoy(msa_ptr->mspells[i]))
252             annoy[annoy_num++] = msa_ptr->mspells[i];
253
254         if (spell_invulner(msa_ptr->mspells[i]))
255             invul[invul_num++] = msa_ptr->mspells[i];
256
257         if (spell_haste(msa_ptr->mspells[i]))
258             haste[haste_num++] = msa_ptr->mspells[i];
259
260         if (spell_world(msa_ptr->mspells[i]))
261             world[world_num++] = msa_ptr->mspells[i];
262
263         if (spell_special(target_ptr, msa_ptr->mspells[i]))
264             special[special_num++] = msa_ptr->mspells[i];
265
266         if (spell_psy_spe(msa_ptr->mspells[i]))
267             psy_spe[psy_spe_num++] = msa_ptr->mspells[i];
268
269         if (spell_raise(msa_ptr->mspells[i]))
270             raise[raise_num++] = msa_ptr->mspells[i];
271
272         if (spell_heal(msa_ptr->mspells[i]))
273             heal[heal_num++] = msa_ptr->mspells[i];
274
275         if (spell_dispel(msa_ptr->mspells[i]))
276             dispel[dispel_num++] = msa_ptr->mspells[i];
277     }
278
279     if (world_num && (randint0(100) < 15) && !current_world_ptr->timewalk_m_idx)
280         return (world[randint0(world_num)]);
281
282     if (special_num) {
283         bool success = FALSE;
284         switch (m_ptr->r_idx) {
285         case MON_BANOR:
286         case MON_LUPART:
287             if ((m_ptr->hp < m_ptr->maxhp / 2) && r_info[MON_BANOR].max_num && r_info[MON_LUPART].max_num)
288                 success = TRUE;
289             break;
290         default:
291             break;
292         }
293
294         if (success)
295             return (special[randint0(special_num)]);
296     }
297
298     if (m_ptr->hp < m_ptr->maxhp / 3 && one_in_(2)) {
299         if (heal_num)
300             return (heal[randint0(heal_num)]);
301     }
302
303     if (((m_ptr->hp < m_ptr->maxhp / 3) || monster_fear_remaining(m_ptr)) && one_in_(2)) {
304         if (escape_num)
305             return (escape[randint0(escape_num)]);
306     }
307
308     if (special_num) {
309         bool success = FALSE;
310         switch (m_ptr->r_idx) {
311         case MON_OHMU:
312         case MON_BANOR:
313         case MON_LUPART:
314             break;
315         case MON_BANORLUPART:
316             if (randint0(100) < 70)
317                 success = TRUE;
318             break;
319         case MON_ROLENTO:
320             if (randint0(100) < 40)
321                 success = TRUE;
322             break;
323         default:
324             if (randint0(100) < 50)
325                 success = TRUE;
326             break;
327         }
328         if (success)
329             return (special[randint0(special_num)]);
330     }
331
332     if ((distance(target_ptr->y, target_ptr->x, m_ptr->fy, m_ptr->fx) < 4) && (attack_num || (r_ptr->a_ability_flags2 & RF6_TRAPS)) && (randint0(100) < 75)
333         && !current_world_ptr->timewalk_m_idx) {
334         if (tactic_num)
335             return (tactic[randint0(tactic_num)]);
336     }
337
338     if (summon_num && (randint0(100) < 40))
339         return (summon[randint0(summon_num)]);
340
341     if (dispel_num && one_in_(2)) {
342         if (dispel_check(target_ptr, msa_ptr->m_idx)) {
343             return (dispel[randint0(dispel_num)]);
344         }
345     }
346
347     if (raise_num && (randint0(100) < 40))
348         return (raise[randint0(raise_num)]);
349
350     if (is_invuln(target_ptr)) {
351         if (psy_spe_num && (randint0(100) < 50)) {
352             return (psy_spe[randint0(psy_spe_num)]);
353         } else if (attack_num && (randint0(100) < 40)) {
354             return (attack[randint0(attack_num)]);
355         }
356     } else if (attack_num && (randint0(100) < 85)) {
357         return (attack[randint0(attack_num)]);
358     }
359
360     if (tactic_num && (randint0(100) < 50) && !current_world_ptr->timewalk_m_idx)
361         return (tactic[randint0(tactic_num)]);
362
363     if (invul_num && !m_ptr->mtimed[MTIMED_INVULNER] && (randint0(100) < 50))
364         return (invul[randint0(invul_num)]);
365
366     if ((m_ptr->hp < m_ptr->maxhp * 3 / 4) && (randint0(100) < 25)) {
367         if (heal_num)
368             return (heal[randint0(heal_num)]);
369     }
370
371     if (haste_num && (randint0(100) < 20) && !monster_fast_remaining(m_ptr))
372         return (haste[randint0(haste_num)]);
373
374     if (annoy_num && (randint0(100) < 80))
375         return (annoy[randint0(annoy_num)]);
376
377     return 0;
378 }