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/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"
31 #define HORDE_NOGOOD 0x01 /*!< (未実装フラグ)HORDE生成でGOODなモンスターの生成を禁止する? */
32 #define HORDE_NOEVIL 0x02 /*!< (未実装フラグ)HORDE生成でEVILなモンスターの生成を禁止する? */
35 * @brief モンスター配列の空きを探す / Acquires and returns the index of a "free" monster.
36 * @return 利用可能なモンスター配列の添字
38 * This routine should almost never fail, but it *can* happen.
40 MONSTER_IDX m_pop(floor_type *floor_ptr)
42 /* Normal allocation */
43 if (floor_ptr->m_max < current_world_ptr->max_m_idx) {
44 MONSTER_IDX i = floor_ptr->m_max;
50 /* Recycle dead monsters */
51 for (MONSTER_IDX i = 1; i < floor_ptr->m_max; i++) {
53 m_ptr = &floor_ptr->m_list[i];
60 if (current_world_ptr->character_dungeon)
61 msg_print(_("モンスターが多すぎる!", "Too many monsters!"));
66 * @brief 生成モンスター種族を1種生成テーブルから選択する
67 * @param player_ptr プレーヤーへの参照ポインタ
69 * @return 選択されたモンスター生成種族
71 MONRACE_IDX get_mon_num(player_type *player_ptr, DEPTH level, BIT_FLAGS option)
77 alloc_entry *table = alloc_race_table;
79 int pls_kakuritu, pls_level, over_days;
80 int delay = mysqrt(level * 10000L) + (level * 5);
82 /* town level : same delay as 10F, no nasty mons till day18 */
86 if (level > MAX_DEPTH - 1)
87 level = MAX_DEPTH - 1;
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);
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);
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)
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));
113 /* Occasional "nasty" monster */
114 if (!randint0(pls_kakuritu)) {
115 /* Pick a level bonus */
123 /* Process probabilities */
124 for (i = 0; i < alloc_race_size; i++) {
125 if (table[i].level > level)
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)) {
135 if ((r_ptr->flags7 & (RF7_UNIQUE2)) && (r_ptr->cur_num >= 1)) {
139 if (r_idx == MON_BANORLUPART) {
140 if (r_info[MON_BANOR].cur_num > 0)
142 if (r_info[MON_LUPART].cur_num > 0)
147 table[i].prob3 = table[i].prob2;
148 total += table[i].prob3;
154 value = randint0(total);
156 for (i = 0; i < alloc_race_size; i++) {
157 if (value < table[i].prob3)
159 value = value - table[i].prob3;
165 /* Try for a "harder" monster once (50%) or twice (10%) */
168 value = randint0(total);
169 for (found_count = 0; found_count < alloc_race_size; found_count++) {
170 if (value < table[found_count].prob3)
173 value = value - table[found_count].prob3;
176 if (table[found_count].level < table[j].level)
180 /* Try for a "harder" monster twice (10%) */
183 value = randint0(total);
184 for (found_count = 0; found_count < alloc_race_size; found_count++) {
185 if (value < table[found_count].prob3)
188 value = value - table[found_count].prob3;
191 if (table[found_count].level < table[j].level)
195 return (table[found_count].index);
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を返す
205 static bool monster_hook_chameleon_lord(MONRACE_IDX r_idx)
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];
212 if (!(r_ptr->flags1 & (RF1_UNIQUE)))
214 if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
217 if (ABS(r_ptr->level - r_info[MON_CHAMELEON_K].level) > 5)
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))
224 if (!monster_can_cross_terrain(p_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
227 if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
228 if (monster_has_hostile_align(p_ptr, m_ptr, 0, 0, r_ptr))
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))
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へ移す。
245 static bool monster_hook_chameleon(MONRACE_IDX r_idx)
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];
252 if (r_ptr->flags1 & (RF1_UNIQUE))
254 if (r_ptr->flags2 & RF2_MULTIPLY)
256 if (r_ptr->flags7 & (RF7_FRIENDLY | RF7_CHAMELEON))
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))
263 if (!monster_can_cross_terrain(p_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0))
266 if (!(old_r_ptr->flags7 & RF7_CHAMELEON)) {
267 if ((old_r_ptr->flags3 & RF3_GOOD) && !(r_ptr->flags3 & RF3_GOOD))
269 if ((old_r_ptr->flags3 & RF3_EVIL) && !(r_ptr->flags3 & RF3_EVIL))
271 if (!(old_r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)) && (r_ptr->flags3 & (RF3_GOOD | RF3_EVIL)))
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))
278 return (*(get_monster_hook(p_ptr)))(r_idx);
283 * @param player_ptr プレーヤーへの参照ポインタ
284 * @param m_idx 変身処理を受けるモンスター情報のID
285 * @param born 生成時の初変身先指定ならばtrue
286 * @param r_idx 旧モンスター種族のID
289 void choose_new_monster(player_type *player_ptr, MONSTER_IDX m_idx, bool born, MONRACE_IDX r_idx)
291 floor_type *floor_ptr = player_ptr->current_floor_ptr;
292 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
295 bool old_unique = FALSE;
296 if (r_info[m_ptr->r_idx].flags1 & RF1_UNIQUE)
298 if (old_unique && (r_idx == MON_CHAMELEON))
299 r_idx = MON_CHAMELEON_K;
300 r_ptr = &r_info[r_idx];
302 char old_m_name[MAX_NLEN];
303 monster_desc(player_ptr, old_m_name, m_ptr, 0);
308 chameleon_change_m_idx = m_idx;
310 get_mon_num_prep(player_ptr, monster_hook_chameleon_lord, NULL);
312 get_mon_num_prep(player_ptr, monster_hook_chameleon, NULL);
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;
319 level = floor_ptr->dun_level;
321 if (d_info[player_ptr->dungeon_idx].flags1 & DF1_CHAMELEON)
322 level += 2 + randint1(3);
324 r_idx = get_mon_num(player_ptr, level, 0);
325 r_ptr = &r_info[r_idx];
327 chameleon_change_m_idx = 0;
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);
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);
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;
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);
362 m_ptr->mspeed = get_mspeed(player_ptr, r_ptr);
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);
368 m_ptr->max_maxhp = damroll(r_ptr->hdice, r_ptr->hside);
371 if (ironman_nightmare) {
372 u32b hp = m_ptr->max_maxhp * 2L;
373 m_ptr->max_maxhp = (HIT_POINT)MIN(30000, hp);
376 m_ptr->maxhp = (long)(m_ptr->maxhp * m_ptr->max_maxhp) / oldmaxhp;
377 if (m_ptr->maxhp < 1)
379 m_ptr->hp = (long)(m_ptr->hp * m_ptr->max_maxhp) / oldmaxhp;
380 m_ptr->dealt_damage = 0;
384 * todo ここには本来floor_type*を追加したいが、monster.hにfloor.hの参照を追加するとコンパイルエラーが出るので保留
385 * @brief モンスターの個体加速を設定する / Get initial monster speed
386 * @param r_ptr モンスター種族の参照ポインタ
389 SPEED get_mspeed(player_type *player_ptr, monster_race *r_ptr)
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);
396 mspeed += rand_spread(0, i);
406 * @brief 指定したモンスターに隣接しているモンスターの数を返す。
407 * / Count number of adjacent monsters
408 * @param player_ptr プレーヤーへの参照ポインタ
409 * @param m_idx 隣接数を調べたいモンスターのID
410 * @return 隣接しているモンスターの数
412 int get_monster_crowd_number(floor_type *floor_ptr, MONSTER_IDX m_idx)
414 monster_type *m_ptr = &floor_ptr->m_list[m_idx];
415 POSITION my = m_ptr->fy;
416 POSITION mx = m_ptr->fx;
418 for (int i = 0; i < 7; i++) {
419 int ay = my + ddy_ddd[i];
420 int ax = mx + ddx_ddd[i];
422 if (!in_bounds(floor_ptr, ay, ax))
424 if (floor_ptr->grid_array[ay][ax].m_idx > 0)