2 * @file random-art-characteristics.cpp
3 * @brief ランダムアーティファクトのバイアス付加処理実装
6 #include "artifact/random-art-characteristics.h"
7 #include "flavor/object-flavor.h"
8 #include "game-option/cheat-types.h"
9 #include "io/files-util.h"
10 #include "object-enchant/tr-types.h"
11 #include "object-enchant/trc-types.h"
12 #include "object/object-flags.h"
13 #include "player-base/player-class.h"
14 #include "system/item-entity.h"
15 #include "system/player-type-definition.h"
16 #include "util/bit-flags-calculator.h"
17 #include "wizard/wizard-messages.h"
19 #include <string_view>
21 static void pval_subtraction(ItemEntity *o_ptr)
23 if (o_ptr->pval > 0) {
24 o_ptr->pval = 0 - (o_ptr->pval + randint1(4));
27 if (o_ptr->to_a > 0) {
28 o_ptr->to_a = 0 - (o_ptr->to_a + randint1(4));
31 if (o_ptr->to_h > 0) {
32 o_ptr->to_h = 0 - (o_ptr->to_h + randint1(4));
35 if (o_ptr->to_d > 0) {
36 o_ptr->to_d = 0 - (o_ptr->to_d + randint1(4));
40 static void add_negative_flags(ItemEntity *o_ptr)
43 o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
47 o_ptr->art_flags.set(TR_TY_CURSE);
51 o_ptr->art_flags.set(TR_AGGRAVATE);
55 o_ptr->art_flags.set(TR_DRAIN_EXP);
59 o_ptr->art_flags.set(TR_ADD_L_CURSE);
63 o_ptr->art_flags.set(TR_ADD_H_CURSE);
67 o_ptr->art_flags.set(TR_DRAIN_HP);
71 o_ptr->art_flags.set(TR_DRAIN_MANA);
75 o_ptr->art_flags.set(TR_TELEPORT);
76 } else if (one_in_(3)) {
77 o_ptr->art_flags.set(TR_NO_TELE);
82 * @brief ランダムアーティファクト生成中、対象のオブジェクトを呪いのアーティファクトにする経過処理。/ generation process of cursed artifact.
83 * @details pval、AC、命中、ダメージが正の場合、符号反転の上1d4だけ悪化させ、重い呪い、呪いフラグを必ず付加。
84 * 祝福を無効。確率に応じて、永遠の呪い、太古の怨念、経験値吸収、弱い呪いの継続的付加、強い呪いの継続的付加、HP吸収の呪い、
85 * MP吸収の呪い、乱テレポート、反テレポート、反魔法をつける。
86 * @attention プレイヤーの職業依存処理あり。
87 * @param player_ptr プレイヤーへの参照ポインタ
88 * @param o_ptr 対象のオブジェクト構造体ポインタ
90 void curse_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
92 pval_subtraction(o_ptr);
93 o_ptr->curse_flags.set({ CurseTraitType::HEAVY_CURSE, CurseTraitType::CURSED });
94 o_ptr->art_flags.reset(TR_BLESSED);
95 add_negative_flags(o_ptr);
96 if (!PlayerClass(player_ptr).is_soldier() && one_in_(3)) {
97 o_ptr->art_flags.set(TR_NO_MAGIC);
102 * @brief ランダムアーティファクトの名前リストをオブジェクト種別と生成パワーに応じて選択する
103 * @param armour 防具かどうか
107 static std::string get_random_art_filename(const bool armour, const int power)
109 std::stringstream ss;
110 ss << (armour ? "a_" : "w_");
125 ss << _("_j.txt", ".txt");
130 * @brief ランダムアーティファクト生成中、対象のオブジェクトに名前を与える.
131 * @param o_ptr 処理中のアイテム参照ポインタ
132 * @param armour 対象のオブジェクトが防具が否か
133 * @param power 銘の基準となるオブジェクトの価値レベル(0=呪い、1=低位、2=中位、3以上=高位)
134 * @return ランダムアーティファクト名
135 * @details 確率によって、シンダリン銘、漢字銘 (anameからランダム)、固定名のいずれか一つが与えられる.
136 * シンダリン銘:10%、漢字銘18%、固定銘72% (固定銘が尽きていたら漢字銘になることもある).
138 std::string get_random_name(const ItemEntity &item, bool armour, int power)
140 const auto prob = randint1(100);
141 constexpr auto chance_sindarin = 10;
142 if (prob <= chance_sindarin) {
143 return get_table_sindarin();
146 constexpr auto chance_table = 20;
147 if (prob <= chance_table) {
148 return get_table_name();
151 auto filename = get_random_art_filename(armour, power);
152 auto random_artifact_name = get_random_line(filename.data(), item.artifact_bias);
154 if (random_artifact_name.has_value()) {
155 return random_artifact_name.value();
158 return get_table_name();
160 return random_artifact_name.value();
165 static int calc_arm_avgdamage(PlayerType *player_ptr, ItemEntity *o_ptr)
167 auto flags = object_flags(o_ptr);
168 int base, forced, vorpal;
169 int s_evil = forced = vorpal = 0;
170 int dam = base = (o_ptr->dd * o_ptr->ds + o_ptr->dd) / 2;
171 if (flags.has(TR_KILL_EVIL)) {
172 dam = s_evil = dam * 7 / 2;
173 } else if (flags.has_not(TR_KILL_EVIL) && flags.has(TR_SLAY_EVIL)) {
174 dam = s_evil = dam * 2;
179 if (flags.has(TR_FORCE_WEAPON)) {
180 dam = forced = dam * 3 / 2 + (o_ptr->dd * o_ptr->ds + o_ptr->dd);
185 if (flags.has(TR_VORPAL)) {
186 dam = vorpal = dam * 11 / 9;
191 dam = dam + o_ptr->to_d;
192 constexpr auto fmt = _("素:%d> 対邪:%d> 理力:%d> 切:%d> 最終:%d", "Normal:%d> Evil:%d> Force:%d> Vorpal:%d> Total:%d");
193 msg_format_wizard(player_ptr, CHEAT_OBJECT, fmt, base, s_evil, forced, vorpal, dam);
197 bool has_extreme_damage_rate(PlayerType *player_ptr, ItemEntity *o_ptr)
199 auto flags = object_flags(o_ptr);
200 if (flags.has(TR_VAMPIRIC)) {
201 if (flags.has(TR_BLOWS) && (o_ptr->pval == 1) && (calc_arm_avgdamage(player_ptr, o_ptr) > 52)) {
205 if (flags.has(TR_BLOWS) && (o_ptr->pval == 2) && (calc_arm_avgdamage(player_ptr, o_ptr) > 43)) {
209 if (flags.has(TR_BLOWS) && (o_ptr->pval == 3) && (calc_arm_avgdamage(player_ptr, o_ptr) > 33)) {
213 if (calc_arm_avgdamage(player_ptr, o_ptr) > 63) {
220 if (flags.has(TR_BLOWS) && (o_ptr->pval == 1) && (calc_arm_avgdamage(player_ptr, o_ptr) > 65)) {
224 if (flags.has(TR_BLOWS) && (o_ptr->pval == 2) && (calc_arm_avgdamage(player_ptr, o_ptr) > 52)) {
228 if (flags.has(TR_BLOWS) && (o_ptr->pval == 3) && (calc_arm_avgdamage(player_ptr, o_ptr) > 40)) {
232 if (calc_arm_avgdamage(player_ptr, o_ptr) > 75) {