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"
7 #include "grid/feature.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-flags-resistance.h"
12 #include "monster-race/race-flags1.h"
13 #include "monster-race/race-flags7.h"
14 #include "monster-race/race-indice-types.h"
15 #include "spell/summon-types.h"
16 #include "system/alloc-entries.h"
17 #include "system/floor-type-definition.h"
18 #include "system/grid-type-definition.h"
19 #include "system/monster-race-definition.h"
20 #include "system/player-type-definition.h"
21 #include "util/bit-flags-calculator.h"
22 #include "view/display-messages.h"
24 enum dungeon_mode_type {
26 DUNGEON_MODE_NAND = 2,
31 MONSTER_IDX hack_m_idx = 0; /* Hack -- see "process_monsters()" */
32 MONSTER_IDX hack_m_idx_ii = 0;
35 * @var chameleon_change_m_idx
36 * @brief カメレオンの変身先モンスターIDを受け渡すためのグローバル変数
37 * @todo 変数渡しの問題などもあるができればchameleon_change_m_idxのグローバル変数を除去し、関数引き渡しに移行すること
39 int chameleon_change_m_idx = 0;
42 * @var summon_specific_type
43 * @brief 召喚条件を指定するグローバル変数 / Hack -- the "type" of the current "summon specific"
44 * @todo summon_specific_typeグローバル変数の除去と関数引数への代替を行う
46 summon_type summon_specific_type = SUMMON_NONE;
49 * @brief 指定されたモンスター種族がダンジョンの制限にかかるかどうかをチェックする / Some dungeon types restrict the possible monsters.
50 * @param player_ptr プレイヤーへの参照ポインタ
51 * @param r_idx チェックするモンスター種族ID
52 * @return 召喚条件が一致するならtrue / Return TRUE is the monster is OK and FALSE otherwise
54 static bool restrict_monster_to_dungeon(PlayerType *player_ptr, MonsterRaceId r_idx)
56 DUNGEON_IDX d_idx = player_ptr->dungeon_idx;
57 dungeon_type *d_ptr = &d_info[d_idx];
58 auto *r_ptr = &r_info[r_idx];
60 if (d_ptr->flags.has(DungeonFeatureType::CHAMELEON)) {
61 if (chameleon_change_m_idx) {
66 if (d_ptr->flags.has(DungeonFeatureType::NO_MAGIC)) {
67 if (r_idx != MonsterRaceId::CHAMELEON && r_ptr->freq_spell && r_ptr->ability_flags.has_none_of(RF_ABILITY_NOMAGIC_MASK)) {
72 if (d_ptr->flags.has(DungeonFeatureType::NO_MELEE)) {
73 if (r_idx == MonsterRaceId::CHAMELEON) {
76 if (r_ptr->ability_flags.has_none_of(RF_ABILITY_BOLT_MASK | RF_ABILITY_BEAM_MASK | RF_ABILITY_BALL_MASK) && r_ptr->ability_flags.has_none_of(
77 { MonsterAbilityType::CAUSE_1, MonsterAbilityType::CAUSE_2, MonsterAbilityType::CAUSE_3, MonsterAbilityType::CAUSE_4, MonsterAbilityType::MIND_BLAST, MonsterAbilityType::BRAIN_SMASH })) {
82 auto *floor_ptr = player_ptr->current_floor_ptr;
83 if (d_ptr->flags.has(DungeonFeatureType::BEGINNER)) {
84 if (r_ptr->level > floor_ptr->dun_level) {
89 if (d_ptr->special_div >= 64) {
92 if (summon_specific_type && d_ptr->flags.has_not(DungeonFeatureType::CHAMELEON)) {
97 switch (d_ptr->mode) {
98 case DUNGEON_MODE_AND: {
100 if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1) {
105 if (d_ptr->mflags2) {
106 if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2) {
111 if (d_ptr->mflags3) {
112 if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3) {
117 if (d_ptr->mon_ability_flags.any()) {
118 if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags)) {
123 if (d_ptr->mon_behavior_flags.any()) {
124 if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags)) {
129 if (d_ptr->mflags7) {
130 if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7) {
135 if (d_ptr->mflags8) {
136 if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8) {
141 if (d_ptr->mflags9) {
142 if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9) {
147 if (d_ptr->mon_resistance_flags.any()) {
148 if (!r_ptr->resistance_flags.has_all_of(d_ptr->mon_resistance_flags)) {
153 if (d_ptr->mon_drop_flags.any()) {
154 if (!r_ptr->drop_flags.has_all_of(d_ptr->mon_drop_flags)) {
159 if (d_ptr->mon_kind_flags.any()) {
160 if (!r_ptr->kind_flags.has_all_of(d_ptr->mon_kind_flags)) {
165 for (a = 0; a < 5; a++) {
166 if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char)) {
173 case DUNGEON_MODE_NAND: {
174 if (d_ptr->mflags1) {
175 if ((d_ptr->mflags1 & r_ptr->flags1) != d_ptr->mflags1) {
180 if (d_ptr->mflags2) {
181 if ((d_ptr->mflags2 & r_ptr->flags2) != d_ptr->mflags2) {
186 if (d_ptr->mflags3) {
187 if ((d_ptr->mflags3 & r_ptr->flags3) != d_ptr->mflags3) {
192 if (d_ptr->mon_ability_flags.any()) {
193 if (!r_ptr->ability_flags.has_all_of(d_ptr->mon_ability_flags)) {
198 if (d_ptr->mon_behavior_flags.any()) {
199 if (!r_ptr->behavior_flags.has_all_of(d_ptr->mon_behavior_flags)) {
204 if (d_ptr->mflags7) {
205 if ((d_ptr->mflags7 & r_ptr->flags7) != d_ptr->mflags7) {
210 if (d_ptr->mflags8) {
211 if ((d_ptr->mflags8 & r_ptr->flags8) != d_ptr->mflags8) {
216 if (d_ptr->mflags9) {
217 if ((d_ptr->mflags9 & r_ptr->flags9) != d_ptr->mflags9) {
222 if (d_ptr->mon_resistance_flags.any()) {
223 if (!r_ptr->resistance_flags.has_all_of(d_ptr->mon_resistance_flags)) {
228 if (d_ptr->mon_drop_flags.any()) {
229 if (!r_ptr->drop_flags.has_all_of(d_ptr->mon_drop_flags)) {
234 if (d_ptr->mon_kind_flags.any()) {
235 if (!r_ptr->kind_flags.has_all_of(d_ptr->mon_kind_flags)) {
240 for (a = 0; a < 5; a++) {
241 if (d_ptr->r_char[a] && (d_ptr->r_char[a] != r_ptr->d_char)) {
248 case DUNGEON_MODE_OR: {
249 if (r_ptr->flags1 & d_ptr->mflags1) {
252 if (r_ptr->flags2 & d_ptr->mflags2) {
255 if (r_ptr->flags3 & d_ptr->mflags3) {
258 if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags)) {
261 if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags)) {
264 if (r_ptr->flags7 & d_ptr->mflags7) {
267 if (r_ptr->flags8 & d_ptr->mflags8) {
270 if (r_ptr->flags9 & d_ptr->mflags9) {
273 if (r_ptr->resistance_flags.has_any_of(d_ptr->mon_resistance_flags)) {
276 if (r_ptr->drop_flags.has_any_of(d_ptr->mon_drop_flags)) {
279 if (r_ptr->kind_flags.has_any_of(d_ptr->mon_kind_flags)) {
282 for (a = 0; a < 5; a++) {
283 if (d_ptr->r_char[a] == r_ptr->d_char) {
290 case DUNGEON_MODE_NOR: {
291 if (r_ptr->flags1 & d_ptr->mflags1) {
294 if (r_ptr->flags2 & d_ptr->mflags2) {
297 if (r_ptr->flags3 & d_ptr->mflags3) {
300 if (r_ptr->ability_flags.has_any_of(d_ptr->mon_ability_flags)) {
303 if (r_ptr->behavior_flags.has_any_of(d_ptr->mon_behavior_flags)) {
306 if (r_ptr->flags7 & d_ptr->mflags7) {
309 if (r_ptr->flags8 & d_ptr->mflags8) {
312 if (r_ptr->flags9 & d_ptr->mflags9) {
315 if (r_ptr->resistance_flags.has_any_of(d_ptr->mon_resistance_flags)) {
318 if (r_ptr->drop_flags.has_any_of(d_ptr->mon_drop_flags)) {
321 if (r_ptr->kind_flags.has_any_of(d_ptr->mon_kind_flags)) {
324 for (a = 0; a < 5; a++) {
325 if (d_ptr->r_char[a] == r_ptr->d_char) {
338 * @brief プレイヤーの現在の広域マップ座標から得た地勢を元にモンスターの生成条件関数を返す
339 * @param player_ptr プレイヤーへの参照ポインタ
340 * @return 地勢にあったモンスターの生成条件関数
342 monsterrace_hook_type get_monster_hook(PlayerType *player_ptr)
344 if ((player_ptr->current_floor_ptr->dun_level > 0) || (inside_quest(player_ptr->current_floor_ptr->quest_number))) {
345 return (monsterrace_hook_type)mon_hook_dungeon;
348 switch (wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].terrain) {
350 return (monsterrace_hook_type)mon_hook_town;
351 case TERRAIN_DEEP_WATER:
352 return (monsterrace_hook_type)mon_hook_ocean;
353 case TERRAIN_SHALLOW_WATER:
355 return (monsterrace_hook_type)mon_hook_shore;
358 return (monsterrace_hook_type)mon_hook_waste;
360 return (monsterrace_hook_type)mon_hook_grass;
362 return (monsterrace_hook_type)mon_hook_wood;
363 case TERRAIN_SHALLOW_LAVA:
364 case TERRAIN_DEEP_LAVA:
365 return (monsterrace_hook_type)mon_hook_volcano;
366 case TERRAIN_MOUNTAIN:
367 return (monsterrace_hook_type)mon_hook_mountain;
369 return (monsterrace_hook_type)mon_hook_dungeon;
374 * @brief 指定された広域マップ座標の地勢を元にモンスターの生成条件関数を返す
375 * @return 地勢にあったモンスターの生成条件関数
377 monsterrace_hook_type get_monster_hook2(PlayerType *player_ptr, POSITION y, POSITION x)
379 auto *f_ptr = &f_info[player_ptr->current_floor_ptr->grid_array[y][x].feat];
380 if (f_ptr->flags.has(FloorFeatureType::WATER)) {
381 return f_ptr->flags.has(FloorFeatureType::DEEP) ? (monsterrace_hook_type)mon_hook_deep_water : (monsterrace_hook_type)mon_hook_shallow_water;
384 if (f_ptr->flags.has(FloorFeatureType::LAVA)) {
385 return (monsterrace_hook_type)mon_hook_lava;
388 return (monsterrace_hook_type)mon_hook_floor;
392 * @brief モンスター生成テーブルの重みを指定条件に従って変更する。
394 * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
395 * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
396 * @param restrict_to_dungeon 現在プレイヤーのいるダンジョンの制約を適用するか
399 * モンスター生成テーブル alloc_race_table の各要素の基本重み prob1 を指定条件
400 * に従って変更し、結果を prob2 に書き込む。
402 static errr do_get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2, const bool restrict_to_dungeon)
404 const floor_type *const floor_ptr = player_ptr->current_floor_ptr;
407 int mon_num = 0; // 重み(prob2)が正の要素数
408 DEPTH lev_min = MAX_DEPTH; // 重みが正の要素のうち最小階
409 DEPTH lev_max = 0; // 重みが正の要素のうち最大階
410 int prob2_total = 0; // 重みの総和
412 // モンスター生成テーブルの各要素について重みを修正する。
413 for (auto i = 0U; i < alloc_race_table.size(); i++) {
414 alloc_entry *const entry = &alloc_race_table[i];
415 const auto entry_r_idx = i2enum<MonsterRaceId>(entry->index);
416 const monster_race *const r_ptr = &r_info[entry_r_idx];
418 // 生成を禁止する要素は重み 0 とする。
422 // テーブル内の無効エントリもこれに該当する(alloc_race_table は生成時にゼロクリアされるため)。
423 if (entry->prob1 <= 0) {
427 // いずれかの生成制約関数が偽を返したら生成禁止。
428 if ((hook1 && !hook1(player_ptr, entry_r_idx)) || (hook2 && !hook2(player_ptr, entry_r_idx))) {
432 // 原則生成禁止するものたち(フェイズアウト状態 / カメレオンの変身先 / ダンジョンの主召喚 は例外)。
433 if (!player_ptr->phase_out && !chameleon_change_m_idx && summon_specific_type != SUMMON_GUARDIANS) {
435 if (r_ptr->flags1 & RF1_QUESTOR) {
440 if (r_ptr->flags7 & RF7_GUARDIAN) {
444 // RF1_FORCE_DEPTH フラグ持ちは指定階未満では生成禁止。
445 if ((r_ptr->flags1 & RF1_FORCE_DEPTH) && (r_ptr->level > floor_ptr->dun_level)) {
449 // クエスト内でRES_ALLの生成を禁止する (殲滅系クエストの詰み防止)
450 if (inside_quest(player_ptr->current_floor_ptr->quest_number) && r_ptr->resistance_flags.has(MonsterResistanceType::RESIST_ALL)) {
455 // 生成を許可するものは基本重みをそのまま引き継ぐ。
456 entry->prob2 = entry->prob1;
458 // 引数で指定されていればさらにダンジョンによる制約を試みる。
459 if (restrict_to_dungeon) {
460 // ダンジョンによる制約を適用する条件:
465 const bool in_random_quest = inside_quest(floor_ptr->quest_number) && !quest_type::is_fixed(floor_ptr->quest_number);
466 const bool cond = !player_ptr->phase_out && floor_ptr->dun_level > 0 && !in_random_quest;
468 if (cond && !restrict_monster_to_dungeon(player_ptr, entry_r_idx)) {
469 // ダンジョンによる制約に掛かった場合、重みを special_div/64 倍する。
471 const int numer = entry->prob2 * d_info[player_ptr->dungeon_idx].special_div;
472 const int q = numer / 64;
473 const int r = numer % 64;
474 entry->prob2 = (PROB)(randint0(64) < r ? q + 1 : q);
479 if (entry->prob2 > 0) {
481 if (lev_min > entry->level) {
482 lev_min = entry->level;
484 if (lev_max < entry->level) {
485 lev_max = entry->level;
487 prob2_total += entry->prob2;
491 // チートオプションが有効なら統計情報を出力。
493 msg_format(_("モンスター第2次候補数:%d(%d-%dF)%d ", "monster second selection:%d(%d-%dF)%d "), mon_num, lev_min, lev_max, prob2_total);
500 * @brief モンスター生成テーブルの重み修正
502 * @param hook1 生成制約関数1 (nullptr の場合、制約なし)
503 * @param hook2 生成制約関数2 (nullptr の場合、制約なし)
506 * get_mon_num() を呼ぶ前に get_mon_num_prep() 系関数のいずれかを呼ぶこと。
508 errr get_mon_num_prep(PlayerType *player_ptr, const monsterrace_hook_type hook1, const monsterrace_hook_type hook2)
510 return do_get_mon_num_prep(player_ptr, hook1, hook2, true);
514 * @brief モンスター生成テーブルの重み修正(賞金首選定用)
517 * get_mon_num() を呼ぶ前に get_mon_num_prep 系関数のいずれかを呼ぶこと。
519 errr get_mon_num_prep_bounty(PlayerType *player_ptr)
521 return do_get_mon_num_prep(player_ptr, nullptr, nullptr, false);