OSDN Git Service

[Refactor] #40014 Separated monster-summonc./h from monster-generator.c/h
[hengband/hengband.git] / src / monster / monster-list.c
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.h"
15 #include "floor/floor-object.h"
16 #include "floor/wild.h"
17 #include "monster-floor/monster-summon.h"
18 #include "monster-race/race-flags1.h"
19 #include "monster-race/race-flags2.h"
20 #include "monster-race/race-flags3.h"
21 #include "monster-race/race-flags7.h"
22 #include "monster-race/race-indice-types.h"
23 #include "monster/monster-describer.h"
24 #include "monster/monster-info.h"
25 #include "monster/monster-update.h"
26 #include "monster/monster-util.h"
27 #include "object/object-generator.h"
28 #include "pet/pet-fall-off.h"
29 #include "world/world.h"
30
31 #define HORDE_NOGOOD 0x01 /*!< (未実装フラグ)HORDE生成でGOODなモンスターの生成を禁止する? */
32 #define HORDE_NOEVIL 0x02 /*!< (未実装フラグ)HORDE生成でEVILなモンスターの生成を禁止する? */
33
34 /*!
35  * @brief モンスター配列の空きを探す / Acquires and returns the index of a "free" monster.
36  * @return 利用可能なモンスター配列の添字
37  * @details
38  * This routine should almost never fail, but it *can* happen.
39  */
40 MONSTER_IDX m_pop(floor_type *floor_ptr)
41 {
42     /* Normal allocation */
43     if (floor_ptr->m_max < current_world_ptr->max_m_idx) {
44         MONSTER_IDX i = floor_ptr->m_max;
45         floor_ptr->m_max++;
46         floor_ptr->m_cnt++;
47         return i;
48     }
49
50     /* Recycle dead monsters */
51     for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
52         monster_type *m_ptr;
53         m_ptr = &floor_ptr->m_list[i];
54         if (m_ptr->r_idx)
55             continue;
56         floor_ptr->m_cnt++;
57         return i;
58     }
59
60     if (current_world_ptr->character_dungeon)
61         msg_print(_("モンスターが多すぎる!", "Too many monsters!"));
62     return 0;
63 }
64
65 /*!
66  * @brief 生成モンスター種族を1種生成テーブルから選択する
67  * @param player_ptr プレーヤーへの参照ポインタ
68  * @param level 生成階
69  * @return 選択されたモンスター生成種族
70  */
71 MONRACE_IDX get_mon_num(player_type *player_ptr, DEPTH level, BIT_FLAGS option)
72 {
73     int i, j, p;
74     int r_idx;
75     long value, total;
76     monster_race *r_ptr;
77     alloc_entry *table = alloc_race_table;
78
79     int pls_kakuritu, pls_level, over_days;
80     int delay = mysqrt(level * 10000L) + (level * 5);
81
82     /* town level : same delay as 10F, no nasty mons till day18 */
83     if (!level)
84         delay = 360;
85
86     if (level > MAX_DEPTH - 1)
87         level = MAX_DEPTH - 1;
88
89     /* +1 per day after the base date */
90     /* base dates : day5(1F), day18(10F,0F), day34(30F), day53(60F), day69(90F) */
91     over_days = MAX(0, current_world_ptr->dungeon_turn / (TURNS_PER_TICK * 10000L) - delay / 20);
92
93     /* starts from 1/25, reaches 1/3 after 44days from a level dependent base date */
94     pls_kakuritu = MAX(NASTY_MON_MAX, NASTY_MON_BASE - over_days / 2);
95     /* starts from 0, reaches +25lv after 75days from a level dependent base date */
96     pls_level = MIN(NASTY_MON_PLUS_MAX, over_days / 3);
97
98     if (d_info[player_ptr->dungeon_idx].flags1 & DF1_MAZE) {
99         pls_kakuritu = MIN(pls_kakuritu / 2, pls_kakuritu - 10);
100         if (pls_kakuritu < 2)
101             pls_kakuritu = 2;
102         pls_level += 2;
103         level += 3;
104     }
105
106     /* Boost the level */
107     if (!player_ptr->phase_out && !(d_info[player_ptr->dungeon_idx].flags1 & DF1_BEGINNER)) {
108         /* Nightmare mode allows more out-of depth monsters */
109         if (ironman_nightmare && !randint0(pls_kakuritu)) {
110             /* What a bizarre calculation */
111             level = 1 + (level * MAX_DEPTH / randint1(MAX_DEPTH));
112         } else {
113             /* Occasional "nasty" monster */
114             if (!randint0(pls_kakuritu)) {
115                 /* Pick a level bonus */
116                 level += pls_level;
117             }
118         }
119     }
120
121     total = 0L;
122
123     /* Process probabilities */
124     for (i = 0; i < alloc_race_size; i++) {
125         if (table[i].level > level)
126             break;
127         table[i].prob3 = 0;
128         r_idx = table[i].index;
129         r_ptr = &r_info[r_idx];
130         if (!(option & GMN_ARENA) && !chameleon_change_m_idx) {
131             if (((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags7 & (RF7_NAZGUL))) && (r_ptr->cur_num >= r_ptr->max_num)) {
132                 continue;
133             }
134
135             if ((r_ptr->flags7 & (RF7_UNIQUE2)) && (r_ptr->cur_num >= 1)) {
136                 continue;
137             }
138
139             if (r_idx == MON_BANORLUPART) {
140                 if (r_info[MON_BANOR].cur_num > 0)
141                     continue;
142                 if (r_info[MON_LUPART].cur_num > 0)
143                     continue;
144             }
145         }
146
147         table[i].prob3 = table[i].prob2;
148         total += table[i].prob3;
149     }
150
151     if (total <= 0)
152         return 0;
153
154     value = randint0(total);
155     int found_count = 0;
156     for (i = 0; i < alloc_race_size; i++) {
157         if (value < table[i].prob3)
158             break;
159         value = value - table[i].prob3;
160         found_count++;
161     }
162
163     p = randint0(100);
164
165     /* Try for a "harder" monster once (50%) or twice (10%) */
166     if (p < 60) {
167         j = found_count;
168         value = randint0(total);
169         for (found_count = 0; found_count < alloc_race_size; found_count++) {
170             if (value < table[found_count].prob3)
171                 break;
172
173             value = value - table[found_count].prob3;
174         }
175
176         if (table[found_count].level < table[j].level)
177             found_count = j;
178     }
179
180     /* Try for a "harder" monster twice (10%) */
181     if (p < 10) {
182         j = found_count;
183         value = randint0(total);
184         for (found_count = 0; found_count < alloc_race_size; found_count++) {
185             if (value < table[found_count].prob3)
186                 break;
187
188             value = value - table[found_count].prob3;
189         }
190
191         if (table[found_count].level < table[j].level)
192             found_count = j;
193     }
194
195     return (table[found_count].index);
196 }
197
198 /*!
199  * todo ここにplayer_typeを追加すると関数ポインタ周りの収拾がつかなくなるので保留
200  * @param player_ptr プレーヤーへの参照ポインタ
201  * @brief カメレオンの王の変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
202  * @param r_idx モンスター種族ID
203  * @return 対象にできるならtrueを返す
204  */
205 static bool monster_hook_chameleon_lord(MONRACE_IDX r_idx)
206 {
207     floor_type *floor_ptr = p_ptr->current_floor_ptr;
208     monster_race *r_ptr = &r_info[r_idx];
209     monster_type *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
210     monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
211
212     if (!(r_ptr->flags1 & (RF1_UNIQUE)))
213         return FALSE;
214     if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
215         return FALSE;
216
217     if (ABS(r_ptr->level - r_info[MON_CHAMELEON_K].level) > 5)
218         return FALSE;
219
220     if ((r_ptr->blow[0].method == RBM_EXPLODE) || (r_ptr->blow[1].method == RBM_EXPLODE) || (r_ptr->blow[2].method == RBM_EXPLODE)
221         || (r_ptr->blow[3].method == RBM_EXPLODE))
222         return FALSE;
223
224     if (!monster_can_cross_terrain(p_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
225         return FALSE;
226
227     if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
228         if (monster_has_hostile_align(p_ptr, m_ptr, 0, 0, r_ptr))
229             return FALSE;
230     } else if (summon_specific_who > 0) {
231         if (monster_has_hostile_align(p_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
232             return FALSE;
233     }
234
235     return TRUE;
236 }
237
238 /*!
239  * todo ここにplayer_typeを追加すると関数ポインタ周りの収拾がつかなくなるので保留
240  * @brief カメレオンの変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
241  * @param r_idx モンスター種族ID
242  * @return 対象にできるならtrueを返す
243  * @todo グローバル変数対策の上 monster_hook.cへ移す。
244  */
245 static bool monster_hook_chameleon(MONRACE_IDX r_idx)
246 {
247     floor_type *floor_ptr = p_ptr->current_floor_ptr;
248     monster_race *r_ptr = &r_info[r_idx];
249     monster_type *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
250     monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
251
252     if (r_ptr->flags1 & (RF1_UNIQUE))
253         return FALSE;
254     if (r_ptr->flags2 & RF2_MULTIPLY)
255         return FALSE;
256     if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
257         return FALSE;
258
259     if ((r_ptr->blow[0].method == RBM_EXPLODE) || (r_ptr->blow[1].method == RBM_EXPLODE) || (r_ptr->blow[2].method == RBM_EXPLODE)
260         || (r_ptr->blow[3].method == RBM_EXPLODE))
261         return FALSE;
262
263     if (!monster_can_cross_terrain(p_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
264         return FALSE;
265
266     if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
267         if ((old_r_ptr->flags3 & RF3_GOOD) && !(r_ptr->flags3 & RF3_GOOD))
268             return FALSE;
269         if ((old_r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags3 & RF3_EVIL))
270             return FALSE;
271         if (!(old_r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)) && (r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)))
272             return FALSE;
273     } else if (summon_specific_who > 0) {
274         if (monster_has_hostile_align(p_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
275             return FALSE;
276     }
277
278     return (*(get_monster_hook(p_ptr)))(r_idx);
279 }
280
281 /*!
282  * @brief モンスターの変身処理
283  * @param player_ptr プレーヤーへの参照ポインタ
284  * @param m_idx 変身処理を受けるモンスター情報のID
285  * @param born 生成時の初変身先指定ならばtrue
286  * @param r_idx 旧モンスター種族のID
287  * @return なし
288  */
289 void choose_new_monster(player_type *player_ptr, MONSTER_IDX m_idx, bool born, MONRACE_IDX r_idx)
290 {
291     floor_type *floor_ptr = player_ptr->current_floor_ptr;
292     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
293     monster_race *r_ptr;
294
295     bool old_unique = FALSE;
296     if (r_info[m_ptr->r_idx].flags1 & RF1_UNIQUE)
297         old_unique = TRUE;
298     if (old_unique && (r_idx == MON_CHAMELEON))
299         r_idx = MON_CHAMELEON_K;
300     r_ptr = &r_info[r_idx];
301
302     char old_m_name[MAX_NLEN];
303     monster_desc(player_ptr, old_m_name, m_ptr, 0);
304
305     if (!r_idx) {
306         DEPTH level;
307
308         chameleon_change_m_idx = m_idx;
309         if (old_unique)
310             get_mon_num_prep(player_ptr, monster_hook_chameleon_lord, NULL);
311         else
312             get_mon_num_prep(player_ptr, monster_hook_chameleon, NULL);
313
314         if (old_unique)
315             level = r_info[MON_CHAMELEON_K].level;
316         else if (!floor_ptr->dun_level)
317             level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
318         else
319             level = floor_ptr->dun_level;
320
321         if (d_info[player_ptr->dungeon_idx].flags1 & DF1_CHAMELEON)
322             level += 2 + randint1(3);
323
324         r_idx = get_mon_num(player_ptr, level, 0);
325         r_ptr = &r_info[r_idx];
326
327         chameleon_change_m_idx = 0;
328         if (!r_idx)
329             return;
330     }
331
332     m_ptr->r_idx = r_idx;
333     m_ptr->ap_r_idx = r_idx;
334     update_monster(player_ptr, m_idx, FALSE);
335     lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
336
337     int old_r_idx = m_ptr->r_idx;
338     if ((r_info[old_r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)) || (r_ptr->flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)))
339         player_ptr->update |= (PU_MON_LITE);
340
341     if (born) {
342         if (r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) {
343             m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
344             if (r_ptr->flags3 & RF3_EVIL)
345                 m_ptr->sub_align |= SUB_ALIGN_EVIL;
346             if (r_ptr->flags3 & RF3_GOOD)
347                 m_ptr->sub_align |= SUB_ALIGN_GOOD;
348         }
349
350         return;
351     }
352
353     if (m_idx == player_ptr->riding) {
354         GAME_TEXT m_name[MAX_NLEN];
355         monster_desc(player_ptr, m_name, m_ptr, 0);
356         msg_format(_("突然%sが変身した。", "Suddenly, %s transforms!"), old_m_name);
357         if (!(r_ptr->flags7 & RF7_RIDING))
358             if (process_fall_off_horse(player_ptr, 0, TRUE))
359                 msg_format(_("地面に落とされた。", "You have fallen from %s."), m_name);
360     }
361
362     m_ptr->mspeed = get_mspeed(player_ptr, r_ptr);
363
364     int oldmaxhp = m_ptr->max_maxhp;
365     if (r_ptr->flags1 & RF1_FORCE_MAXHP) {
366         m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
367     } else {
368         m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
369     }
370
371     if (ironman_nightmare) {
372         u32b hp = m_ptr->max_maxhp * 2L;
373         m_ptr->max_maxhp = (HIT_POINT)MIN(30000, hp);
374     }
375
376     m_ptr->maxhp = (long)(m_ptr->maxhp * m_ptr->max_maxhp) / oldmaxhp;
377     if (m_ptr->maxhp < 1)
378         m_ptr->maxhp = 1;
379     m_ptr->hp = (long)(m_ptr->hp * m_ptr->max_maxhp) / oldmaxhp;
380     m_ptr->dealt_damage = 0;
381 }
382
383 /*!
384  * todo ここには本来floor_type*を追加したいが、monster.hにfloor.hの参照を追加するとコンパイルエラーが出るので保留
385  * @brief モンスターの個体加速を設定する / Get initial monster speed
386  * @param r_ptr モンスター種族の参照ポインタ
387  * @return 加速値
388  */
389 SPEED get_mspeed(player_type *player_ptr, monster_race *r_ptr)
390 {
391     SPEED mspeed = r_ptr->speed;
392     if (!(r_ptr->flags1 & RF1_UNIQUE) && !player_ptr->current_floor_ptr->inside_arena) {
393         /* Allow some small variation per monster */
394         int i = SPEED_TO_ENERGY(r_ptr->speed) / (one_in_(4) ? 3 : 10);
395         if (i)
396             mspeed += rand_spread(0, i);
397     }
398
399     if (mspeed > 199)
400         mspeed = 199;
401
402     return mspeed;
403 }
404
405 /*!
406  * @brief 指定したモンスターに隣接しているモンスターの数を返す。
407  * / Count number of adjacent monsters
408  * @param player_ptr プレーヤーへの参照ポインタ
409  * @param m_idx 隣接数を調べたいモンスターのID
410  * @return 隣接しているモンスターの数
411  */
412 int get_monster_crowd_number(floor_type *floor_ptr, MONSTER_IDX m_idx)
413 {
414     monster_type *m_ptr = &floor_ptr->m_list[m_idx];
415     POSITION my = m_ptr->fy;
416     POSITION mx = m_ptr->fx;
417     int count = 0;
418     for (int i = 0; i < 7; i++) {
419         int ay = my + ddy_ddd[i];
420         int ax = mx + ddx_ddd[i];
421
422         if (!in_bounds(floor_ptr, ay, ax))
423             continue;
424         if (floor_ptr->grid_array[ay][ax].m_idx > 0)
425             count++;
426     }
427
428     return count;
429 }