1 #include "monster/monster-util.h"
2 #include "dungeon/dungeon-flag-types.h"
3 #include "dungeon/dungeon.h"
4 #include "dungeon/quest.h"
5 #include "floor/wild.h"
6 #include "game-option/cheat-options.h"
8 #include "monster-race/monster-race-hook.h"
9 #include "monster-race/monster-race.h"
10 #include "monster-race/race-ability-mask.h"
11 #include "monster-race/race-flags1.h"
12 #include "monster-race/race-flags7.h"
13 #include "monster-race/race-indice-types.h"
14 #include "spell/summon-types.h"
15 #include "system/alloc-entries.h"
16 #include "system/floor-type-definition.h"
17 #include "util/bit-flags-calculator.h"
18 #include "view/display-messages.h"
20 enum dungeon_mode_type {
22 DUNGEON_MODE_NAND = 2,
27 MONSTER_IDX hack_m_idx = 0; /* Hack -- see "process_monsters()" */
28 MONSTER_IDX hack_m_idx_ii = 0;
31 * @var chameleon_change_m_idx
32 * @brief カメレオンの変身先モンスターIDを受け渡すためのグローバル変数
33 * @todo 変数渡しの問題などもあるができればchameleon_change_m_idxのグローバル変数を除去し、関数引き渡しに移行すること
35 int chameleon_change_m_idx = 0;
38 * @var summon_specific_type
39 * @brief 召喚条件を指定するグローバル変数 / Hack -- the "type" of the current "summon specific"
40 * @todo summon_specific_typeグローバル変数の除去と関数引数への代替を行う
42 summon_type summon_specific_type = SUMMON_NONE;
45 * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
46 * @param player_ptr プレーヤーへの参照ポインタ
47 * @param r_idx チェックするモンスター種族ID
48 * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
50 static bool restrict_monster_to_dungeon(player_type *player_ptr, MONRACE_IDX r_idx)
52 DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
53 dungeon_type *d_ptr = &d_info[d_idx];
54 monster_race *r_ptr = &r_info[r_idx];
56 if (d_ptr->flags1 & DF1_CHAMELEON) {
57 if (chameleon_change_m_idx)
61 if (d_ptr->flags1 & DF1_NO_MAGIC) {
62 if (r_idx != MON_CHAMELEON && r_ptr->freq_spell && r_ptr->ability_flags.has_none_of(RF_ABILITY_NOMAGIC_MASK))
66 if (d_ptr->flags1 & DF1_NO_MELEE) {
67 if (r_idx == MON_CHAMELEON)
69 if (r_ptr->ability_flags.has_none_of(RF_ABILITY_BOLT_MASK | RF_ABILITY_BEAM_MASK | RF_ABILITY_BALL_MASK)
70 && r_ptr->ability_flags.has_none_of(
71 { RF_ABILITY::CAUSE_1, RF_ABILITY::CAUSE_2, RF_ABILITY::CAUSE_3, RF_ABILITY::CAUSE_4, RF_ABILITY::MIND_BLAST, RF_ABILITY::BRAIN_SMASH }))
75 floor_type *floor_ptr = player_ptr->current_floor_ptr;
76 if (d_ptr->flags1 & DF1_BEGINNER) {
77 if (r_ptr->level > floor_ptr->dun_level)
81 if (d_ptr->special_div >= 64)
83 if (summon_specific_type && !(d_ptr->flags1 & DF1_CHAMELEON))
87 switch (d_ptr->mode) {
88 case DUNGEON_MODE_AND: {
90 if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
95 if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
100 if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
104 if (d_ptr->m_ability_flags.any()) {
105 if (!r_ptr->ability_flags.has_all_of(d_ptr->m_ability_flags))
109 if (d_ptr->mflags7) {
110 if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
114 if (d_ptr->mflags8) {
115 if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
119 if (d_ptr->mflags9) {
120 if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
124 if (d_ptr->mflagsr) {
125 if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
129 for (a = 0; a < 5; a++)
130 if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
135 case DUNGEON_MODE_NAND: {
136 if (d_ptr->mflags1) {
137 if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1)
141 if (d_ptr->mflags2) {
142 if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2)
146 if (d_ptr->mflags3) {
147 if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3)
151 if (d_ptr->m_ability_flags.any()) {
152 if (!r_ptr->ability_flags.has_all_of(d_ptr->m_ability_flags))
156 if (d_ptr->mflags7) {
157 if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7)
161 if (d_ptr->mflags8) {
162 if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8)
166 if (d_ptr->mflags9) {
167 if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9)
171 if (d_ptr->mflagsr) {
172 if ((d_ptr->mflagsr & r_ptr->flagsr) != d_ptr->mflagsr)
176 for (a = 0; a < 5; a++)
177 if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char))
182 case DUNGEON_MODE_OR: {
183 if (r_ptr->flags1 & d_ptr->mflags1)
185 if (r_ptr->flags2 & d_ptr->mflags2)
187 if (r_ptr->flags3 & d_ptr->mflags3)
189 if (r_ptr->ability_flags.has_any_of(d_ptr->m_ability_flags))
191 if (r_ptr->flags7 & d_ptr->mflags7)
193 if (r_ptr->flags8 & d_ptr->mflags8)
195 if (r_ptr->flags9 & d_ptr->mflags9)
197 if (r_ptr->flagsr & d_ptr->mflagsr)
199 for (a = 0; a < 5; a++)
200 if (d_ptr->r_char[a] == r_ptr->d_char)
205 case DUNGEON_MODE_NOR: {
206 if (r_ptr->flags1 & d_ptr->mflags1)
208 if (r_ptr->flags2 & d_ptr->mflags2)
210 if (r_ptr->flags3 & d_ptr->mflags3)
212 if (r_ptr->ability_flags.has_any_of(d_ptr->m_ability_flags))
214 if (r_ptr->flags7 & d_ptr->mflags7)
216 if (r_ptr->flags8 & d_ptr->mflags8)
218 if (r_ptr->flags9 & d_ptr->mflags9)
220 if (r_ptr->flagsr & d_ptr->mflagsr)
222 for (a = 0; a < 5; a++)
223 if (d_ptr->r_char[a] == r_ptr->d_char)
234 * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
235 * @param player_ptr プレーヤーへの参照ポインタ
236 * @return 地勢にあったモンスターの生成条件関数
238 monsterrace_hook_type get_monster_hook(player_type *player_ptr)
240 if ((player_ptr->current_floor_ptr->dun_level > 0) || (player_ptr->current_floor_ptr->inside_quest > 0))
241 return (monsterrace_hook_type)mon_hook_dungeon;
243 switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
245 return (monsterrace_hook_type)mon_hook_town;
246 case TERRAIN_DEEP_WATER:
247 return (monsterrace_hook_type)mon_hook_ocean;
248 case TERRAIN_SHALLOW_WATER:
250 return (monsterrace_hook_type)mon_hook_shore;
253 return (monsterrace_hook_type)mon_hook_waste;
255 return (monsterrace_hook_type)mon_hook_grass;
257 return (monsterrace_hook_type)mon_hook_wood;
258 case TERRAIN_SHALLOW_LAVA:
259 case TERRAIN_DEEP_LAVA:
260 return (monsterrace_hook_type)mon_hook_volcano;
261 case TERRAIN_MOUNTAIN:
262 return (monsterrace_hook_type)mon_hook_mountain;
264 return (monsterrace_hook_type)mon_hook_dungeon;
269 * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
270 * @return 地勢にあったモンスターの生成条件関数
272 monsterrace_hook_type get_monster_hook2(player_type *player_ptr, POSITION y, POSITION x)
274 feature_type *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
275 if (has_flag(f_ptr->flags, FF_WATER))
276 return has_flag(f_ptr->flags, FF_DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
278 if (has_flag(f_ptr->flags, FF_LAVA))
279 return (monsterrace_hook_type)mon_hook_lava;
281 return (monsterrace_hook_type)mon_hook_floor;
285 * @brief モンスター生成テーブルの重みを指定条件に従って変更する。
287 * @param hook1 生成制約関数1 (NULL の場合、制約なし)
288 * @param hook2 生成制約関数2 (NULL の場合、制約なし)
289 * @param restrict_to_dungeon 現在プレイヤーのいるダンジョンの制約を適用するか
292 * モンスター生成テーブル alloc_race_table の各要素の基本重み prob1 を指定条件
293 * に従って変更し、結果を prob2 に書き込む。
295 static errr do_get_mon_num_prep(player_type *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2, const bool restrict_to_dungeon)
297 const floor_type *const floor_ptr = player_ptr->current_floor_ptr;
300 int mon_num = 0; // 重み(prob2)が正の要素数
301 DEPTH lev_min = MAX_DEPTH; // 重みが正の要素のうち最小階
302 DEPTH lev_max = 0; // 重みが正の要素のうち最大階
303 int prob2_total = 0; // 重みの総和
305 // モンスター生成テーブルの各要素について重みを修正する。
306 for (int i = 0; i < alloc_race_size; i++) {
307 alloc_entry *const entry = &alloc_race_table[i];
308 const monster_race *const r_ptr = &r_info[entry->index];
310 // 生成を禁止する要素は重み 0 とする。
314 // テーブル内の無効エントリもこれに該当する(alloc_race_table は生成時にゼロクリアされるため)。
315 if (entry->prob1 <= 0)
318 // いずれかの生成制約関数が偽を返したら生成禁止。
319 if ((hook1 && !hook1(player_ptr, entry->index)) || (hook2 && !hook2(player_ptr, entry->index)))
322 // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
323 if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
325 if (r_ptr->flags1 & RF1_QUESTOR)
329 if (r_ptr->flags7 & RF7_GUARDIAN)
332 // RF1_FORCE_DEPTH フラグ持ちは指定階未満では生成禁止。
333 if ((r_ptr->flags1 & RF1_FORCE_DEPTH) && (r_ptr->level > floor_ptr->dun_level))
337 // 生成を許可するものは基本重みをそのまま引き継ぐ。
338 entry->prob2 = entry->prob1;
340 // 引数で指定されていればさらにダンジョンによる制約を試みる。
341 if (restrict_to_dungeon) {
342 // ダンジョンによる制約を適用する条件:
347 const bool in_random_quest = floor_ptr->inside_quest && !is_fixed_quest_idx(floor_ptr->inside_quest);
348 const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
350 if (cond && !restrict_monster_to_dungeon(player_ptr, entry->index)) {
351 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
353 const int numer = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
354 const int q = numer / 64;
355 const int r = numer % 64;
356 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
361 if (entry->prob2 > 0) {
363 if (lev_min > entry->level)
364 lev_min = entry->level;
365 if (lev_max < entry->level)
366 lev_max = entry->level;
367 prob2_total += entry->prob2;
371 // チートオプションが有効なら統計情報を出力。
373 msg_format(_("モンスター第2次候補数:%d(%d-%dF)%d ", "monster second selection:%d(%d-%dF)%d "), mon_num, lev_min, lev_max, prob2_total);
379 * @brief モンスター生成テーブルの重み修正
381 * @param hook1 生成制約関数1 (NULL の場合、制約なし)
382 * @param hook2 生成制約関数2 (NULL の場合、制約なし)
385 * get_mon_num() を呼ぶ前に get_mon_num_prep() 系関数のいずれかを呼ぶこと。
387 errr get_mon_num_prep(player_type *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2)
389 return do_get_mon_num_prep(player_ptr, hook1, hook2, TRUE);
393 * @brief モンスター生成テーブルの重み修正(賞金首選定用)
396 * get_mon_num() を呼ぶ前に get_mon_num_prep 系関数のいずれかを呼ぶこと。
398 errr get_mon_num_prep_bounty(player_type *player_ptr)
400 return do_get_mon_num_prep(player_ptr, NULL, NULL, FALSE);