OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[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/speed-table.h"
14 #include "dungeon/dungeon-flag-types.h"
15 #include "floor/cave.h"
16 #include "floor/floor-object.h"
17 #include "floor/geometry.h"
18 #include "floor/wild.h"
19 #include "game-option/birth-options.h"
20 #include "game-option/cheat-options.h"
21 #include "grid/grid.h"
22 #include "monster-floor/monster-summon.h"
23 #include "monster-floor/place-monster-types.h"
24 #include "monster-race/monster-kind-mask.h"
25 #include "monster-race/monster-race.h"
26 #include "monster-race/race-brightness-mask.h"
27 #include "monster-race/race-indice-types.h"
28 #include "monster/monster-describer.h"
29 #include "monster/monster-info.h"
30 #include "monster/monster-update.h"
31 #include "monster/monster-util.h"
32 #include "pet/pet-fall-off.h"
33 #include "player/player-status.h"
34 #include "system/alloc-entries.h"
35 #include "system/dungeon-info.h"
36 #include "system/floor-type-definition.h"
37 #include "system/grid-type-definition.h"
38 #include "system/monster-entity.h"
39 #include "system/monster-race-info.h"
40 #include "system/player-type-definition.h"
41 #include "system/redrawing-flags-updater.h"
42 #include "util/bit-flags-calculator.h"
43 #include "util/probability-table.h"
44 #include "view/display-messages.h"
45 #include "world/world.h"
46 #include <cmath>
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(FloorType *floor_ptr)
59 {
60     /* Normal allocation */
61     if (floor_ptr->m_max < MAX_FLOOR_MONSTERS) {
62         const auto 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 (short i = 1; i < floor_ptr->m_max; i++) {
70         const auto &monster = floor_ptr->m_list[i];
71         if (monster.is_valid()) {
72             continue;
73         }
74
75         floor_ptr->m_cnt++;
76         return i;
77     }
78
79     if (w_ptr->character_dungeon) {
80         msg_print(_("モンスターが多すぎる!", "Too many monsters!"));
81     }
82
83     return 0;
84 }
85
86 /*!
87  * @brief 生成モンスター種族を1種生成テーブルから選択する
88  * @param player_ptr プレイヤーへの参照ポインタ
89  * @param min_level 最小生成階
90  * @param max_level 最大生成階
91  * @return 選択されたモンスター生成種族
92  * @details nasty生成 (ゲーム内経過日数に応じて、現在フロアより深いフロアのモンスターを出現させる仕様)は
93  */
94 MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode)
95 {
96     /* town max_level : same delay as 10F, no nasty mons till day18 */
97     auto delay = static_cast<int>(std::sqrt(max_level * 10000)) + (max_level * 5);
98     if (!max_level) {
99         delay = 360;
100     }
101
102     if (max_level > MAX_DEPTH - 1) {
103         max_level = MAX_DEPTH - 1;
104     }
105
106     /* +1 per day after the base date */
107     /* base dates : day5(1F), day18(10F,0F), day34(30F), day53(60F), day69(90F) */
108     const auto over_days = std::max<int>(0, w_ptr->dungeon_turn / (TURNS_PER_TICK * 10000L) - delay / 20);
109
110     /* Probability starts from 1/25, reaches 1/3 after 44days from a max_level dependent base date */
111     /* Boost level starts from 0, reaches +25lv after 75days from a max_level dependent base date */
112     constexpr auto chance_nasty_monster = 25;
113     constexpr auto max_num_nasty_monsters = 3;
114     constexpr auto max_depth_nasty_monster = 25;
115     auto chance_nasty = std::max(max_num_nasty_monsters, chance_nasty_monster - over_days / 2);
116     auto nasty_level = std::min(max_depth_nasty_monster, over_days / 3);
117     const auto &floor = *player_ptr->current_floor_ptr;
118     const auto &dungeon = floor.get_dungeon_definition();
119     if (dungeon.flags.has(DungeonFeatureType::MAZE)) {
120         chance_nasty = std::min(chance_nasty / 2, chance_nasty - 10);
121         if (chance_nasty < 2) {
122             chance_nasty = 2;
123         }
124
125         nasty_level += 2;
126         max_level += 3;
127     }
128
129     /* Boost the max_level */
130     if (any_bits(mode, PM_ARENA) || dungeon.flags.has_not(DungeonFeatureType::BEGINNER)) {
131         /* Nightmare mode allows more out-of depth monsters */
132         if (ironman_nightmare && !randint0(chance_nasty)) {
133             /* What a bizarre calculation */
134             max_level = 1 + (max_level * MAX_DEPTH / randint1(MAX_DEPTH));
135         } else {
136             /* Occasional "nasty" monster */
137             if (!randint0(chance_nasty)) {
138                 /* Pick a max_level bonus */
139                 max_level += nasty_level;
140             }
141         }
142     }
143
144     ProbabilityTable<int> prob_table;
145
146     /* Process probabilities */
147     const auto &monraces = MonraceList::get_instance();
148     for (auto i = 0U; i < alloc_race_table.size(); i++) {
149         const auto &entry = alloc_race_table[i];
150         if (entry.level < min_level) {
151             continue;
152         }
153         if (max_level < entry.level) {
154             break;
155         } // sorted by depth array,
156         auto r_idx = i2enum<MonsterRaceId>(entry.index);
157         auto r_ptr = &monraces_info[r_idx];
158         if (none_bits(mode, PM_ARENA) && !chameleon_change_m_idx) {
159             if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num) && none_bits(mode, PM_CLONE)) {
160                 continue;
161             }
162
163             if (r_ptr->population_flags.has(MonsterPopulationType::ONLY_ONE) && (r_ptr->cur_num >= 1)) {
164                 continue;
165             }
166
167             if (!monraces.is_selectable(r_idx)) {
168                 continue;
169             }
170         }
171
172         prob_table.entry_item(i, entry.prob2);
173     }
174
175     if (cheat_hear) {
176         msg_format(_("モンスター第3次候補数:%lu(%d-%dF)%d ", "monster third selection:%lu(%d-%dF)%d "), prob_table.item_count(), min_level, max_level,
177             prob_table.total_prob());
178     }
179
180     if (prob_table.empty()) {
181         return MonsterRace::empty_id();
182     }
183
184     // 40%で1回、50%で2回、10%で3回抽選し、その中で一番レベルが高いモンスターを選択する
185     int n = 1;
186
187     const int p = randint0(100);
188     if (p < 60) {
189         n++;
190     }
191     if (p < 10) {
192         n++;
193     }
194
195     std::vector<int> result;
196     ProbabilityTable<int>::lottery(std::back_inserter(result), prob_table, n);
197
198     auto it = std::max_element(result.begin(), result.end(), [](int a, int b) { return alloc_race_table[a].level < alloc_race_table[b].level; });
199
200     return i2enum<MonsterRaceId>(alloc_race_table[*it].index);
201 }
202
203 /*!
204  * @param player_ptr プレイヤーへの参照ポインタ
205  * @brief カメレオンの王の変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
206  * @param r_idx モンスター種族ID
207  * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID
208  * @return 対象にできるならtrueを返す
209  */
210 static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_idx, std::optional<MONSTER_IDX> summoner_m_idx)
211 {
212     auto *floor_ptr = player_ptr->current_floor_ptr;
213     auto *r_ptr = &monraces_info[r_idx];
214     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
215     MonsterRaceInfo *old_r_ptr = &m_ptr->get_monrace();
216
217     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
218         return false;
219     }
220     if (r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY) || r_ptr->misc_flags.has(MonsterMiscType::CHAMELEON)) {
221         return false;
222     }
223
224     if (std::abs(r_ptr->level - monraces_info[MonsterRaceId::CHAMELEON_K].level) > 5) {
225         return false;
226     }
227
228     if (m_ptr->is_explodable()) {
229         return false;
230     }
231
232     if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0)) {
233         return false;
234     }
235
236     if (old_r_ptr->misc_flags.has_not(MonsterMiscType::CHAMELEON)) {
237         if (monster_has_hostile_align(player_ptr, m_ptr, 0, 0, r_ptr)) {
238             return false;
239         }
240     } else if (summoner_m_idx && monster_has_hostile_align(player_ptr, &floor_ptr->m_list[*summoner_m_idx], 0, 0, r_ptr)) {
241         return false;
242     }
243
244     return true;
245 }
246
247 /*!
248  * @brief カメレオンの変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
249  * @param r_idx モンスター種族ID
250  * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID
251  * @return 対象にできるならtrueを返す
252  * @todo グローバル変数対策の上 monster_hook.cへ移す。
253  */
254 static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx, std::optional<MONSTER_IDX> summoner_m_idx)
255 {
256     auto *floor_ptr = player_ptr->current_floor_ptr;
257     auto *r_ptr = &monraces_info[r_idx];
258     auto *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
259     MonsterRaceInfo *old_r_ptr = &m_ptr->get_monrace();
260
261     if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
262         return false;
263     }
264     if (r_ptr->misc_flags.has(MonsterMiscType::MULTIPLY)) {
265         return false;
266     }
267     if (r_ptr->behavior_flags.has(MonsterBehaviorType::FRIENDLY) || (r_ptr->misc_flags.has(MonsterMiscType::CHAMELEON))) {
268         return false;
269     }
270
271     if (m_ptr->is_explodable()) {
272         return false;
273     }
274
275     if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0)) {
276         return false;
277     }
278
279     if (old_r_ptr->misc_flags.has_not(MonsterMiscType::CHAMELEON)) {
280         if (old_r_ptr->kind_flags.has(MonsterKindType::GOOD) && r_ptr->kind_flags.has_not(MonsterKindType::GOOD)) {
281             return false;
282         }
283         if (old_r_ptr->kind_flags.has(MonsterKindType::EVIL) && r_ptr->kind_flags.has_not(MonsterKindType::EVIL)) {
284             return false;
285         }
286         if (old_r_ptr->kind_flags.has_none_of(alignment_mask)) {
287             return false;
288         }
289     } else if (summoner_m_idx && monster_has_hostile_align(player_ptr, &floor_ptr->m_list[*summoner_m_idx], 0, 0, r_ptr)) {
290         return false;
291     }
292
293     auto hook_pf = get_monster_hook(player_ptr);
294     return hook_pf(player_ptr, r_idx);
295 }
296
297 /*!
298  * @brief モンスターの変身処理
299  * @param player_ptr プレイヤーへの参照ポインタ
300  * @param m_idx 変身処理を受けるモンスター情報のID
301  * @param born 生成時の初変身先指定ならばtrue
302  * @param r_idx 旧モンスター種族のID
303  * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID
304  */
305 void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, MonsterRaceId r_idx, std::optional<MONSTER_IDX> summoner_m_idx)
306 {
307     auto *floor_ptr = player_ptr->current_floor_ptr;
308     auto *m_ptr = &floor_ptr->m_list[m_idx];
309     MonsterRaceInfo *r_ptr;
310
311     bool old_unique = false;
312     if (m_ptr->get_monrace().kind_flags.has(MonsterKindType::UNIQUE)) {
313         old_unique = true;
314     }
315     if (old_unique && (r_idx == MonsterRaceId::CHAMELEON)) {
316         r_idx = MonsterRaceId::CHAMELEON_K;
317     }
318     r_ptr = &monraces_info[r_idx];
319
320     const auto old_m_name = monster_desc(player_ptr, m_ptr, 0);
321
322     if (!MonraceList::is_valid(r_idx)) {
323         DEPTH level;
324
325         chameleon_change_m_idx = m_idx;
326         if (old_unique) {
327             auto hook = [summoner_m_idx](PlayerType *player_ptr, MonsterRaceId r_idx) { return monster_hook_chameleon_lord(player_ptr, r_idx, summoner_m_idx); };
328             get_mon_num_prep(player_ptr, std::move(hook), nullptr);
329         } else {
330             auto hook = [summoner_m_idx](PlayerType *player_ptr, MonsterRaceId r_idx) { return monster_hook_chameleon(player_ptr, r_idx, summoner_m_idx); };
331             get_mon_num_prep(player_ptr, std::move(hook), nullptr);
332         }
333
334         if (old_unique) {
335             level = monraces_info[MonsterRaceId::CHAMELEON_K].level;
336         } else if (!floor_ptr->dun_level) {
337             level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
338         } else {
339             level = floor_ptr->dun_level;
340         }
341
342         if (floor_ptr->get_dungeon_definition().flags.has(DungeonFeatureType::CHAMELEON)) {
343             level += 2 + randint1(3);
344         }
345
346         r_idx = get_mon_num(player_ptr, 0, level, 0);
347         r_ptr = &monraces_info[r_idx];
348
349         chameleon_change_m_idx = 0;
350         if (!MonraceList::is_valid(r_idx)) {
351             return;
352         }
353     }
354
355     m_ptr->r_idx = r_idx;
356     m_ptr->ap_r_idx = r_idx;
357     update_monster(player_ptr, m_idx, false);
358     lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
359
360     const auto &new_monrace = m_ptr->get_monrace();
361     if (new_monrace.brightness_flags.has_any_of(ld_mask) || r_ptr->brightness_flags.has_any_of(ld_mask)) {
362         RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::MONSTER_LITE);
363     }
364
365     if (born) {
366         if (r_ptr->kind_flags.has_any_of(alignment_mask)) {
367             m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
368             if (r_ptr->kind_flags.has(MonsterKindType::EVIL)) {
369                 m_ptr->sub_align |= SUB_ALIGN_EVIL;
370             }
371             if (r_ptr->kind_flags.has(MonsterKindType::GOOD)) {
372                 m_ptr->sub_align |= SUB_ALIGN_GOOD;
373             }
374         }
375
376         return;
377     }
378
379     if (m_idx == player_ptr->riding) {
380         msg_format(_("突然%sが変身した。", "Suddenly, %s transforms!"), old_m_name.data());
381         if (r_ptr->misc_flags.has_not(MonsterMiscType::RIDING)) {
382             if (process_fall_off_horse(player_ptr, 0, true)) {
383                 const auto m_name = monster_desc(player_ptr, m_ptr, 0);
384                 msg_print(_("地面に落とされた。", format("You have fallen from %s.", m_name.data())));
385             }
386         }
387     }
388
389     m_ptr->mspeed = get_mspeed(floor_ptr, r_ptr);
390
391     int oldmaxhp = m_ptr->max_maxhp;
392     if (r_ptr->misc_flags.has(MonsterMiscType::FORCE_MAXHP)) {
393         m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
394     } else {
395         m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
396     }
397
398     if (ironman_nightmare) {
399         auto hp = m_ptr->max_maxhp * 2;
400         m_ptr->max_maxhp = std::min(MONSTER_MAXHP, hp);
401     }
402
403     m_ptr->maxhp = (long)(m_ptr->maxhp * m_ptr->max_maxhp) / oldmaxhp;
404     if (m_ptr->maxhp < 1) {
405         m_ptr->maxhp = 1;
406     }
407     m_ptr->hp = (long)(m_ptr->hp * m_ptr->max_maxhp) / oldmaxhp;
408     m_ptr->dealt_damage = 0;
409 }
410
411 /*!
412  * @brief モンスターの個体加速を設定する / Get initial monster speed
413  * @param r_ptr モンスター種族の参照ポインタ
414  * @return 加速値
415  */
416 byte get_mspeed(FloorType *floor_ptr, MonsterRaceInfo *r_ptr)
417 {
418     auto mspeed = r_ptr->speed;
419     if (r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE) && !floor_ptr->inside_arena) {
420         /* Allow some small variation per monster */
421         int i = speed_to_energy(r_ptr->speed) / (one_in_(4) ? 3 : 10);
422         if (i) {
423             mspeed += rand_spread(0, i);
424         }
425     }
426
427     if (mspeed > 199) {
428         mspeed = 199;
429     }
430
431     return mspeed;
432 }
433
434 /*!
435  * @brief 指定したモンスターに隣接しているモンスターの数を返す。
436  * / Count number of adjacent monsters
437  * @param player_ptr プレイヤーへの参照ポインタ
438  * @param m_idx 隣接数を調べたいモンスターのID
439  * @return 隣接しているモンスターの数
440  */
441 int get_monster_crowd_number(FloorType *floor_ptr, MONSTER_IDX m_idx)
442 {
443     auto *m_ptr = &floor_ptr->m_list[m_idx];
444     POSITION my = m_ptr->fy;
445     POSITION mx = m_ptr->fx;
446     int count = 0;
447     for (int i = 0; i < 7; i++) {
448         int ay = my + ddy_ddd[i];
449         int ax = mx + ddx_ddd[i];
450
451         if (!in_bounds(floor_ptr, ay, ax)) {
452             continue;
453         }
454         if (floor_ptr->grid_array[ay][ax].has_monster()) {
455             count++;
456         }
457     }
458
459     return count;
460 }