OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / artifact / random-art-characteristics.cpp
1 /*!
2  * @file random-art-characteristics.cpp
3  * @brief ランダムアーティファクトのバイアス付加処理実装
4  */
5
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"
18 #include <sstream>
19 #include <string_view>
20
21 static void pval_subtraction(ItemEntity *o_ptr)
22 {
23     if (o_ptr->pval > 0) {
24         o_ptr->pval = 0 - (o_ptr->pval + randint1(4));
25     }
26
27     if (o_ptr->to_a > 0) {
28         o_ptr->to_a = 0 - (o_ptr->to_a + randint1(4));
29     }
30
31     if (o_ptr->to_h > 0) {
32         o_ptr->to_h = 0 - (o_ptr->to_h + randint1(4));
33     }
34
35     if (o_ptr->to_d > 0) {
36         o_ptr->to_d = 0 - (o_ptr->to_d + randint1(4));
37     }
38 }
39
40 static void add_negative_flags(ItemEntity *o_ptr)
41 {
42     if (one_in_(4)) {
43         o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
44     }
45
46     if (one_in_(3)) {
47         o_ptr->art_flags.set(TR_TY_CURSE);
48     }
49
50     if (one_in_(2)) {
51         o_ptr->art_flags.set(TR_AGGRAVATE);
52     }
53
54     if (one_in_(3)) {
55         o_ptr->art_flags.set(TR_DRAIN_EXP);
56     }
57
58     if (one_in_(6)) {
59         o_ptr->art_flags.set(TR_ADD_L_CURSE);
60     }
61
62     if (one_in_(9)) {
63         o_ptr->art_flags.set(TR_ADD_H_CURSE);
64     }
65
66     if (one_in_(9)) {
67         o_ptr->art_flags.set(TR_DRAIN_HP);
68     }
69
70     if (one_in_(9)) {
71         o_ptr->art_flags.set(TR_DRAIN_MANA);
72     }
73
74     if (one_in_(2)) {
75         o_ptr->art_flags.set(TR_TELEPORT);
76     } else if (one_in_(3)) {
77         o_ptr->art_flags.set(TR_NO_TELE);
78     }
79 }
80
81 /*!
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 対象のオブジェクト構造体ポインタ
89  */
90 void curse_artifact(PlayerType *player_ptr, ItemEntity *o_ptr)
91 {
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);
98     }
99 }
100
101 /*!
102  * @brief ランダムアーティファクトの名前リストをオブジェクト種別と生成パワーに応じて選択する
103  * @param armour 防具かどうか
104  * @param power 生成パワー
105  * @return ファイル名
106  */
107 static std::string get_random_art_filename(const bool armour, const int power)
108 {
109     std::stringstream ss;
110     ss << (armour ? "a_" : "w_");
111     switch (power) {
112     case 0:
113         ss << "cursed";
114         break;
115     case 1:
116         ss << "low";
117         break;
118     case 2:
119         ss << "med";
120         break;
121     default:
122         ss << "high";
123     }
124
125     ss << _("_j.txt", ".txt");
126     return ss.str();
127 }
128
129 /*!
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% (固定銘が尽きていたら漢字銘になることもある).
137  */
138 std::string get_random_name(const ItemEntity &item, bool armour, int power)
139 {
140     const auto prob = randint1(100);
141     constexpr auto chance_sindarin = 10;
142     if (prob <= chance_sindarin) {
143         return get_table_sindarin();
144     }
145
146     constexpr auto chance_table = 20;
147     if (prob <= chance_table) {
148         return get_table_name();
149     }
150
151     auto filename = get_random_art_filename(armour, power);
152     auto random_artifact_name = get_random_line(filename.data(), item.artifact_bias);
153 #ifdef JP
154     if (random_artifact_name.has_value()) {
155         return random_artifact_name.value();
156     }
157
158     return get_table_name();
159 #else
160     return random_artifact_name.value();
161 #endif
162 }
163
164 /*対邪平均ダメージの計算処理*/
165 static int calc_arm_avgdamage(PlayerType *player_ptr, ItemEntity *o_ptr)
166 {
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;
175     } else {
176         s_evil = dam;
177     }
178
179     if (flags.has(TR_FORCE_WEAPON)) {
180         dam = forced = dam * 3 / 2 + (o_ptr->dd * o_ptr->ds + o_ptr->dd);
181     } else {
182         forced = dam;
183     }
184
185     if (flags.has(TR_VORPAL)) {
186         dam = vorpal = dam * 11 / 9;
187     } else {
188         vorpal = dam;
189     }
190
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);
194     return dam;
195 }
196
197 bool has_extreme_damage_rate(PlayerType *player_ptr, ItemEntity *o_ptr)
198 {
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)) {
202             return true;
203         }
204
205         if (flags.has(TR_BLOWS) && (o_ptr->pval == 2) && (calc_arm_avgdamage(player_ptr, o_ptr) > 43)) {
206             return true;
207         }
208
209         if (flags.has(TR_BLOWS) && (o_ptr->pval == 3) && (calc_arm_avgdamage(player_ptr, o_ptr) > 33)) {
210             return true;
211         }
212
213         if (calc_arm_avgdamage(player_ptr, o_ptr) > 63) {
214             return true;
215         }
216
217         return false;
218     }
219
220     if (flags.has(TR_BLOWS) && (o_ptr->pval == 1) && (calc_arm_avgdamage(player_ptr, o_ptr) > 65)) {
221         return true;
222     }
223
224     if (flags.has(TR_BLOWS) && (o_ptr->pval == 2) && (calc_arm_avgdamage(player_ptr, o_ptr) > 52)) {
225         return true;
226     }
227
228     if (flags.has(TR_BLOWS) && (o_ptr->pval == 3) && (calc_arm_avgdamage(player_ptr, o_ptr) > 40)) {
229         return true;
230     }
231
232     if (calc_arm_avgdamage(player_ptr, o_ptr) > 75) {
233         return true;
234     }
235
236     return false;
237 }