#include "core/asking-player.h"
#include "core/player-redraw-types.h"
#include "core/stuff-handler.h"
-#include "dungeon/dungeon.h"
#include "flavor/flavor-describer.h"
#include "game-option/cheat-options.h"
#include "inventory/inventory-object.h"
#include "monster-race/race-flags1.h"
#include "monster-race/race-flags2.h"
#include "monster-race/race-flags7.h"
-#include "monster-race/race-flags9.h"
#include "monster-race/race-indice-types.h"
#include "monster/monster-list.h"
#include "monster/monster-util.h"
-#include "object-enchant/apply-magic.h"
#include "object-enchant/item-apply-magic.h"
+#include "object-enchant/item-magic-applier.h"
#include "object/object-info.h"
#include "object/object-kind-hook.h"
#include "perception/object-perception.h"
#include "sv-definition/sv-other-types.h"
+#include "system/baseitem-info.h"
+#include "system/dungeon-info.h"
#include "system/floor-type-definition.h"
-#include "system/monster-race-definition.h"
-#include "system/object-type-definition.h"
+#include "system/item-entity.h"
+#include "system/monster-race-info.h"
#include "system/player-type-definition.h"
#include "term/screen-processor.h"
#include "term/term-color-types.h"
+#include "term/z-form.h"
+#include "util/bit-flags-calculator.h"
#include "view/display-messages.h"
#include "world/world.h"
+#include <algorithm>
/*!
* @brief 賞金首の引き換え処理 / Get prize
- * @param player_ptr ã\83\97ã\83¬ã\83¼ヤーへの参照ポインタ
+ * @param player_ptr ã\83\97ã\83¬ã\82¤ヤーへの参照ポインタ
* @return 各種賞金首のいずれかでも換金が行われたか否か。
*/
-bool exchange_cash(player_type *player_ptr)
+bool exchange_cash(PlayerType *player_ptr)
{
bool change = false;
GAME_TEXT o_name[MAX_NLEN];
- object_type *o_ptr;
+ ItemEntity *o_ptr;
for (INVENTORY_IDX i = 0; i <= INVEN_SUB_HAND; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CAPTURE) && (o_ptr->pval == MON_TSUCHINOKO)) {
- char buf[MAX_NLEN + 32];
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
+
+ if ((o_ptr->bi_key.tval() == ItemKindType::CAPTURE) && (r_idx_of_item == MonsterRaceId::TSUCHINOKO)) {
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
- if (get_check(buf)) {
+ if (get_check(format(_("%s を換金しますか?", "Convert %s into money? "), o_name))) {
msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(1000000L * o_ptr->number));
player_ptr->au += 1000000L * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE) && (o_ptr->pval == MON_TSUCHINOKO)) {
- char buf[MAX_NLEN + 32];
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
+
+ if (o_ptr->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE) && (r_idx_of_item == MonsterRaceId::TSUCHINOKO)) {
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
- if (get_check(buf)) {
+ if (get_check(format(_("%s を換金しますか?", "Convert %s into money? "), o_name))) {
msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(200000L * o_ptr->number));
player_ptr->au += 200000L * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON) && (o_ptr->pval == MON_TSUCHINOKO)) {
- char buf[MAX_NLEN + 32];
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
+
+ if (o_ptr->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON) && (r_idx_of_item == MonsterRaceId::TSUCHINOKO)) {
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
- if (get_check(buf)) {
+ if (get_check(format(_("%s を換金しますか?", "Convert %s into money? "), o_name))) {
msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)(100000L * o_ptr->number));
player_ptr->au += 100000L * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_CORPSE)
- && (streq(r_info[o_ptr->pval].name.c_str(), r_info[current_world_ptr->today_mon].name.c_str()))) {
- char buf[MAX_NLEN + 32];
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
+
+ if (o_ptr->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_CORPSE) && (streq(monraces_info[r_idx_of_item].name.data(), monraces_info[w_ptr->today_mon].name.data()))) {
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
- if (get_check(buf)) {
+ if (get_check(format(_("%s を換金しますか?", "Convert %s into money? "), o_name))) {
msg_format(
- _("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[current_world_ptr->today_mon].level * 50 + 100) * o_ptr->number));
- player_ptr->au += (r_info[current_world_ptr->today_mon].level * 50 + 100) * o_ptr->number;
+ _("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((monraces_info[w_ptr->today_mon].level * 50 + 100) * o_ptr->number));
+ player_ptr->au += (monraces_info[w_ptr->today_mon].level * 50 + 100) * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
vary_item(player_ptr, i, -o_ptr->number);
}
for (INVENTORY_IDX i = 0; i < INVEN_PACK; i++) {
o_ptr = &player_ptr->inventory_list[i];
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
- if ((o_ptr->tval == TV_CORPSE) && (o_ptr->sval == SV_SKELETON)
- && (streq(r_info[o_ptr->pval].name.c_str(), r_info[current_world_ptr->today_mon].name.c_str()))) {
- char buf[MAX_NLEN + 32];
+ if (o_ptr->bi_key == BaseitemKey(ItemKindType::CORPSE, SV_SKELETON) && (streq(monraces_info[r_idx_of_item].name.data(), monraces_info[w_ptr->today_mon].name.data()))) {
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%s を換金しますか?", "Convert %s into money? "), o_name);
- if (get_check(buf)) {
- msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((r_info[current_world_ptr->today_mon].level * 30 + 60) * o_ptr->number));
- player_ptr->au += (r_info[current_world_ptr->today_mon].level * 30 + 60) * o_ptr->number;
+ if (get_check(format(_("%s を換金しますか?", "Convert %s into money? "), o_name))) {
+ msg_format(_("賞金 %ld$を手に入れた。", "You get %ldgp."), (long int)((monraces_info[w_ptr->today_mon].level * 30 + 60) * o_ptr->number));
+ player_ptr->au += (monraces_info[w_ptr->today_mon].level * 30 + 60) * o_ptr->number;
player_ptr->redraw |= (PR_GOLD);
vary_item(player_ptr, i, -o_ptr->number);
}
}
}
- for (int j = 0; j < MAX_BOUNTY; j++) {
+ for (auto &[r_idx, is_achieved] : w_ptr->bounties) {
+ if (is_achieved) {
+ continue;
+ }
+
for (INVENTORY_IDX i = INVEN_PACK - 1; i >= 0; i--) {
o_ptr = &player_ptr->inventory_list[i];
- if ((o_ptr->tval != TV_CORPSE) || (o_ptr->pval != current_world_ptr->bounty_r_idx[j]))
+ const auto r_idx_of_item = static_cast<MonsterRaceId>(o_ptr->pval);
+
+ if ((o_ptr->bi_key.tval() != ItemKindType::CORPSE) || (r_idx_of_item != r_idx)) {
continue;
+ }
- char buf[MAX_NLEN + 20];
- int num, k;
INVENTORY_IDX item_new;
- object_type forge;
+ ItemEntity forge;
describe_flavor(player_ptr, o_name, o_ptr, 0);
- sprintf(buf, _("%sを渡しますか?", "Hand %s over? "), o_name);
- if (!get_check(buf))
+ if (!get_check(format(_("%sを渡しますか?", "Hand %s over? "), o_name))) {
continue;
+ }
vary_item(player_ptr, i, -o_ptr->number);
chg_virtue(player_ptr, V_JUSTICE, 5);
- current_world_ptr->bounty_r_idx[j] += 10000;
+ is_achieved = true;
- for (num = 0, k = 0; k < MAX_BOUNTY; k++) {
- if (current_world_ptr->bounty_r_idx[k] >= 10000)
- num++;
- }
+ auto num = std::count_if(std::begin(w_ptr->bounties), std::end(w_ptr->bounties),
+ [](const auto &b_ref) { return b_ref.is_achieved; });
msg_format(_("これで合計 %d ポイント獲得しました。", "You earned %d point%s total."), num, (num > 1 ? "s" : ""));
- (&forge)->prep(player_ptr, lookup_kind(prize_list[num - 1].tval, prize_list[num - 1].sval));
- apply_magic_to_object(player_ptr, &forge, player_ptr->current_floor_ptr->object_level, AM_NO_FIXED_ART);
+ (&forge)->prep(lookup_baseitem_id(prize_list[num - 1]));
+ ItemMagicApplier(player_ptr, &forge, player_ptr->current_floor_ptr->object_level, AM_NO_FIXED_ART).execute();
object_aware(player_ptr, &forge);
object_known(&forge);
}
}
- if (change)
+ if (change) {
return true;
+ }
msg_print(_("賞金を得られそうなものは持っていなかった。", "You have nothing."));
- msg_print(NULL);
+ msg_print(nullptr);
return false;
}
/*!
* @brief 本日の賞金首情報を表示する。
- * @param player_ptr ã\83\97ã\83¬ã\83¼ヤーへの参照ポインタ
+ * @param player_ptr ã\83\97ã\83¬ã\82¤ヤーへの参照ポインタ
*/
-void today_target(player_type *player_ptr)
+void today_target(PlayerType *player_ptr)
{
- char buf[160];
- monster_race *r_ptr = &r_info[current_world_ptr->today_mon];
+ auto *r_ptr = &monraces_info[w_ptr->today_mon];
clear_bldg(4, 18);
c_put_str(TERM_YELLOW, _("本日の賞金首", "Wanted monster that changes from day to day"), 5, 10);
- sprintf(buf, _("ターゲット: %s", "target: %s"), r_ptr->name.c_str());
- c_put_str(TERM_YELLOW, buf, 6, 10);
- sprintf(buf, _("死体 ---- $%d", "corpse ---- $%d"), (int)r_ptr->level * 50 + 100);
- prt(buf, 8, 10);
- sprintf(buf, _("骨 ---- $%d", "skeleton ---- $%d"), (int)r_ptr->level * 30 + 60);
- prt(buf, 9, 10);
- player_ptr->today_mon = current_world_ptr->today_mon;
+ c_put_str(TERM_YELLOW, format(_("ターゲット: %s", "target: %s"), r_ptr->name.data()), 6, 10);
+ prt(format(_("死体 ---- $%d", "corpse ---- $%d"), (int)r_ptr->level * 50 + 100), 8, 10);
+ prt(format(_("骨 ---- $%d", "skeleton ---- $%d"), (int)r_ptr->level * 30 + 60), 9, 10);
+ player_ptr->knows_daily_bounty = true;
}
/*!
prt(_("死体を持ち帰れば報酬を差し上げます。", "Offer a prize when you bring a wanted monster's corpse"), 4, 10);
c_put_str(TERM_YELLOW, _("現在の賞金首", "Wanted monsters"), 6, 10);
- for (int i = 0; i < MAX_BOUNTY; i++) {
- byte color;
- concptr done_mark;
- monster_race *r_ptr
- = &r_info[(current_world_ptr->bounty_r_idx[i] > 10000 ? current_world_ptr->bounty_r_idx[i] - 10000 : current_world_ptr->bounty_r_idx[i])];
-
- if (current_world_ptr->bounty_r_idx[i] > 10000) {
- color = TERM_RED;
- done_mark = _("(済)", "(done)");
- } else {
- color = TERM_WHITE;
- done_mark = "";
- }
+ for (auto i = 0U; i < std::size(w_ptr->bounties); i++) {
+ const auto &[r_idx, is_achieved] = w_ptr->bounties[i];
+ MonsterRaceInfo *r_ptr = &monraces_info[r_idx];
+
+ auto color = is_achieved ? TERM_RED : TERM_WHITE;
+ auto done_mark = is_achieved ? _("(済)", "(done)") : "";
- c_prt(color, format("%s %s", r_ptr->name.c_str(), done_mark), y + 7, 10);
+ c_prt(color, format("%s %s", r_ptr->name.data(), done_mark), y + 7, 10);
y = (y + 1) % 10;
- if (!y && (i < MAX_BOUNTY - 1)) {
+ if (!y && (i < std::size(w_ptr->bounties) - 1)) {
prt(_("何かキーを押してください", "Hit any key."), 0, 0);
(void)inkey();
prt("", 0, 0);
/*!
* @brief 今日の賞金首を確定する / Determine today's bounty monster
- * @param player_type プレーヤーへの参照ポインタ
+ * @param PlayerType プレイヤーへの参照ポインタ
* @note conv_old is used if loaded 0.0.3 or older save file
*/
-void determine_daily_bounty(player_type *player_ptr, bool conv_old)
+void determine_daily_bounty(PlayerType *player_ptr, bool conv_old)
{
- int max_dl = 3, i;
+ int max_dl = 3;
if (!conv_old) {
- for (i = 0; i < current_world_ptr->max_d_idx; i++) {
- if (max_dlv[i] < d_info[i].mindepth)
+ for (const auto &d_ref : dungeons_info) {
+ if (max_dlv[d_ref.idx] < d_ref.mindepth) {
continue;
- if (max_dl < max_dlv[i])
- max_dl = max_dlv[i];
+ }
+ if (max_dl < max_dlv[d_ref.idx]) {
+ max_dl = max_dlv[d_ref.idx];
+ }
}
} else {
- max_dl = MAX(max_dlv[DUNGEON_ANGBAND], 3);
+ max_dl = std::max(max_dlv[DUNGEON_ANGBAND], 3);
}
get_mon_num_prep_bounty(player_ptr);
while (true) {
- current_world_ptr->today_mon = get_mon_num(player_ptr, MIN(max_dl / 2, 40), max_dl, GMN_ARENA);
- monster_race *r_ptr;
- r_ptr = &r_info[current_world_ptr->today_mon];
+ w_ptr->today_mon = get_mon_num(player_ptr, std::min(max_dl / 2, 40), max_dl, GMN_ARENA);
+ MonsterRaceInfo *r_ptr;
+ r_ptr = &monraces_info[w_ptr->today_mon];
if (cheat_hear) {
- msg_format("日替わり候補: %s ", r_ptr->name.c_str());
+ msg_format("日替わり候補: %s ", r_ptr->name.data());
}
- if (r_ptr->flags1 & RF1_UNIQUE)
+ if (r_ptr->kind_flags.has(MonsterKindType::UNIQUE)) {
continue;
- if (r_ptr->flags7 & (RF7_NAZGUL | RF7_UNIQUE2))
+ }
+ if (r_ptr->population_flags.has(MonsterPopulationType::NAZGUL) || any_bits(r_ptr->flags7, RF7_UNIQUE2)) {
continue;
- if (r_ptr->flags2 & RF2_MULTIPLY)
+ }
+ if (r_ptr->flags2 & RF2_MULTIPLY) {
continue;
- if ((r_ptr->flags9 & (RF9_DROP_CORPSE | RF9_DROP_SKELETON)) != (RF9_DROP_CORPSE | RF9_DROP_SKELETON))
+ }
+ if (!r_ptr->drop_flags.has_all_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON })) {
continue;
- if (r_ptr->rarity > 10)
+ }
+ if (r_ptr->rarity > 10) {
continue;
+ }
break;
}
- // プレイヤーは日替わり賞金首に関する知識を失う。
- player_ptr->today_mon = 0;
+ player_ptr->knows_daily_bounty = false;
}
/*!
* @brief 賞金首となるユニークを確定する / Determine bounty uniques
- * @param player_ptr ã\83\97ã\83¬ã\83¼ヤーへの参照ポインタ
+ * @param player_ptr ã\83\97ã\83¬ã\82¤ヤーへの参照ポインタ
*/
-void determine_bounty_uniques(player_type *player_ptr)
+void determine_bounty_uniques(PlayerType *player_ptr)
{
get_mon_num_prep_bounty(player_ptr);
- for (int i = 0; i < MAX_BOUNTY; i++) {
- while (true) {
- current_world_ptr->bounty_r_idx[i] = get_mon_num(player_ptr, 0, MAX_DEPTH - 1, GMN_ARENA);
- monster_race *r_ptr;
- r_ptr = &r_info[current_world_ptr->bounty_r_idx[i]];
-
- if (!(r_ptr->flags1 & RF1_UNIQUE))
- continue;
-
- if (!(r_ptr->flags9 & (RF9_DROP_CORPSE | RF9_DROP_SKELETON)))
- continue;
-
- if (r_ptr->rarity > 100)
- continue;
-
- if (no_questor_or_bounty_uniques(current_world_ptr->bounty_r_idx[i]))
- continue;
-
- int j;
- for (j = 0; j < i; j++) {
- if (current_world_ptr->bounty_r_idx[i] == current_world_ptr->bounty_r_idx[j])
- break;
- }
-
- if (j == i)
- break;
+ auto is_suitable_for_bounty = [](MonsterRaceId r_idx) {
+ const auto &r_ref = monraces_info[r_idx];
+ bool is_suitable = r_ref.kind_flags.has(MonsterKindType::UNIQUE);
+ is_suitable &= r_ref.drop_flags.has_any_of({ MonsterDropType::DROP_CORPSE, MonsterDropType::DROP_SKELETON });
+ is_suitable &= r_ref.rarity <= 100;
+ is_suitable &= !no_questor_or_bounty_uniques(r_idx);
+ return is_suitable;
+ };
+
+ // 賞金首とするモンスターの種族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);
+ if (!is_suitable_for_bounty(r_idx)) {
+ continue;
}
- }
- for (int i = 0; i < MAX_BOUNTY - 1; i++) {
- for (int j = i; j < MAX_BOUNTY; j++) {
- MONRACE_IDX tmp;
- if (r_info[current_world_ptr->bounty_r_idx[i]].level > r_info[current_world_ptr->bounty_r_idx[j]].level) {
- tmp = current_world_ptr->bounty_r_idx[i];
- current_world_ptr->bounty_r_idx[i] = current_world_ptr->bounty_r_idx[j];
- current_world_ptr->bounty_r_idx[j] = tmp;
- }
+ auto is_already_selected = std::any_of(bounty_r_idx_list.begin(), bounty_r_idx_list.end(),
+ [r_idx](MonsterRaceId bounty_r_idx) { return r_idx == bounty_r_idx; });
+ if (!is_already_selected) {
+ bounty_r_idx_list.push_back(r_idx);
}
}
+
+ // モンスターのLVで昇順に並び替える
+ std::sort(bounty_r_idx_list.begin(), bounty_r_idx_list.end(),
+ [](MonsterRaceId r_idx1, MonsterRaceId r_idx2) {
+ return monraces_info[r_idx1].level < monraces_info[r_idx2].level;
+ });
+
+ // 賞金首情報を設定
+ std::transform(bounty_r_idx_list.begin(), bounty_r_idx_list.end(), std::begin(w_ptr->bounties),
+ [](MonsterRaceId r_idx) -> bounty_type {
+ return { r_idx, false };
+ });
}