OSDN Git Service

モンスター魔法「ユニークモンスター口寄せ」を追加。併せて使用するモンスターの追加、巨大サイバー以下略の使用魔法に追加、青魔法とものまねも追加。
authordaradarach <daradarach@gmail.com>
Sun, 9 Jul 2023 13:49:41 +0000 (22:49 +0900)
committerdaradarach <daradarach@gmail.com>
Tue, 11 Jul 2023 04:04:08 +0000 (13:04 +0900)
34 files changed:
lib/edit/MonsterRaceDefinitions.txt
src/birth/inventory-initializer.cpp
src/blue-magic/blue-magic-caster.cpp
src/blue-magic/blue-magic-summon.cpp
src/blue-magic/blue-magic-summon.h
src/cmd-action/cmd-mane.cpp
src/core/player-processor.cpp
src/dungeon/quest.cpp
src/info-reader/race-info-tokens-table.cpp
src/lore/magic-types-setter.cpp
src/market/arena.cpp
src/market/bounty.cpp
src/monster-floor/monster-death.cpp
src/monster-floor/monster-generator.cpp
src/monster-floor/monster-summon.cpp
src/monster-floor/one-monster-placer.cpp
src/monster-floor/place-monster-types.h
src/monster-race/monster-race-hook.cpp
src/monster-race/race-ability-flags.h
src/monster-race/race-ability-mask.cpp
src/monster/monster-list.cpp
src/monster/monster-list.h
src/mspell/assign-monster-spell.cpp
src/mspell/monster-power-table.cpp
src/mspell/mspell-damage-calculator.cpp
src/mspell/mspell-selector.cpp
src/mspell/mspell-summon.cpp
src/mspell/mspell-summon.h
src/mspell/summon-checker.cpp
src/object-enchant/others/apply-magic-others.cpp
src/player/eldritch-horror.cpp
src/room/rooms-pit-nest.cpp
src/spell-kind/spells-polymorph.cpp
src/spell/summon-types.h

index 2ff3876..6916542 100644 (file)
@@ -18889,7 +18889,7 @@ S:BO_PLAS | BO_ICEE | MISSILE | BLIND | CONF | SLOW | HOLD | HASTE | HAND_DOOM |
 S:HEAL | INVULNER | BLINK | TPORT | WORLD | TELE_TO | TELE_AWAY | TELE_LEVEL |
 S:PSY_SPEAR | DARKNESS | TRAPS | FORGET | ANIM_DEAD | S_KIN | S_CYBER | S_MONSTER |
 S:S_MONSTERS | S_ANT | S_SPIDER | S_HOUND | S_HYDRA | S_DEMON | S_UNDEAD |
-S:S_DRAGON | S_HI_UNDEAD | S_AMBERITES | S_UNIQUE | BA_LITE
+S:S_DRAGON | S_HI_UNDEAD | S_AMBERITES | S_UNIQUE | BA_LITE | S_DEAD_UNIQUE
 V:133
 D:$You don't know what it is.
 D:それは何が何だか分からない。
@@ -26719,3 +26719,27 @@ S:1_IN_6 | BR_ABYSS
 V:150
 D:$It's a abyssal whirlpool.
 D:深淵の渦巻きだ。
+
+N:1353:破壊と憎悪の化身『サルーイン』
+E:Saruin, The avatar of destruction and hatred
+G:P:w
+I:135:90d100:100:175:0
+W:82:3:0:66666:0:0
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+B:HIT:HURT:11d13
+F:UNIQUE | MALE | DROP_CORPSE | NONLIVING |
+F:ONLY_ITEM | DROP_2D2 | DROP_4D2 | DROP_GREAT |
+F:PREVENT_SUDDEN_MAGIC | FORCE_MAXHP | SMART |
+F:OPEN_DOOR | BASH_DOOR |
+F:EVIL | IM_ACID | IM_FIRE | IM_COLD | IM_ELEC | IM_POIS |
+F:RES_WATE | RES_SHAR | RES_LITE | RES_DARK |
+F:NO_CONF | NO_SLEEP | NO_FEAR | NO_STUN | RES_TELE
+S:1_IN_3 | S_DEAD_UNIQUE |
+S:BA_FIRE | BA_WATE | BA_ACID | ROCKET | DISPEL | BLIND | BO_MANA |
+S:HOLD | HEAL | HASTE | CONF | BRAIN_SMASH
+D:$He was born from the heart of Sayva, the goddess of destruction.
+D:$  Apparently, some foolish adventurer had given away all the Destiny Stones.
+D:破壊の女神サイヴァの心臓から生まれた存在だ。
+D:どうやら愚かなる冒険者がすべてのデステニィストーンを捧げてしまったらしい。
index 9b04274..47d3aa6 100644 (file)
@@ -4,6 +4,7 @@
 #include "floor/floor-object.h"
 #include "inventory/inventory-object.h"
 #include "inventory/inventory-slot-types.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster/monster-list.h"
 #include "monster/monster-util.h"
@@ -103,7 +104,7 @@ static void decide_initial_items(PlayerType *player_ptr, ItemEntity *q_ptr)
         get_mon_num_prep(player_ptr, monster_hook_human, nullptr);
         for (int i = rand_range(3, 4); i > 0; i--) {
             q_ptr->prep(lookup_baseitem_id({ ItemKindType::CORPSE, SV_CORPSE }));
-            q_ptr->pval = enum2i(get_mon_num(player_ptr, 0, 2, 0));
+            q_ptr->pval = enum2i(get_mon_num(player_ptr, 0, 2, PM_NONE));
             if (q_ptr->pval) {
                 q_ptr->number = 1;
                 add_outfit(player_ptr, q_ptr);
index d6e13b3..a40152d 100644 (file)
@@ -404,6 +404,8 @@ static bool switch_cast_blue_magic(PlayerType *player_ptr, bmc_type *bmc_ptr, Mo
         return cast_blue_summon_amberite(player_ptr, bmc_ptr);
     case MonsterAbilityType::S_UNIQUE:
         return cast_blue_summon_unique(player_ptr, bmc_ptr);
+    case MonsterAbilityType::S_DEAD_UNIQUE:
+        return cast_blue_summon_dead_unique(player_ptr, bmc_ptr);
     default:
         msg_print("hoge?");
         return true;
index f23adb7..cbc4e6c 100644 (file)
@@ -271,3 +271,24 @@ bool cast_blue_summon_unique(PlayerType *player_ptr, bmc_type *bmc_ptr)
 
     return true;
 }
+
+bool cast_blue_summon_dead_unique(PlayerType *player_ptr, bmc_type *bmc_ptr)
+{
+    int count = 0;
+    msg_print(_("特別な強敵を蘇らせた!", "You summon a special dead opponent!"));
+    for (int k = 0; k < 1; k++) {
+        if (summon_specific(player_ptr, (bmc_ptr->pet ? -1 : 0), player_ptr->y, player_ptr->x, bmc_ptr->summon_lev, SUMMON_DEAD_UNIQUE,
+                (bmc_ptr->g_mode | bmc_ptr->p_mode | PM_ALLOW_UNIQUE | PM_CLONE))) {
+            count++;
+            if (!bmc_ptr->pet) {
+                msg_print(_("蘇生されたユニーク・モンスターは怒っている!", "The summoned special dead opponent is angry!"));
+            }
+        }
+    }
+
+    if (!count) {
+        bmc_ptr->no_trump = true;
+    }
+
+    return true;
+}
index 79d90b2..096801c 100644 (file)
@@ -22,3 +22,4 @@ bool cast_blue_summon_high_undead(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_high_dragon(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_amberite(PlayerType *player_ptr, bmc_type *bmc_ptr);
 bool cast_blue_summon_unique(PlayerType *player_ptr, bmc_type *bmc_ptr);
+bool cast_blue_summon_dead_unique(PlayerType *player_ptr, bmc_type *bmc_ptr);
index bb596e9..ec34422 100644 (file)
@@ -1194,6 +1194,19 @@ static bool use_mane(PlayerType *player_ptr, MonsterAbilityType spell)
         }
         break;
     }
+    case MonsterAbilityType::S_DEAD_UNIQUE: {
+        int k, count = 0;
+        if (!target_set(player_ptr, TARGET_KILL)) {
+            return false;
+        }
+        msg_print(_("特別な強敵を蘇生した!", "You summon special dead opponents!"));
+        for (k = 0; k < 4; k++) {
+            if (summon_specific(player_ptr, -1, target_row, target_col, plev, SUMMON_DEAD_UNIQUE, (mode | PM_ALLOW_UNIQUE | PM_CLONE))) {
+                count++;
+            }
+        }
+        break;
+    }
     default:
         msg_print("hoge?");
     }
index 12f4e72..edce3dc 100644 (file)
@@ -79,7 +79,7 @@ static void process_fishing(PlayerType *player_ptr)
         auto *floor_ptr = player_ptr->current_floor_ptr;
         const auto wild_level = wilderness[player_ptr->wilderness_y][player_ptr->wilderness_x].level;
         const auto level = floor_ptr->is_in_dungeon() ? floor_ptr->dun_level : wild_level;
-        const auto r_idx = get_mon_num(player_ptr, 0, level, 0);
+        const auto r_idx = get_mon_num(player_ptr, 0, level, PM_NONE);
         msg_print(nullptr);
         if (MonsterRace(r_idx).is_valid() && one_in_(2)) {
             POSITION y, x;
index 10aa7d1..35ad042 100644 (file)
@@ -12,6 +12,7 @@
 #include "locale/english.h"
 #include "main/music-definitions-table.h"
 #include "main/sound-of-music.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -184,7 +185,7 @@ void determine_random_questor(PlayerType *player_ptr, QuestType *q_ptr)
     get_mon_num_prep(player_ptr, mon_hook_quest, nullptr);
     MonsterRaceId r_idx;
     while (true) {
-        r_idx = get_mon_num(player_ptr, 0, q_ptr->level + 5 + randint1(q_ptr->level / 10), GMN_ARENA);
+        r_idx = get_mon_num(player_ptr, 0, q_ptr->level + 5 + randint1(q_ptr->level / 10), PM_ARENA);
         const auto &monrace = monraces_info[r_idx];
         if (monrace.kind_flags.has_not(MonsterKindType::UNIQUE)) {
             continue;
index aac612e..1100150 100644 (file)
@@ -244,6 +244,7 @@ const std::unordered_map<std::string_view, MonsterAbilityType> r_info_ability_fl
        {"S_HI_DRAGON", MonsterAbilityType::S_HI_DRAGON },
        {"S_AMBERITES", MonsterAbilityType::S_AMBERITES },
        {"S_UNIQUE", MonsterAbilityType::S_UNIQUE },
+       {"S_DEAD_UNIQUE", MonsterAbilityType::S_DEAD_UNIQUE },
 };
 /* clang-format on */
 
index b2316ff..501a896 100644 (file)
@@ -569,4 +569,9 @@ void set_summon_types(lore_type *lore_ptr)
         lore_ptr->vp[lore_ptr->vn] = _("ユニーク・モンスター召喚", "summon Unique Monsters");
         lore_ptr->color[lore_ptr->vn++] = TERM_VIOLET;
     }
+
+    if (lore_ptr->ability_flags.has(MonsterAbilityType::S_DEAD_UNIQUE)) {
+        lore_ptr->vp[lore_ptr->vn] = _("ユニーク・モンスター口寄せ", "animate Unique Monsters");
+        lore_ptr->color[lore_ptr->vn++] = TERM_VIOLET;
+    }
 }
index 32d9277..97c1195 100644 (file)
@@ -10,6 +10,7 @@
 #include "market/arena-info-table.h"
 #include "market/building-actions-table.h"
 #include "market/building-util.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags-resistance.h"
@@ -202,7 +203,7 @@ void update_gambling_monsters(PlayerType *player_ptr)
             int j;
             while (true) {
                 get_mon_num_prep(player_ptr, monster_can_entry_arena, nullptr);
-                r_idx = get_mon_num(player_ptr, 0, mon_level, GMN_ARENA);
+                r_idx = get_mon_num(player_ptr, 0, mon_level, PM_ARENA);
                 if (!MonsterRace(r_idx).is_valid()) {
                     continue;
                 }
index 41c4cba..8de944f 100644 (file)
@@ -11,6 +11,7 @@
 #include "io/input-key-acceptor.h"
 #include "market/bounty-prize-table.h"
 #include "market/building-util.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -288,7 +289,7 @@ void determine_daily_bounty(PlayerType *player_ptr, bool conv_old)
     get_mon_num_prep_bounty(player_ptr);
 
     while (true) {
-        w_ptr->today_mon = get_mon_num(player_ptr, std::min(max_dl / 2, 40), max_dl, GMN_ARENA);
+        w_ptr->today_mon = get_mon_num(player_ptr, std::min(max_dl / 2, 40), max_dl, PM_ARENA);
         MonsterRaceInfo *r_ptr;
         r_ptr = &monraces_info[w_ptr->today_mon];
 
@@ -337,7 +338,7 @@ void determine_bounty_uniques(PlayerType *player_ptr)
     // 賞金首とするモンスターの種族IDのリストを生成
     std::vector<MonsterRaceId> bounty_r_idx_list;
     while (bounty_r_idx_list.size() < std::size(w_ptr->bounties)) {
-        auto r_idx = get_mon_num(player_ptr, 0, MAX_DEPTH - 1, GMN_ARENA);
+        auto r_idx = get_mon_num(player_ptr, 0, MAX_DEPTH - 1, PM_ARENA);
         if (!is_suitable_for_bounty(r_idx)) {
             continue;
         }
index 139aac2..fdf7b46 100644 (file)
@@ -271,7 +271,8 @@ static int decide_drop_numbers(PlayerType *player_ptr, monster_death_type *md_pt
         drop_numbers += damroll(4, 2);
     }
 
-    if (md_ptr->cloned && md_ptr->r_ptr->kind_flags.has_not(MonsterKindType::UNIQUE)) {
+    // クローンは、クローン地獄内のユニークモンスター以外はドロップしない
+    if (md_ptr->cloned && !(md_ptr->r_ptr->kind_flags.has(MonsterKindType::UNIQUE) && (player_ptr->current_floor_ptr->quest_number == QuestId::CLONE))) {
         drop_numbers = 0;
     }
 
index d6c0ab7..8819cd9 100644 (file)
@@ -375,7 +375,7 @@ bool place_random_monster(PlayerType *player_ptr, POSITION y, POSITION x, BIT_FL
     get_mon_num_prep(player_ptr, get_monster_hook(player_ptr), get_monster_hook2(player_ptr, y, x));
     MonsterRaceId r_idx;
     do {
-        r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->monster_level, 0);
+        r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->monster_level, PM_NONE);
     } while ((mode & PM_NO_QUEST) && (monraces_info[r_idx].flags8 & RF8_NO_QUEST));
 
     if (!MonsterRace(r_idx).is_valid()) {
@@ -394,7 +394,7 @@ static std::optional<MonsterRaceId> select_horde_leader_r_idx(PlayerType *player
     const auto *floor_ptr = player_ptr->current_floor_ptr;
 
     for (auto attempts = 1000; attempts > 0; --attempts) {
-        auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->monster_level, 0);
+        auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->monster_level, PM_NONE);
         if (!MonsterRace(r_idx).is_valid()) {
             return std::nullopt;
         }
index 0475b94..cbca566 100644 (file)
@@ -145,7 +145,7 @@ bool summon_specific(PlayerType *player_ptr, MONSTER_IDX who, POSITION y1, POSIT
     get_mon_num_prep(player_ptr, summon_specific_okay, get_monster_hook2(player_ptr, y, x));
 
     DEPTH dlev = get_dungeon_or_wilderness_level(player_ptr);
-    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, (dlev + lev) / 2 + 5, 0);
+    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, (dlev + lev) / 2 + 5, mode);
     if (!MonsterRace(r_idx).is_valid()) {
         summon_specific_type = SUMMON_NONE;
         return false;
index fd87a32..d27c931 100644 (file)
@@ -102,7 +102,7 @@ static MonsterRaceId initial_r_appearance(PlayerType *player_ptr, MonsterRaceId
     int attempts = 1000;
     DEPTH min = std::min(floor_ptr->base_level - 5, 50);
     while (--attempts) {
-        auto ap_r_idx = get_mon_num(player_ptr, 0, floor_ptr->base_level + 10, 0);
+        auto ap_r_idx = get_mon_num(player_ptr, 0, floor_ptr->base_level + 10, PM_NONE);
         if (monraces_info[ap_r_idx].level >= min) {
             return ap_r_idx;
         }
@@ -117,12 +117,16 @@ static MonsterRaceId initial_r_appearance(PlayerType *player_ptr, MonsterRaceId
  * @param r_idx 生成モンスター種族
  * @return ユニークの生成が不可能な条件ならFALSE、それ以外はTRUE
  */
-static bool check_unique_placeable(PlayerType *player_ptr, MonsterRaceId r_idx)
+static bool check_unique_placeable(PlayerType *player_ptr, MonsterRaceId r_idx, BIT_FLAGS mode)
 {
     if (player_ptr->phase_out) {
         return true;
     }
 
+    if (any_bits(mode, PM_CLONE)) {
+        return true;
+    }
+
     auto *r_ptr = &monraces_info[r_idx];
     if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num)) {
         return false;
@@ -277,7 +281,7 @@ bool place_monster_one(PlayerType *player_ptr, MONSTER_IDX who, POSITION y, POSI
         return false;
     }
 
-    if (!check_unique_placeable(player_ptr, r_idx) || !check_quest_placeable(floor, r_idx) || !check_procection_rune(player_ptr, r_idx, y, x)) {
+    if (!check_unique_placeable(player_ptr, r_idx, mode) || !check_quest_placeable(floor, r_idx) || !check_procection_rune(player_ptr, r_idx, y, x)) {
         return false;
     }
 
index 002b691..9ef9f00 100644 (file)
@@ -19,4 +19,6 @@ enum place_monster_type {
     PM_JURAL = 0x00000800, /*!< モンスター生成フラグ: ジュラル星人として誤認生成する */
     PM_NO_QUEST = 0x00001000, /*!< モンスター生成フラグ: クエスト除外モンスターを生成しない */
     PM_CLONE = 0x00002000, /*!< モンスター生成フラグ: クローンとして生成する */
+    PM_ARENA = 0x00004000, /*!< モンスター生成フラグ: アリーナ用の生成 */
+
 };
index 1d993ae..4d332ff 100644 (file)
@@ -1,6 +1,7 @@
 #include "monster-race/monster-race-hook.h"
 #include "monster-attack/monster-attack-effect.h"
 #include "monster-attack/monster-attack-table.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-ability-mask.h"
 #include "monster-race/race-flags-resistance.h"
@@ -37,7 +38,7 @@ EnumClassFlagGroup<MonsterAbilityType> vault_aux_dragon_mask4;
 void vault_prep_clone(PlayerType *player_ptr)
 {
     get_mon_num_prep(player_ptr, vault_aux_simple, nullptr);
-    vault_aux_race = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, 0);
+    vault_aux_race = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, PM_NONE);
     get_mon_num_prep(player_ptr, nullptr, nullptr);
 }
 
@@ -48,7 +49,7 @@ void vault_prep_clone(PlayerType *player_ptr)
 void vault_prep_symbol(PlayerType *player_ptr)
 {
     get_mon_num_prep(player_ptr, vault_aux_simple, nullptr);
-    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, 0);
+    MonsterRaceId r_idx = get_mon_num(player_ptr, 0, player_ptr->current_floor_ptr->dun_level + 10, PM_NONE);
     get_mon_num_prep(player_ptr, nullptr, nullptr);
     vault_aux_char = monraces_info[r_idx].d_char;
 }
index 9f0028b..0853a55 100644 (file)
@@ -99,6 +99,7 @@ enum class MonsterAbilityType {
     S_HI_DRAGON = 93, /* Summon Ancient Dragon */
     S_AMBERITES = 94, /* Summon Amberites */
     S_UNIQUE = 95, /* Summon Unique Monster */
+    S_DEAD_UNIQUE = 96, /* Summon Dead Unique Monster */
     BO_VOID = 97, /*!< モンスター能力: ヴォイド・ボルト / Void Bolt */
     BO_ABYSS = 98, /*!< モンスター能力: アビス・ボルト / Abyss Bolt */
     BR_VOID = 99, /*!< モンスター能力: 虚無のブレス / Breathe Void */
index 9e5df37..89be835 100644 (file)
@@ -7,6 +7,7 @@ const EnumClassFlagGroup<MonsterAbilityType> RF_ABILITY_SUMMON_MASK = {
     MonsterAbilityType::S_ANT, MonsterAbilityType::S_SPIDER, MonsterAbilityType::S_HOUND, MonsterAbilityType::S_HYDRA,
     MonsterAbilityType::S_ANGEL, MonsterAbilityType::S_DEMON, MonsterAbilityType::S_UNDEAD, MonsterAbilityType::S_DRAGON,
     MonsterAbilityType::S_HI_UNDEAD, MonsterAbilityType::S_HI_DRAGON, MonsterAbilityType::S_AMBERITES, MonsterAbilityType::S_UNIQUE,
+    MonsterAbilityType::S_DEAD_UNIQUE,
 };
 
 /* Choose "intelligent" spells when desperate Including "summon" spells */
index 611c385..b2c0f9d 100644 (file)
@@ -20,6 +20,7 @@
 #include "game-option/cheat-options.h"
 #include "grid/grid.h"
 #include "monster-floor/monster-summon.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-kind-mask.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-brightness-mask.h"
@@ -42,6 +43,7 @@
 #include "system/monster-race-info.h"
 #include "system/player-type-definition.h"
 #include "system/redrawing-flags-updater.h"
+#include "util/bit-flags-calculator.h"
 #include "util/probability-table.h"
 #include "view/display-messages.h"
 #include "world/world.h"
@@ -92,7 +94,7 @@ MONSTER_IDX m_pop(FloorType *floor_ptr)
  * @return 選択されたモンスター生成種族
  * @details nasty生成 (ゲーム内経過日数に応じて、現在フロアより深いフロアのモンスターを出現させる仕様)は
  */
-MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option)
+MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode)
 {
     /* town max_level : same delay as 10F, no nasty mons till day18 */
     auto delay = static_cast<int>(std::sqrt(max_level * 10000)) + (max_level * 5);
@@ -128,7 +130,7 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
     }
 
     /* Boost the max_level */
-    if ((option & GMN_ARENA) || dungeon.flags.has_not(DungeonFeatureType::BEGINNER)) {
+    if (any_bits(mode, PM_ARENA) || dungeon.flags.has_not(DungeonFeatureType::BEGINNER)) {
         /* Nightmare mode allows more out-of depth monsters */
         if (ironman_nightmare && !randint0(chance_nasty)) {
             /* What a bizarre calculation */
@@ -155,8 +157,8 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev
         } // sorted by depth array,
         auto r_idx = i2enum<MonsterRaceId>(entry.index);
         auto r_ptr = &monraces_info[r_idx];
-        if (!(option & GMN_ARENA) && !chameleon_change_m_idx) {
-            if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num)) {
+        if (none_bits(mode, PM_ARENA) && !chameleon_change_m_idx) {
+            if ((r_ptr->kind_flags.has(MonsterKindType::UNIQUE) || r_ptr->population_flags.has(MonsterPopulationType::NAZGUL)) && (r_ptr->cur_num >= r_ptr->max_num) && none_bits(mode, PM_CLONE)) {
                 continue;
             }
 
index 6293e34..32729a5 100644 (file)
@@ -2,15 +2,13 @@
 
 #include "system/angband.h"
 
-#define GMN_ARENA 0x00000001 //!< 賭け闘技場向け生成
-
 enum class MonsterRaceId : int16_t;
 class FloorType;
 class MonsterRaceInfo;
 class PlayerType;
 MONSTER_IDX m_pop(FloorType *floor_ptr);
 
-MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS option);
+MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode);
 void choose_new_monster(PlayerType *player_ptr, MONSTER_IDX m_idx, bool born, MonsterRaceId r_idx);
 byte get_mspeed(FloorType *player_ptr, MonsterRaceInfo *r_ptr);
 int get_monster_crowd_number(FloorType *floor_ptr, MONSTER_IDX m_idx);
index 61a83da..2215e50 100644 (file)
@@ -147,6 +147,7 @@ static MonsterSpellResult monspell_to_player_impl(PlayerType *player_ptr, Monste
     case MonsterAbilityType::S_HI_DRAGON: return spell_RF6_S_HI_DRAGON(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_HI_DRAGON */
     case MonsterAbilityType::S_AMBERITES: return spell_RF6_S_AMBERITES(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_AMBERITES */
     case MonsterAbilityType::S_UNIQUE: return spell_RF6_S_UNIQUE(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_UNIQUE */
+    case MonsterAbilityType::S_DEAD_UNIQUE: return spell_RF6_S_DEAD_UNIQUE(player_ptr, y, x, m_idx, 0, MONSTER_TO_PLAYER); /* RF6_S_DEAD_UNIQUE */
     default: break;
     }
     // clang-format on
@@ -278,6 +279,7 @@ static MonsterSpellResult monspell_to_monster_impl(
     case MonsterAbilityType::S_HI_DRAGON: return spell_RF6_S_HI_DRAGON(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_HI_DRAGON */
     case MonsterAbilityType::S_AMBERITES: return spell_RF6_S_AMBERITES(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_AMBERITES */
     case MonsterAbilityType::S_UNIQUE: return spell_RF6_S_UNIQUE(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_UNIQUE */
+    case MonsterAbilityType::S_DEAD_UNIQUE: return spell_RF6_S_DEAD_UNIQUE(player_ptr, y, x, m_idx, t_idx, MONSTER_TO_MONSTER); /* RF6_S_DEAD_UNIQUE */
     default: break;
     }
     // clang-format on
index 588b020..5e9768c 100644 (file)
@@ -112,6 +112,7 @@ const std::map<MonsterAbilityType, const monster_power> monster_powers = {
     { MonsterAbilityType::S_HI_DRAGON, { 46, 90, 85, 0, 45, A_INT, _("古代ドラゴンの召喚", "summon Ancient Dragon") } },
     { MonsterAbilityType::S_AMBERITES, { 48, 120, 90, 0, 50, A_INT, _("アンバーの王族の召喚", "summon Lords of Amber") } },
     { MonsterAbilityType::S_UNIQUE, { 50, 150, 95, 0, 50, A_INT, _("ユニークモンスターの召喚", "summon Unique Monsters") } },
+    { MonsterAbilityType::S_DEAD_UNIQUE, { 50, 150, 95, 0, 50, A_INT, _("ユニークモンスターの口寄せ", "summon Dead Unique Monsters") } },
 };
 
 /*!
@@ -222,4 +223,5 @@ const std::map<MonsterAbilityType, concptr> monster_powers_short = {
     { MonsterAbilityType::S_HI_DRAGON, _("古代ドラゴン", "Ancient Dragon") },
     { MonsterAbilityType::S_AMBERITES, _("アンバーの王族", "Lords of Amber") },
     { MonsterAbilityType::S_UNIQUE, _("ユニーク", "Unique monsters") },
+    { MonsterAbilityType::S_DEAD_UNIQUE, _("黄泉のユニーク", "Dead unique monsters") },
 };
index 3c08c91..be39d60 100644 (file)
@@ -428,6 +428,8 @@ static int monspell_damage_base(
         return -1;
     case MonsterAbilityType::S_UNIQUE:
         return -1;
+    case MonsterAbilityType::S_DEAD_UNIQUE:
+        return -1;
     case MonsterAbilityType::MAX:
         return -1;
     }
index b067567..f8292b3 100644 (file)
@@ -155,7 +155,7 @@ static bool spell_annoy(MonsterAbilityType spell)
  */
 static bool spell_summon(MonsterAbilityType spell)
 {
-    return spell_in_between(spell, MonsterAbilityType::S_KIN, MonsterAbilityType::S_UNIQUE);
+    return spell_in_between(spell, MonsterAbilityType::S_KIN, MonsterAbilityType::S_DEAD_UNIQUE);
 }
 
 /*!
index 4d50372..9108b03 100644 (file)
@@ -969,3 +969,49 @@ MonsterSpellResult spell_RF6_S_UNIQUE(PlayerType *player_ptr, POSITION y, POSITI
 
     return res;
 }
+
+/*!
+ * @brief RF6_S_DEAD_UNIQUEの処理。撃破済みユニーク・モンスターをクローンとして召喚。 /
+ * @param player_ptr プレイヤーへの参照ポインタ
+ * @param y 対象の地点のy座標
+ * @param x 対象の地点のx座標
+ * @param m_idx 呪文を唱えるモンスターID
+ * @param t_idx 呪文を受けるモンスターID。プレイヤーの場合はdummyで0とする。
+ * @param target_type プレイヤーを対象とする場合MONSTER_TO_PLAYER、モンスターを対象とする場合MONSTER_TO_MONSTER
+ *
+ * プレイヤーが対象ならラーニング可。
+ */
+MonsterSpellResult spell_RF6_S_DEAD_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type)
+{
+    auto *floor_ptr = player_ptr->current_floor_ptr;
+    auto rlev = monster_level_idx(floor_ptr, m_idx);
+    auto mon_to_mon = (target_type == MONSTER_TO_MONSTER);
+    auto mon_to_player = (target_type == MONSTER_TO_PLAYER);
+    auto see_either = see_monster(player_ptr, m_idx) || see_monster(player_ptr, t_idx);
+    auto known = monster_near_player(floor_ptr, m_idx, t_idx);
+
+    mspell_cast_msg_blind msg(_("%^sが何かをつぶやいた。", "%^s mumbles."),
+        _("%s^が魔法で特別な強敵を蘇らせた!", "%^s magically animates special opponents!"),
+        _("%s^が魔法で特別な強敵を蘇らせた!", "%^s magically animates special opponents!"));
+
+    monspell_message(player_ptr, m_idx, t_idx, msg, target_type);
+    summon_disturb(player_ptr, target_type, known, see_either);
+
+    auto count = 0;
+    for (auto k = 0; k < S_NUM_4; k++) {
+        count += summon_specific(player_ptr, m_idx, y, x, rlev, SUMMON_DEAD_UNIQUE, (PM_ALLOW_GROUP | PM_ALLOW_UNIQUE | PM_CLONE));
+    }
+
+    if (player_ptr->effects()->blindness()->is_blind() && count && mon_to_player) {
+        msg_format(_("多くの力強いものが間近に蘇った音が聞こえる。", "You hear many powerful things animate nearby."));
+    }
+
+    if (monster_near_player(floor_ptr, m_idx, t_idx) && !see_monster(player_ptr, t_idx) && count && mon_to_mon) {
+        floor_ptr->monster_noise = true;
+    }
+
+    auto res = MonsterSpellResult::make_valid();
+    res.learnable = target_type == MONSTER_TO_PLAYER;
+
+    return res;
+}
index 0974683..0aaf16a 100644 (file)
@@ -21,3 +21,4 @@ MonsterSpellResult spell_RF6_S_HI_UNDEAD(PlayerType *player_ptr, POSITION y, POS
 MonsterSpellResult spell_RF6_S_HI_DRAGON(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
 MonsterSpellResult spell_RF6_S_AMBERITES(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
 MonsterSpellResult spell_RF6_S_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
+MonsterSpellResult spell_RF6_S_DEAD_UNIQUE(PlayerType *player_ptr, POSITION y, POSITION x, MONSTER_IDX m_idx, MONSTER_IDX t_idx, int target_type);
index b690b03..b601c97 100644 (file)
@@ -153,6 +153,9 @@ bool check_summon_specific(PlayerType *player_ptr, MonsterRaceId summoner_idx, M
         is_match |= (r_idx == MonsterRaceId::SHALLOW_PUDDLE) || (r_idx == MonsterRaceId::DEEP_PUDDLE) || (r_idx == MonsterRaceId::SKY_WHALE);
         return is_match;
     }
+    case SUMMON_DEAD_UNIQUE: {
+        return monrace.kind_flags.has(MonsterKindType::UNIQUE) && monrace.max_num == 0;
+    }
     default:
         return false;
     }
index bcd3e52..12be934 100644 (file)
@@ -9,6 +9,7 @@
 #include "artifact/random-art-generator.h"
 #include "game-option/cheat-options.h"
 #include "inventory/inventory-slot-types.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-indice-types.h"
@@ -147,7 +148,7 @@ void OtherItemsEnchanter::generate_corpse()
     auto *floor_ptr = this->player_ptr->current_floor_ptr;
     MonsterRaceId r_idx;
     while (true) {
-        r_idx = get_mon_num(this->player_ptr, 0, floor_ptr->dun_level, 0);
+        r_idx = get_mon_num(this->player_ptr, 0, floor_ptr->dun_level, PM_NONE);
         auto &r_ref = monraces_info[r_idx];
         auto check = (floor_ptr->dun_level < r_ref.level) ? (r_ref.level - floor_ptr->dun_level) : 0;
         const auto sval = this->o_ptr->bi_key.sval();
index 05693ac..98031f6 100644 (file)
@@ -7,6 +7,7 @@
 #include "player/eldritch-horror.h"
 #include "core/stuff-handler.h"
 #include "locale/english.h"
+#include "monster-floor/place-monster-types.h"
 #include "monster-race/monster-race-hook.h"
 #include "monster-race/monster-race.h"
 #include "monster-race/race-flags1.h"
@@ -143,7 +144,7 @@ void sanity_blast(PlayerType *player_ptr, MonsterEntity *m_ptr, bool necro)
         }
     } else if (!necro) {
         get_mon_num_prep(player_ptr, get_nightmare, nullptr);
-        auto *r_ptr = &monraces_info[get_mon_num(player_ptr, 0, MAX_DEPTH, 0)];
+        auto *r_ptr = &monraces_info[get_mon_num(player_ptr, 0, MAX_DEPTH, PM_NONE)];
         power = r_ptr->level + 10;
         const auto &desc = r_ptr->name;
         get_mon_num_prep(player_ptr, nullptr, nullptr);
index 050bafa..9bea43f 100644 (file)
@@ -255,7 +255,7 @@ bool build_type5(PlayerType *player_ptr, dun_data_type *dd_ptr)
         auto select_r_idx = [player_ptr, floor_ptr, &align]() -> std::optional<MonsterRaceId> {
             for (auto attempts = 100; attempts > 0; attempts--) {
                 /* Get a (hard) monster type */
-                auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
+                auto r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, PM_NONE);
                 auto *r_ptr = &monraces_info[r_idx];
 
                 /* Decline incorrect alignment */
@@ -502,7 +502,7 @@ bool build_type6(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         while (attempts--) {
             /* Get a (hard) monster type */
-            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, 0);
+            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 11, PM_NONE);
             r_ptr = &monraces_info[r_idx];
 
             /* Decline incorrect alignment */
@@ -817,7 +817,7 @@ bool build_type13(PlayerType *player_ptr, dun_data_type *dd_ptr)
 
         while (attempts--) {
             /* Get a (hard) monster type */
-            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 0, 0);
+            r_idx = get_mon_num(player_ptr, 0, floor_ptr->dun_level + 0, PM_NONE);
             r_ptr = &monraces_info[r_idx];
 
             /* Decline incorrect alignment */
index 541e2e1..c8420c3 100644 (file)
@@ -40,7 +40,7 @@ static MonsterRaceId poly_r_idx(PlayerType *player_ptr, MonsterRaceId r_idx)
     DEPTH lev2 = r_ptr->level + ((randint1(20) / randint1(9)) + 1);
     MonsterRaceId r;
     for (int i = 0; i < 1000; i++) {
-        r = get_mon_num(player_ptr, 0, (player_ptr->current_floor_ptr->dun_level + r_ptr->level) / 2 + 5, 0);
+        r = get_mon_num(player_ptr, 0, (player_ptr->current_floor_ptr->dun_level + r_ptr->level) / 2 + 5, PM_NONE);
         if (!MonsterRace(r).is_valid()) {
             break;
         }
index 5a6f4ee..72dd80d 100644 (file)
@@ -53,4 +53,5 @@ enum summon_type : int {
     SUMMON_APOCRYPHA_DRAGONS = 69, /*!< 召喚タイプ: 強力な古代ドラゴン */
     SUMMON_VESPOID = 70, /*!< 召喚タイプ: ランゴスタ */
     SUMMON_ANTI_TIGERS = 71, /*!< 召喚タイプ: トラ以外 */
+    SUMMON_DEAD_UNIQUE = 72, /*!< 召喚タイプ: 撃破済みユニーク */
 };