2 * @brief モンスター処理 / misc code for monsters
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.
12 #include "monster/monster-list.h"
13 #include "core/player-update-types.h"
14 #include "core/speed-table.h"
15 #include "dungeon/dungeon.h"
16 #include "floor/floor-object.h"
17 #include "floor/wild.h"
18 #include "game-option/birth-options.h"
19 #include "grid/grid.h"
20 #include "monster-floor/monster-summon.h"
21 #include "monster-race/monster-race.h"
22 #include "monster-race/race-flags1.h"
23 #include "monster-race/race-flags2.h"
24 #include "monster-race/race-flags3.h"
25 #include "monster-race/race-flags7.h"
26 #include "monster-race/race-indice-types.h"
27 #include "monster/monster-describer.h"
28 #include "monster/monster-info.h"
29 #include "monster/monster-update.h"
30 #include "monster/monster-util.h"
31 #include "object/object-generator.h"
32 #include "pet/pet-fall-off.h"
33 #include "system/alloc-entries.h"
34 #include "system/floor-type-definition.h"
35 #include "view/display-messages.h"
36 #include "world/world.h"
38 #define HORDE_NOGOOD 0x01 /*!< (未実装フラグ)HORDE生成でGOODなモンスターの生成を禁止する? */
39 #define HORDE_NOEVIL 0x02 /*!< (未実装フラグ)HORDE生成でEVILなモンスターの生成を禁止する? */
42 * @brief モンスター配列の空きを探す / Acquires and returns the index of a "free" monster.
43 * @return 利用可能なモンスター配列の添字
45 * This routine should almost never fail, but it *can* happen.
47 MONSTER_IDX m_pop(floor_type *floor_ptr)
49 /* Normal allocation */
50 if (floor_ptr->m_max < current_world_ptr->max_m_idx) {
51 MONSTER_IDX i = floor_ptr->m_max;
57 /* Recycle dead monsters */
58 for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
60 m_ptr = &floor_ptr->m_list[i];
67 if (current_world_ptr->character_dungeon)
68 msg_print(_("モンスターが多すぎる!", "Too many monsters!"));
73 * @brief 生成モンスター種族を1種生成テーブルから選択する
74 * @param player_ptr プレーヤーへの参照ポインタ
76 * @return 選択されたモンスター生成種族
78 MONRACE_IDX get_mon_num(player_type *player_ptr, DEPTH level, BIT_FLAGS option)
84 alloc_entry *table = alloc_race_table;
86 int pls_kakuritu, pls_level, over_days;
87 int delay = mysqrt(level * 10000L) + (level * 5);
89 /* town level : same delay as 10F, no nasty mons till day18 */
93 if (level > MAX_DEPTH - 1)
94 level = MAX_DEPTH - 1;
96 /* +1 per day after the base date */
97 /* base dates : day5(1F), day18(10F,0F), day34(30F), day53(60F), day69(90F) */
98 over_days = MAX(0, current_world_ptr->dungeon_turn / (TURNS_PER_TICK * 10000L) - delay / 20);
100 /* starts from 1/25, reaches 1/3 after 44days from a level dependent base date */
101 pls_kakuritu = MAX(NASTY_MON_MAX, NASTY_MON_BASE - over_days / 2);
102 /* starts from 0, reaches +25lv after 75days from a level dependent base date */
103 pls_level = MIN(NASTY_MON_PLUS_MAX, over_days / 3);
105 if (d_info[player_ptr->dungeon_idx].flags1 & DF1_MAZE) {
106 pls_kakuritu = MIN(pls_kakuritu / 2, pls_kakuritu - 10);
107 if (pls_kakuritu < 2)
113 /* Boost the level */
114 if (!player_ptr->phase_out && !(d_info[player_ptr->dungeon_idx].flags1 & DF1_BEGINNER)) {
115 /* Nightmare mode allows more out-of depth monsters */
116 if (ironman_nightmare && !randint0(pls_kakuritu)) {
117 /* What a bizarre calculation */
118 level = 1 + (level * MAX_DEPTH / randint1(MAX_DEPTH));
120 /* Occasional "nasty" monster */
121 if (!randint0(pls_kakuritu)) {
122 /* Pick a level bonus */
130 /* Process probabilities */
131 for (i = 0; i < alloc_race_size; i++) {
132 if (table[i].level > level)
135 r_idx = table[i].index;
136 r_ptr = &r_info[r_idx];
137 if (!(option & GMN_ARENA) && !chameleon_change_m_idx) {
138 if (((r_ptr->flags1 & (RF1_UNIQUE)) || (r_ptr->flags7 & (RF7_NAZGUL))) && (r_ptr->cur_num >= r_ptr->max_num)) {
142 if ((r_ptr->flags7 & (RF7_UNIQUE2)) && (r_ptr->cur_num >= 1)) {
146 if (r_idx == MON_BANORLUPART) {
147 if (r_info[MON_BANOR].cur_num > 0)
149 if (r_info[MON_LUPART].cur_num > 0)
154 table[i].prob3 = table[i].prob2;
155 total += table[i].prob3;
161 value = randint0(total);
163 for (i = 0; i < alloc_race_size; i++) {
164 if (value < table[i].prob3)
166 value = value - table[i].prob3;
172 /* Try for a "harder" monster once (50%) or twice (10%) */
175 value = randint0(total);
176 for (found_count = 0; found_count < alloc_race_size; found_count++) {
177 if (value < table[found_count].prob3)
180 value = value - table[found_count].prob3;
183 if (table[found_count].level < table[j].level)
187 /* Try for a "harder" monster twice (10%) */
190 value = randint0(total);
191 for (found_count = 0; found_count < alloc_race_size; found_count++) {
192 if (value < table[found_count].prob3)
195 value = value - table[found_count].prob3;
198 if (table[found_count].level < table[j].level)
202 return (table[found_count].index);
206 * @param player_ptr プレーヤーへの参照ポインタ
207 * @brief カメレオンの王の変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
208 * @param r_idx モンスター種族ID
209 * @return 対象にできるならtrueを返す
211 static bool monster_hook_chameleon_lord(player_type *player_ptr, MONRACE_IDX r_idx)
213 floor_type *floor_ptr = player_ptr->current_floor_ptr;
214 monster_race *r_ptr = &r_info[r_idx];
215 monster_type *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
216 monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
218 if (!(r_ptr->flags1 & (RF1_UNIQUE)))
220 if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
223 if (ABS(r_ptr->level - r_info[MON_CHAMELEON_K].level) > 5)
226 if ((r_ptr->blow[0].method == RBM_EXPLODE) || (r_ptr->blow[1].method == RBM_EXPLODE) || (r_ptr->blow[2].method == RBM_EXPLODE)
227 || (r_ptr->blow[3].method == RBM_EXPLODE))
230 if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
233 if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
234 if (monster_has_hostile_align(player_ptr, m_ptr, 0, 0, r_ptr))
236 } else if (summon_specific_who > 0) {
237 if (monster_has_hostile_align(player_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
245 * @brief カメレオンの変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster
246 * @param r_idx モンスター種族ID
247 * @return 対象にできるならtrueを返す
248 * @todo グローバル変数対策の上 monster_hook.cへ移す。
250 static bool monster_hook_chameleon(player_type *player_ptr, MONRACE_IDX r_idx)
252 floor_type *floor_ptr = player_ptr->current_floor_ptr;
253 monster_race *r_ptr = &r_info[r_idx];
254 monster_type *m_ptr = &floor_ptr->m_list[chameleon_change_m_idx];
255 monster_race *old_r_ptr = &r_info[m_ptr->r_idx];
257 if (r_ptr->flags1 & (RF1_UNIQUE))
259 if (r_ptr->flags2 & RF2_MULTIPLY)
261 if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
264 if ((r_ptr->blow[0].method == RBM_EXPLODE) || (r_ptr->blow[1].method == RBM_EXPLODE) || (r_ptr->blow[2].method == RBM_EXPLODE)
265 || (r_ptr->blow[3].method == RBM_EXPLODE))
268 if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
271 if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
272 if ((old_r_ptr->flags3 & RF3_GOOD) && !(r_ptr->flags3 & RF3_GOOD))
274 if ((old_r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags3 & RF3_EVIL))
276 if (!(old_r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)) && (r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)))
278 } else if (summon_specific_who > 0) {
279 if (monster_has_hostile_align(player_ptr, &floor_ptr->m_list[summon_specific_who], 0, 0, r_ptr))
283 return (*(get_monster_hook(player_ptr)))(player_ptr, r_idx);
288 * @param player_ptr プレーヤーへの参照ポインタ
289 * @param m_idx 変身処理を受けるモンスター情報のID
290 * @param born 生成時の初変身先指定ならばtrue
291 * @param r_idx 旧モンスター種族のID
294 void choose_new_monster(player_type *player_ptr, MONSTER_IDX m_idx, bool born, MONRACE_IDX r_idx)
296 floor_type *floor_ptr = player_ptr->current_floor_ptr;
297 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
300 bool old_unique = FALSE;
301 if (r_info[m_ptr->r_idx].flags1 & RF1_UNIQUE)
303 if (old_unique && (r_idx == MON_CHAMELEON))
304 r_idx = MON_CHAMELEON_K;
305 r_ptr = &r_info[r_idx];
307 char old_m_name[MAX_NLEN];
308 monster_desc(player_ptr, old_m_name, m_ptr, 0);
313 chameleon_change_m_idx = m_idx;
315 get_mon_num_prep(player_ptr, monster_hook_chameleon_lord, NULL);
317 get_mon_num_prep(player_ptr, monster_hook_chameleon, NULL);
320 level = r_info[MON_CHAMELEON_K].level;
321 else if (!floor_ptr->dun_level)
322 level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
324 level = floor_ptr->dun_level;
326 if (d_info[player_ptr->dungeon_idx].flags1 & DF1_CHAMELEON)
327 level += 2 + randint1(3);
329 r_idx = get_mon_num(player_ptr, level, 0);
330 r_ptr = &r_info[r_idx];
332 chameleon_change_m_idx = 0;
337 m_ptr->r_idx = r_idx;
338 m_ptr->ap_r_idx = r_idx;
339 update_monster(player_ptr, m_idx, FALSE);
340 lite_spot(player_ptr, m_ptr->fy, m_ptr->fx);
342 int old_r_idx = m_ptr->r_idx;
343 if ((r_info[old_r_idx].flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)) || (r_ptr->flags7 & (RF7_LITE_MASK | RF7_DARK_MASK)))
344 player_ptr->update |= (PU_MON_LITE);
347 if (r_ptr->flags3 & (RF3_EVIL | RF3_GOOD)) {
348 m_ptr->sub_align = SUB_ALIGN_NEUTRAL;
349 if (r_ptr->flags3 & RF3_EVIL)
350 m_ptr->sub_align |= SUB_ALIGN_EVIL;
351 if (r_ptr->flags3 & RF3_GOOD)
352 m_ptr->sub_align |= SUB_ALIGN_GOOD;
358 if (m_idx == player_ptr->riding) {
359 GAME_TEXT m_name[MAX_NLEN];
360 monster_desc(player_ptr, m_name, m_ptr, 0);
361 msg_format(_("突然%sが変身した。", "Suddenly, %s transforms!"), old_m_name);
362 if (!(r_ptr->flags7 & RF7_RIDING))
363 if (process_fall_off_horse(player_ptr, 0, TRUE))
364 msg_format(_("地面に落とされた。", "You have fallen from %s."), m_name);
367 m_ptr->mspeed = get_mspeed(player_ptr, r_ptr);
369 int oldmaxhp = m_ptr->max_maxhp;
370 if (r_ptr->flags1 & RF1_FORCE_MAXHP) {
371 m_ptr->max_maxhp = maxroll(r_ptr->hdice, r_ptr->hside);
373 m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
376 if (ironman_nightmare) {
377 u32b hp = m_ptr->max_maxhp * 2L;
378 m_ptr->max_maxhp = (HIT_POINT)MIN(30000, hp);
381 m_ptr->maxhp = (long)(m_ptr->maxhp * m_ptr->max_maxhp) / oldmaxhp;
382 if (m_ptr->maxhp < 1)
384 m_ptr->hp = (long)(m_ptr->hp * m_ptr->max_maxhp) / oldmaxhp;
385 m_ptr->dealt_damage = 0;
389 * todo ここには本来floor_type*を追加したいが、monster.hにfloor.hの参照を追加するとコンパイルエラーが出るので保留
390 * @brief モンスターの個体加速を設定する / Get initial monster speed
391 * @param r_ptr モンスター種族の参照ポインタ
394 SPEED get_mspeed(player_type *player_ptr, monster_race *r_ptr)
396 SPEED mspeed = r_ptr->speed;
397 if (!(r_ptr->flags1 & RF1_UNIQUE) && !player_ptr->current_floor_ptr->inside_arena) {
398 /* Allow some small variation per monster */
399 int i = SPEED_TO_ENERGY(r_ptr->speed) / (one_in_(4) ? 3 : 10);
401 mspeed += rand_spread(0, i);
411 * @brief 指定したモンスターに隣接しているモンスターの数を返す。
412 * / Count number of adjacent monsters
413 * @param player_ptr プレーヤーへの参照ポインタ
414 * @param m_idx 隣接数を調べたいモンスターのID
415 * @return 隣接しているモンスターの数
417 int get_monster_crowd_number(floor_type *floor_ptr, MONSTER_IDX m_idx)
419 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
420 POSITION my = m_ptr->fy;
421 POSITION mx = m_ptr->fx;
423 for (int i = 0; i < 7; i++) {
424 int ay = my + ddy_ddd[i];
425 int ax = mx + ddx_ddd[i];
427 if (!in_bounds(floor_ptr, ay, ax))
429 if (floor_ptr->grid_array[ay][ax].m_idx > 0)