diff --git a/configure.ac b/configure.ac index 346cca6654..23e67b2531 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ dnl Process this file with autoconf to produce a configure script. -AC_INIT(hengband, 3.0.1.16-Beta) +AC_INIT(hengband, 3.0.1.17-Beta) AC_CONFIG_MACRO_DIRS([m4]) AC_CONFIG_HEADERS(src/autoconf.h) diff --git a/doxygen/Hengband.doxyfile b/doxygen/Hengband.doxyfile index 7ab6bca5f4..0f958e255c 100644 --- a/doxygen/Hengband.doxyfile +++ b/doxygen/Hengband.doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Hengband # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = 3.0.1.16-Beta +PROJECT_NUMBER = 3.0.1.17-Beta # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/hengband.spec b/hengband.spec index 7b46279157..46c0a77b15 100644 --- a/hengband.spec +++ b/hengband.spec @@ -1,4 +1,4 @@ -%define version 3.0.1.15 +%define version 3.0.1.16 %define release 1 Summary: hengband %{version} @@ -151,6 +151,9 @@ exit 0 %license lib/help/jlicense.txt %changelog +* Tue Jul 02 2024 whitehara +- hengband RPM 3.0.1.16(Beta) + * Fri Jun 21 2024 whitehara - hengband RPM 3.0.1.15(Beta) diff --git a/lib/edit/MonraceDefinitions.jsonc b/lib/edit/MonraceDefinitions.jsonc index 9d5891b81c..36180c73b2 100644 --- a/lib/edit/MonraceDefinitions.jsonc +++ b/lib/edit/MonraceDefinitions.jsonc @@ -87348,6 +87348,71 @@ "ja": "彼女は元々優しい心の持ち主だったが、とある学園の者に利用され、大罪を犯し大事なものを根こそぎ奪われた。哀れで救いたくなるような者であると同時に軽蔑・嫌悪に値する者でもある。その目は復讐の炎に燃えており、復讐の妨げとなるあなたはどうしようもないゴミとみなされている。", "en": "She had a kind heart, but was taken advantage of by someone at a certain school, committed a serious crime, then all of her precious things were burned. She is deserving of contempt and, in her misery, compassion. Her eyes burn with revenge. She counts you, obstructing her revenge, as one of the hopeless scum." } + }, + { + "id": 1363, + "name": { + "ja": "地獄の出店", + "en": "Hell's market stall" + }, + "symbol": { + "character": "7", + "color": "Dark Gray" + }, + "level": 30, + "hit_point": "30d20", + "speed": 10, + "rarity": 4, + "exp": 300, + "alertness": 0, + "armor_class": 80, + "vision": 10, + "blows": [ + { + "method": "BEG", + "effect": "EAT_FOOD", + "damage_dice": "12d6" + }, + { + "method": "BEG", + "effect": "EAT_GOLD", + "damage_dice": "12d6" + }, + { + "method": "BEG", + "effect": "EAT_ITEM", + "damage_dice": "12d6" + }, + { + "method": "BEG", + "effect": "EAT_ITEM", + "damage_dice": "12d6" + } + ], + "flags": [ + "EVIL", + "UNDEAD", + "COLD_BLOOD", + "NONLIVING", + "NEVER_MOVE", + "EMPTY_MIND", + "RES_NETH", + "NO_CONF", + "NO_SLEEP", + "NO_FEAR", + "DROP_3D2", + "DROP_4D2" + ], + "skill": { + "probability": "1_IN_10", + "list": [ + "SHRIEK" + ] + }, + "flavor": { + "ja": "それは冒険者の来店を待っている。持ち物を狙って…", + "en": "It waits for your coming. Aims at your things..." + } } ] } diff --git a/src/monster-floor/one-monster-placer.cpp b/src/monster-floor/one-monster-placer.cpp index 7342a02b18..17adb233d0 100644 --- a/src/monster-floor/one-monster-placer.cpp +++ b/src/monster-floor/one-monster-placer.cpp @@ -334,7 +334,7 @@ std::optional place_monster_one(PlayerType *player_ptr, MONSTER_IDX } if (r_ptr->misc_flags.has(MonsterMiscType::CHAMELEON)) { - choose_chameleon_polymorph(player_ptr, g_ptr->m_idx, summoner_m_idx); + choose_chameleon_polymorph(player_ptr, g_ptr->m_idx, *g_ptr, summoner_m_idx); r_ptr = &m_ptr->get_monrace(); diff --git a/src/monster/monster-list.cpp b/src/monster/monster-list.cpp index e3c649074b..3b4f0cdac3 100644 --- a/src/monster/monster-list.cpp +++ b/src/monster/monster-list.cpp @@ -204,10 +204,11 @@ MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_lev * @brief カメレオンの王の変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster * @param r_idx モンスター種族ID * @param m_idx 変身するモンスターのモンスターID + * @param grid カメレオンの足元の地形 * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID * @return 対象にできるならtrueを返す */ -static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_idx, MONSTER_IDX m_idx, std::optional summoner_m_idx) +static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_idx, MONSTER_IDX m_idx, const Grid &grid, std::optional summoner_m_idx) { auto *floor_ptr = player_ptr->current_floor_ptr; auto *r_ptr = &monraces_info[r_idx]; @@ -225,11 +226,11 @@ static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_ return false; } - if (m_ptr->is_explodable()) { + if (r_ptr->is_explodable()) { return false; } - if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0)) { + if (!monster_can_cross_terrain(player_ptr, grid.feat, r_ptr, 0)) { return false; } @@ -248,11 +249,12 @@ static bool monster_hook_chameleon_lord(PlayerType *player_ptr, MonsterRaceId r_ * @brief カメレオンの変身対象となるモンスターかどうか判定する / Hack -- the index of the summoning monster * @param r_idx モンスター種族ID * @param m_idx 変身するモンスターのモンスターID + * @param grid カメレオンの足元の地形 * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID * @return 対象にできるならtrueを返す * @todo グローバル変数対策の上 monster_hook.cへ移す。 */ -static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx, MONSTER_IDX m_idx, std::optional summoner_m_idx) +static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx, MONSTER_IDX m_idx, const Grid &grid, std::optional summoner_m_idx) { auto *floor_ptr = player_ptr->current_floor_ptr; auto *r_ptr = &monraces_info[r_idx]; @@ -269,11 +271,11 @@ static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx, return false; } - if (m_ptr->is_explodable()) { + if (r_ptr->is_explodable()) { return false; } - if (!monster_can_cross_terrain(player_ptr, floor_ptr->grid_array[m_ptr->fy][m_ptr->fx].feat, r_ptr, 0)) { + if (!monster_can_cross_terrain(player_ptr, grid.feat, r_ptr, 0)) { return false; } @@ -295,7 +297,7 @@ static bool monster_hook_chameleon(PlayerType *player_ptr, MonsterRaceId r_idx, return hook_pf(player_ptr, r_idx); } -static std::optional polymorph_of_chameleon(PlayerType *player_ptr, MONSTER_IDX m_idx, const std::optional summoner_m_idx) +static std::optional polymorph_of_chameleon(PlayerType *player_ptr, MONSTER_IDX m_idx, const Grid &grid, const std::optional summoner_m_idx) { auto *floor_ptr = player_ptr->current_floor_ptr; auto *m_ptr = &floor_ptr->m_list[m_idx]; @@ -306,8 +308,8 @@ static std::optional polymorph_of_chameleon(PlayerType *player_pt } auto hook_fp = old_unique ? monster_hook_chameleon_lord : monster_hook_chameleon; - auto hook = [m_idx, summoner_m_idx, hook_fp](PlayerType *player_ptr, MonsterRaceId r_idx) { - return hook_fp(player_ptr, r_idx, m_idx, summoner_m_idx); + auto hook = [m_idx, grid, summoner_m_idx, hook_fp](PlayerType *player_ptr, MonsterRaceId r_idx) { + return hook_fp(player_ptr, r_idx, m_idx, grid, summoner_m_idx); }; get_mon_num_prep_chameleon(player_ptr, std::move(hook)); @@ -338,14 +340,15 @@ static std::optional polymorph_of_chameleon(PlayerType *player_pt * @brief カメレオンの変身処理 * @param player_ptr プレイヤーへの参照ポインタ * @param m_idx 変身処理を受けるモンスター情報のID + * @param grid カメレオンの足元の地形 * @param summoner_m_idx モンスターの召喚による場合、召喚者のモンスターID */ -void choose_chameleon_polymorph(PlayerType *player_ptr, MONSTER_IDX m_idx, std::optional summoner_m_idx) +void choose_chameleon_polymorph(PlayerType *player_ptr, MONSTER_IDX m_idx, const Grid &grid, std::optional summoner_m_idx) { auto &floor = *player_ptr->current_floor_ptr; auto &monster = floor.m_list[m_idx]; - auto new_monrace_id = polymorph_of_chameleon(player_ptr, m_idx, summoner_m_idx); + auto new_monrace_id = polymorph_of_chameleon(player_ptr, m_idx, grid, summoner_m_idx); if (!new_monrace_id) { return; } diff --git a/src/monster/monster-list.h b/src/monster/monster-list.h index 67283e3dcb..677d6d2062 100644 --- a/src/monster/monster-list.h +++ b/src/monster/monster-list.h @@ -7,8 +7,9 @@ enum class MonsterRaceId : int16_t; class FloorType; class MonsterRaceInfo; class PlayerType; +class Grid; MONSTER_IDX m_pop(FloorType *floor_ptr); MonsterRaceId get_mon_num(PlayerType *player_ptr, DEPTH min_level, DEPTH max_level, BIT_FLAGS mode); -void choose_chameleon_polymorph(PlayerType *player_ptr, MONSTER_IDX m_idx, std::optional summoner_m_idx = std::nullopt); +void choose_chameleon_polymorph(PlayerType *player_ptr, MONSTER_IDX m_idx, const Grid &grid, std::optional summoner_m_idx = std::nullopt); int get_monster_crowd_number(FloorType *floor_ptr, MONSTER_IDX m_idx); diff --git a/src/monster/monster-processor.cpp b/src/monster/monster-processor.cpp index 020c9cf4a6..4873b41fa9 100644 --- a/src/monster/monster-processor.cpp +++ b/src/monster/monster-processor.cpp @@ -121,12 +121,14 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx) decide_drop_from_monster(player_ptr, m_idx, turn_flags_ptr->is_riding_mon); if (m_ptr->mflag2.has(MonsterConstantFlagType::CHAMELEON) && one_in_(13) && !m_ptr->is_asleep()) { - choose_chameleon_polymorph(player_ptr, m_idx); - - const auto &new_monrace = m_ptr->get_monrace(); + const auto &floor = *player_ptr->current_floor_ptr; const auto old_m_name = monster_desc(player_ptr, m_ptr, 0); + choose_chameleon_polymorph(player_ptr, m_idx, floor.get_grid(Pos2D(m_ptr->fy, m_ptr->fx))); + + const auto &new_monrace = m_ptr->get_monrace(); + if (m_idx == player_ptr->riding) { msg_format(_("突然%sが変身した。", "Suddenly, %s transforms!"), old_m_name.data()); if (new_monrace.misc_flags.has_not(MonsterMiscType::RIDING)) { @@ -137,7 +139,7 @@ void process_monster(PlayerType *player_ptr, MONSTER_IDX m_idx) } } - m_ptr->set_individual_speed(player_ptr->current_floor_ptr->inside_arena); + m_ptr->set_individual_speed(floor.inside_arena); const auto old_maxhp = m_ptr->max_maxhp; if (new_monrace.misc_flags.has(MonsterMiscType::FORCE_MAXHP)) { diff --git a/src/monster/monster-status.cpp b/src/monster/monster-status.cpp index b28856143a..ec230a7356 100644 --- a/src/monster/monster-status.cpp +++ b/src/monster/monster-status.cpp @@ -20,6 +20,7 @@ #include "system/player-type-definition.h" #include "system/redrawing-flags-updater.h" #include "timed-effect/timed-effects.h" +#include "tracking/health-bar-tracker.h" #include "util/bit-flags-calculator.h" #include "view/display-messages.h" #if JP @@ -354,7 +355,9 @@ void process_monsters_mtimed(PlayerType *player_ptr, int mtimed_idx) /* Process the monsters (backwards) */ for (auto i = floor_ptr->mproc_max[mtimed_idx] - 1; i >= 0; i--) { - process_monsters_mtimed_aux(player_ptr, cur_mproc_list[i], mtimed_idx); + const auto m_idx = cur_mproc_list[i]; + process_monsters_mtimed_aux(player_ptr, m_idx, mtimed_idx); + HealthBarTracker::get_instance().set_flag_if_tracking(m_idx); } } diff --git a/src/spell-realm/spells-crusade.cpp b/src/spell-realm/spells-crusade.cpp index 9ac9f117b9..3a99e2cdf3 100644 --- a/src/spell-realm/spells-crusade.cpp +++ b/src/spell-realm/spells-crusade.cpp @@ -90,8 +90,7 @@ bool cast_wrath_of_the_god(PlayerType *player_ptr, int dam, POSITION rad) continue; } - auto should_cast = in_bounds(&floor, pos_explode.y, pos_explode.x); - should_cast &= !cave_stop_disintegration(&floor, pos_explode.y, pos_explode.x); + auto should_cast = in_bounds(&floor, pos_explode.y, pos_explode.x) && !cave_stop_disintegration(&floor, pos_explode.y, pos_explode.x); should_cast &= in_disintegration_range(&floor, pos_target.y, pos_target.x, pos_explode.y, pos_explode.x); if (!should_cast) { continue; diff --git a/src/system/angband-version.h b/src/system/angband-version.h index 212633b65c..86875cd800 100644 --- a/src/system/angband-version.h +++ b/src/system/angband-version.h @@ -24,7 +24,7 @@ constexpr std::string_view ROOT_VARIANT_NAME("Hengband"); #define H_VER_MAJOR 3 //!< ゲームのバージョン定義(メジャー番号) #define H_VER_MINOR 0 //!< ゲームのバージョン定義(マイナー番号) #define H_VER_PATCH 1 //!< ゲームのバージョン定義(パッチ番号) -#define H_VER_EXTRA 16 //!< ゲームのバージョン定義(エクストラ番号) +#define H_VER_EXTRA 17 //!< ゲームのバージョン定義(エクストラ番号) /*! * @brief セーブファイルのバージョン(3.0.0から導入) diff --git a/src/wizard/wizard-special-process.cpp b/src/wizard/wizard-special-process.cpp index 2bbf71bae2..02d70d05db 100644 --- a/src/wizard/wizard-special-process.cpp +++ b/src/wizard/wizard-special-process.cpp @@ -94,6 +94,7 @@ #include "util/bit-flags-calculator.h" #include "util/candidate-selector.h" #include "util/enum-converter.h" +#include "util/enum-range.h" #include "util/finalizer.h" #include "util/int-char-converter.h" #include "view/display-messages.h" @@ -595,17 +596,60 @@ static void change_birth_flags() rfu.set_flags(flags_mwrf); } +static std::optional wiz_select_realm(const RealmChoices &choices, const std::string &msg) +{ + if (choices.count() <= 1) { + return choices.first().value_or(RealmType::NONE); + } + + std::vector candidates; + RealmChoices::get_flags(choices, std::back_inserter(candidates)); + auto describe_realm = [](auto realm) { return PlayerRealm::get_name(realm).string(); }; + + CandidateSelector cs(msg, 15); + const auto choice = cs.select(candidates, describe_realm); + return (choice != candidates.end()) ? std::make_optional(*choice) : std::nullopt; +} + +static std::optional> wiz_select_realms(PlayerClassType pclass) +{ + const auto realm1 = wiz_select_realm(PlayerRealm::get_realm1_choices(pclass), "1st realm: "); + if (!realm1) { + return std::nullopt; + } + + auto realm2_choices = PlayerRealm::get_realm2_choices(pclass).reset(*realm1); + if (pclass == PlayerClassType::PRIEST) { + if (PlayerRealm::Realm(*realm1).is_good_attribute()) { + realm2_choices.reset({ RealmType::DEATH, RealmType::DAEMON }); + } else { + realm2_choices.reset({ RealmType::LIFE, RealmType::CRUSADE }); + } + } + + const auto realm2 = wiz_select_realm(realm2_choices, "2nd realm: "); + if (!realm2) { + return std::nullopt; + } + + return std::make_pair(*realm1, *realm2); +} + /*! * @brief プレイヤーの種族を変更する */ void wiz_reset_race(PlayerType *player_ptr) { - const auto new_race = input_numerics("RaceID", 0, MAX_RACES - 1, player_ptr->prace); - if (!new_race) { + CandidateSelector cs("Which race: ", 15); + constexpr EnumRange races(PlayerRaceType::HUMAN, PlayerRaceType::MAX); + auto describe_race = [](auto player_race) { return race_info[enum2i(player_race)].title.string(); }; + + const auto chosen_race = cs.select(races, describe_race); + if (chosen_race == races.end()) { return; } - player_ptr->prace = *new_race; + player_ptr->prace = *chosen_race; rp_ptr = &race_info[enum2i(player_ptr->prace)]; change_birth_flags(); handle_stuff(player_ptr); @@ -617,17 +661,29 @@ void wiz_reset_race(PlayerType *player_ptr) */ void wiz_reset_class(PlayerType *player_ptr) { - const auto new_class_opt = input_numerics("ClassID", 0, PLAYER_CLASS_TYPE_MAX - 1, player_ptr->pclass); - if (!new_class_opt) { + CandidateSelector cs("Which class: ", 15); + constexpr EnumRange classes(PlayerClassType::WARRIOR, PlayerClassType::MAX); + auto describe_class = [](auto player_class) { return class_info.at(player_class).title.string(); }; + + const auto chosen_class = cs.select(classes, describe_class); + if (chosen_class == classes.end()) { return; } - const auto new_class_enum = *new_class_opt; - const auto new_class = enum2i(new_class_enum); - player_ptr->pclass = new_class_enum; + const auto chosen_realms = wiz_select_realms(*chosen_class); + if (!chosen_realms) { + return; + } + + player_ptr->pclass = *chosen_class; cp_ptr = &class_info.at(player_ptr->pclass); - mp_ptr = &class_magics_info[new_class]; + mp_ptr = &class_magics_info[enum2i(player_ptr->pclass)]; PlayerClass(player_ptr).init_specific_data(); + PlayerRealm pr(player_ptr); + pr.reset(); + if (chosen_realms->first != RealmType::NONE) { + pr.set(chosen_realms->first, chosen_realms->second); + } change_birth_flags(); handle_stuff(player_ptr); } @@ -638,18 +694,16 @@ void wiz_reset_class(PlayerType *player_ptr) */ void wiz_reset_realms(PlayerType *player_ptr) { - PlayerRealm pr(player_ptr); - const auto new_realm1 = input_numerics("1st Realm (None=0)", 0, enum2i(RealmType::MAX) - 1, pr.realm1().to_enum()); - if (!new_realm1) { + const auto chosen_realms = wiz_select_realms(player_ptr->pclass); + if (!chosen_realms) { return; } - const auto new_realm2 = input_numerics("2nd Realm (None=0)", 0, enum2i(RealmType::MAX) - 1, pr.realm2().to_enum()); - if (!new_realm2) { - return; + PlayerRealm pr(player_ptr); + pr.reset(); + if (chosen_realms->first != RealmType::NONE) { + pr.set(chosen_realms->first, chosen_realms->second); } - - pr.set(*new_realm1, *new_realm2); change_birth_flags(); handle_stuff(player_ptr); }