OSDN Git Service

[Refactor] #2198 SPEED型エイリアスを除去した
[hengbandforosx/hengbandosx.git] / src / monster / monster-list.cpp
1 /*!
2  * @brief モンスター処理 / misc code for monsters
3  * @date 2014/07/08
4  * @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  * This software may be copied and distributed for educational, research,
7  * and not for profit purposes provided that this copyright and statement
8  * are included in all such copies.  Other copyrights may also apply.
9  * 2014 Deskull rearranged comment for Doxygen.
10  */
11
12 #include "monster/monster-list.h"
13 #include "core/player-update-types.h"
14 #include "core/speed-table.h"
15 #include "dungeon/dungeon-flag-types.h"
16 #include "dungeon/dungeon.h"
17 #include "floor/cave.h"
18 #include "floor/floor-object.h"
19 #include "floor/geometry.h"
20 #include "floor/wild.h"
21 #include "game-option/birth-options.h"
22 #include "game-option/cheat-options.h"
23 #include "grid/grid.h"
24 #include "monster-floor/monster-summon.h"
25 #include "monster-race/monster-kind-mask.h"
26 #include "monster-race/monster-race.h"
27 #include "monster-race/race-flags1.h"
28 #include "monster-race/race-flags2.h"
29 #include "monster-race/race-flags3.h"
30 #include "monster-race/race-flags7.h"
31 #include "monster-race/race-indice-types.h"
32 #include "monster/monster-describer.h"
33 #include "monster/monster-info.h"
34 #include "monster/monster-update.h"
35 #include "monster/monster-util.h"
36 #include "pet/pet-fall-off.h"
37 #include "player/player-status.h"
38 #include "system/alloc-entries.h"
39 #include "system/floor-type-definition.h"
40 #include "system/grid-type-definition.h"
41 #include "system/monster-race-definition.h"
42 #include "system/monster-type-definition.h"
43 #include "system/player-type-definition.h"
44 #include "util/probability-table.h"
45 #include "view/display-messages.h"
46 #include "world/world.h"
47 #include <iterator>
48
49 #define HORDE_NOGOOD 0x01 /*!< (未実装フラグ)HORDE生成でGOODなモンスターの生成を禁止する? */
50 #define HORDE_NOEVIL 0x02 /*!< (未実装フラグ)HORDE生成でEVILなモンスターの生成を禁止する? */
51
52 /*!
53  * @brief モンスター配列の空きを探す / Acquires and returns the index of a "free" monster.
54  * @return 利用可能なモンスター配列の添字
55  * @details
56  * This routine should almost never fail, but it *can* happen.
57  */
58 MONSTER_IDX m_pop(floor_type *floor_ptr)
59 {
60     /* Normal allocation */
61     if (floor_ptr->m_max < w_ptr->max_m_idx) {
62         MONSTER_IDX i = floor_ptr->m_max;
63         floor_ptr->m_max++;
64         floor_ptr->m_cnt++;
65         return i;
66     }
67
68     /* Recycle dead monsters */
69     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
70         monster_type *m_ptr;
71         m_ptr = &floor_ptr->m_list[i];
72         if (m_ptr->r_idx)
73             continue;
74         floor_ptr->m_cnt++;
75         return i;
76     }
77
78     if (w_ptr->character_dungeon)
79         msg_print(_("モンスターが多すぎる!", "Too many monsters!"));
80     return 0;
81 }
82
83 /*!
84  * @brief 生成モンスター種族を1種生成テーブルから選択する
85  * @param player_ptr プレイヤーへの参照ポインタ
86  * @param min_level 最小生成階
87  * @param max_level 最大生成階
88  * @return 選択されたモンスター生成種族
89  */
90 MONRACE_IDX get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option)
91 {
92     int r_idx;
93     monster_race *r_ptr;
94
95     int pls_kakuritu, pls_max_level, over_days;
96     int delay = mysqrt(max_level * 10000L) + (max_level * 5);
97
98     /* town max_level : same delay as 10F, no nasty mons till day18 */
99     if (!max_level)
100         delay = 360;
101
102     if (max_level > MAX_DEPTH - 1)
103         max_level = MAX_DEPTH - 1;
104
105     /* +1 per day after the base date */
106     /* base dates : day5(1F), day18(10F,0F), day34(30F), day53(60F), day69(90F) */
107     over_days = std::max<int>(0, w_ptr->dungeon_turn / (TURNS_PER_TICK * 10000L) - delay / 20);
108
109     /* starts from 1/25, reaches 1/3 after 44days from a max_level dependent base date */
110     pls_kakuritu = std::max(NASTY_MON_MAX, NASTY_MON_BASE - over_days / 2);
111     /* starts from 0, reaches +25lv after 75days from a max_level dependent base date */
112     pls_max_level = std::min(NASTY_MON_PLUS_MAX, over_days / 3);
113
114     if (d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::MAZE)) {
115         pls_kakuritu = std::min(pls_kakuritu / 2, pls_kakuritu - 10);
116         if (pls_kakuritu < 2)
117             pls_kakuritu = 2;
118         pls_max_level += 2;
119         max_level += 3;
120     }
121
122     /* Boost the max_level */
123     if ((option & GMN_ARENA) || d_info[player_ptr->dungeon_idx].flags.has_not(DungeonFeatureType::BEGINNER)) {
124         /* Nightmare mode allows more out-of depth monsters */
125         if (ironman_nightmare && !randint0(pls_kakuritu)) {
126             /* What a bizarre calculation */
127             max_level = 1 + (max_level * MAX_DEPTH / randint1(MAX_DEPTH));
128         } else {
129             /* Occasional "nasty" monster */
130             if (!randint0(pls_kakuritu)) {
131                 /* Pick a max_level bonus */
132                 max_level += pls_max_level;
133             }
134         }
135     }
136
137     ProbabilityTable<int> prob_table;
138
139     /* Process probabilities */
140     for (auto i = 0U; i < alloc_race_table.size(); i++) {
141         const auto &entry = alloc_race_table[i];
142         if (entry.level < min_level)
143             continue;
144         if (max_level < entry.level)
145             break; // sorted by depth array,
146         r_idx = entry.index;
147         r_ptr = &r_info[r_idx];
148         if (!(option & GMN_ARENA) && !chameleon_change_m_idx) {
149             if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || (r_ptr->flags7 & (RF7_NAZGUL))) && (r_ptr->cur_num >= r_ptr->max_num)) {
150                 continue;
151             }
152
153             if ((r_ptr->flags7 & (RF7_UNIQUE2)) && (r_ptr->cur_num >= 1)) {
154                 continue;
155             }
156
157             if (r_idx == MON_BANORLUPART) {
158                 if (r_info[MON_BANOR].cur_num > 0)
159                     continue;
160                 if (r_info[MON_LUPART].cur_num > 0)
161                     continue;
162             }
163         }
164
165         prob_table.entry_item(i, entry.prob2);
166     }
167
168     if (cheat_hear) {
169         msg_format(_("モンスター第3次候補数:%d(%d-%dF)%d ", "monster third selection:%d(%d-%dF)%d "), prob_table.item_count(), min_level, max_level,
170             prob_table.total_prob());
171     }
172
173     if (prob_table.empty())
174         return 0;
175
176     // 40%で1回、50%で2回、10%で3回抽選し、その中で一番レベルが高いモンスターを選択する
177     int n = 1;
178
179     const int p = randint0(100);
180     if (p < 60)
181         n++;
182     if (p < 10)
183         n++;
184
185     std::vector<int> result;
186     ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, n);
187
188     auto it = std::max_element(result.begin(), result.end(), [](int a, int b) { return alloc_race_table[a].level < alloc_race_table[b].level; });
189
190     return alloc_race_table[*it].index;
191 }
192
193 /*!
194  * @param player_ptr プレイヤーへの参照ポインタ
195  * @brief カメレオンの王の変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
196  * @param r_idx モンスター種族ID
197  * @return 対象にできるならtrueを返す
198  */
199 static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MONRACE_IDX r_idx)
200 {
201     auto *floor_ptr = player_ptr->current_floor_ptr;
202     auto *r_ptr = &r_info[r_idx];
203     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
204     monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
205
206     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE))
207         return false;
208     if (r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY) || (r_ptr->flags7 & RF7_CHAMELEON))
209         return false;
210
211     if (std::abs(r_ptr->level - r_info[MON_CHAMELEON_K].level) > 5)
212         return false;
213
214     if ((r_ptr->blow[0].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[1].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[2].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[3].method == RaceBlowMethodType::EXPLODE))
215         return false;
216
217     if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
218         return false;
219
220     if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
221         if (monster_has_hostile_align(player_ptr, m_ptr, 0, 0, r_ptr))
222             return false;
223     } else if (summon_specific_who > 0) {
224         if (monster_has_hostile_align(player_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
225             return false;
226     }
227
228     return true;
229 }
230
231 /*!
232  * @brief カメレオンの変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
233  * @param r_idx モンスター種族ID
234  * @return 対象にできるならtrueを返す
235  * @todo グローバル変数対策の上 monster_hook.cへ移す。
236  */
237 static bool monster_hook_chameleon(PlayerType *player_ptr, MONRACE_IDX r_idx)
238 {
239     auto *floor_ptr = player_ptr->current_floor_ptr;
240     auto *r_ptr = &r_info[r_idx];
241     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
242     monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
243
244     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE))
245         return false;
246     if (r_ptr->flags2 & RF2_MULTIPLY)
247         return false;
248     if (r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY) && (r_ptr->flags7 & RF7_CHAMELEON))
249         return false;
250
251     if ((r_ptr->blow[0].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[1].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[2].method == RaceBlowMethodType::EXPLODE) || (r_ptr->blow[3].method == RaceBlowMethodType::EXPLODE))
252         return false;
253
254     if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
255         return false;
256
257     if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
258         if (old_r_ptr->kind_flags.has(MonsterKindType::GOOD) && r_ptr->kind_flags.has_not(MonsterKindType::GOOD))
259             return false;
260         if (old_r_ptr->kind_flags.has(MonsterKindType::EVIL) && r_ptr->kind_flags.has_not(MonsterKindType::EVIL))
261             return false;
262         if (old_r_ptr->kind_flags.has_none_of(alignment_mask))
263             return false;
264     } else if (summon_specific_who > 0) {
265         if (monster_has_hostile_align(player_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
266             return false;
267     }
268
269     auto hook_pf = get_monster_hook(player_ptr);
270     return (*hook_pf)(player_ptr, r_idx);
271 }
272
273 /*!
274  * @brief モンスターの変身処理
275  * @param player_ptr プレイヤーへの参照ポインタ
276  * @param m_idx 変身処理を受けるモンスター情報のID
277  * @param born 生成時の初変身先指定ならばtrue
278  * @param r_idx 旧モンスター種族のID
279  */
280 void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, MONRACE_IDX r_idx)
281 {
282     auto *floor_ptr = player_ptr->current_floor_ptr;
283     auto *m_ptr = &floor_ptr->m_list[m_idx];
284     monster_race *r_ptr;
285
286     bool old_unique = false;
287     if (r_info[m_ptr->r_idx].kind_flags.has(MonsterKindType::UNIQUE))
288         old_unique = true;
289     if (old_unique && (r_idx == MON_CHAMELEON))
290         r_idx = MON_CHAMELEON_K;
291     r_ptr = &r_info[r_idx];
292
293     char old_m_name[MAX_NLEN];
294     monster_desc(player_ptr, old_m_name, m_ptr, 0);
295
296     if (!r_idx) {
297         DEPTH level;
298
299         chameleon_change_m_idx = m_idx;
300         if (old_unique)
301             get_mon_num_prep(player_ptr, monster_hook_chameleon_lord, nullptr);
302         else
303             get_mon_num_prep(player_ptr, monster_hook_chameleon, nullptr);
304
305         if (old_unique)
306             level = r_info[MON_CHAMELEON_K].level;
307         else if (!floor_ptr->dun_level)
308             level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
309         else
310             level = floor_ptr->dun_level;
311
312         if (d_info[player_ptr->dungeon_idx].flags.has(DungeonFeatureType::CHAMELEON))
313             level += 2 + randint1(3);
314
315         r_idx = get_mon_num(player_ptr, 0, level, 0);
316         r_ptr = &r_info[r_idx];
317
318         chameleon_change_m_idx = 0;
319         if (!r_idx)
320             return;
321     }
322
323     m_ptr->r_idx = r_idx;
324     m_ptr->ap_r_idx = r_idx;
325     update_monster(player_ptr, m_idx, false);
326     lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
327
328     int old_r_idx = m_ptr->r_idx;
329     if ((r_info[old_r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)) || (r_ptr->flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)))
330         player_ptr->update |= (PU_MON_LITE);
331
332     if (born) {
333         if (r_ptr->kind_flags.has_any_of(alignment_mask)) {
334             m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
335             if (r_ptr->kind_flags.has(MonsterKindType::EVIL))
336                 m_ptr->sub_align |= SUB_ALIGN_EVIL;
337             if (r_ptr->kind_flags.has(MonsterKindType::GOOD))
338                 m_ptr->sub_align |= SUB_ALIGN_GOOD;
339         }
340
341         return;
342     }
343
344     if (m_idx == player_ptr->riding) {
345         GAME_TEXT m_name[MAX_NLEN];
346         monster_desc(player_ptr, m_name, m_ptr, 0);
347         msg_format(_("突然%sが変身した。", "Suddenly, %s transforms!"), old_m_name);
348         if (!(r_ptr->flags7 & RF7_RIDING))
349             if (process_fall_off_horse(player_ptr, 0, true))
350                 msg_format(_("地面に落とされた。", "You have fallen from %s."), m_name);
351     }
352
353     m_ptr->mspeed = get_mspeed(floor_ptr, r_ptr);
354
355     int oldmaxhp = m_ptr->max_maxhp;
356     if (r_ptr->flags1 & RF1_FORCE_MAXHP) {
357         m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
358     } else {
359         m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
360     }
361
362     if (ironman_nightmare) {
363         auto hp = m_ptr->max_maxhp * 2;
364         m_ptr->max_maxhp = std::min(MONSTER_MAXHP, hp);
365     }
366
367     m_ptr->maxhp = (long)(m_ptr->maxhp * m_ptr->max_maxhp) / oldmaxhp;
368     if (m_ptr->maxhp < 1)
369         m_ptr->maxhp = 1;
370     m_ptr->hp = (long)(m_ptr->hp * m_ptr->max_maxhp) / oldmaxhp;
371     m_ptr->dealt_damage = 0;
372 }
373
374 /*!
375  * @brief モンスターの個体加速を設定する / Get initial monster speed
376  * @param r_ptr モンスター種族の参照ポインタ
377  * @return 加速値
378  */
379 byte get_mspeed(floor_type *floor_ptr, monster_race *r_ptr)
380 {
381     auto mspeed = r_ptr->speed;
382     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && !floor_ptr->inside_arena) {
383         /* Allow some small variation per monster */
384         int i = speed_to_energy(r_ptr->speed) / (one_in_(4) ? 3 : 10);
385         if (i)
386             mspeed += rand_spread(0, i);
387     }
388
389     if (mspeed > 199)
390         mspeed = 199;
391
392     return mspeed;
393 }
394
395 /*!
396  * @brief 指定したモンスターに隣接しているモンスターの数を返す。
397  * / Count number of adjacent monsters
398  * @param player_ptr プレイヤーへの参照ポインタ
399  * @param m_idx 隣接数を調べたいモンスターのID
400  * @return 隣接しているモンスターの数
401  */
402 int get_monster_crowd_number(floor_type *floor_ptr, MONSTER_IDX m_idx)
403 {
404     auto *m_ptr = &floor_ptr->m_list[m_idx];
405     POSITION my = m_ptr->fy;
406     POSITION mx = m_ptr->fx;
407     int count = 0;
408     for (int i = 0; i < 7; i++) {
409         int ay = my + ddy_ddd[i];
410         int ax = mx + ddx_ddd[i];
411
412         if (!in_bounds(floor_ptr, ay, ax))
413             continue;
414         if (floor_ptr->grid_array[ay][ax].m_idx > 0)
415             count++;
416     }
417
418     return count;
419 }