5 * @details Ego-Item indexes (see "lib/edit/e_info.txt")
7 #include "object-enchant/object-ego.h"
8 #include "artifact/random-art-effects.h"
9 #include "object-enchant/object-boost.h"
10 #include "object-enchant/object-curse.h"
11 #include "object-enchant/special-object-flags.h"
12 #include "object-enchant/trc-types.h"
13 #include "object-hook/hook-weapon.h"
14 #include "object/tval-types.h"
15 #include "sv-definition/sv-protector-types.h"
16 #include "sv-definition/sv-weapon-types.h"
17 #include "system/object-type-definition.h"
18 #include "util/bit-flags-calculator.h"
19 #include "util/enum-converter.h"
20 #include "util/probability-table.h"
26 std::map<EgoType, ego_item_type> e_info;
29 * @brief アイテムのエゴをレア度の重みに合わせてランダムに選択する
30 * Choose random ego type
31 * @param slot 取得したいエゴの装備部位
32 * @param good TRUEならば通常のエゴ、FALSEならば呪いのエゴが選択対象となる。
33 * @return 選択されたエゴ情報のID、万一選択できなかった場合は0が返る。
35 EgoType get_random_ego(byte slot, bool good)
37 ProbabilityTable<EgoType> prob_table;
38 for (const auto &[e_idx, e_ref] : e_info) {
39 if (e_ref.idx == EgoType::NONE || e_ref.slot != slot || e_ref.rarity <= 0) {
43 bool worthless = e_ref.rating == 0 || e_ref.gen_flags.has_any_of({ ItemGenerationTraitType::CURSED, ItemGenerationTraitType::HEAVY_CURSE, ItemGenerationTraitType::PERMA_CURSE });
45 if (good != worthless) {
46 prob_table.entry_item(e_ref.idx, (255 / e_ref.rarity));
50 if (!prob_table.empty()) {
51 return prob_table.pick_one_at_random();
58 * @brief エゴオブジェクトに呪いを付加する
59 * @param player_ptr プレイヤー情報への参照ポインタ
60 * @param o_ptr オブジェクト情報への参照ポインタ
61 * @param gen_flags 生成フラグ(参照渡し)
63 static void ego_invest_curse(ObjectType *o_ptr, EnumClassFlagGroup<ItemGenerationTraitType> &gen_flags)
65 if (gen_flags.has(ItemGenerationTraitType::CURSED)) {
66 o_ptr->curse_flags.set(CurseTraitType::CURSED);
68 if (gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
69 o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
71 if (gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
72 o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
74 if (gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
75 o_ptr->curse_flags.set(get_curse(0, o_ptr));
77 if (gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
78 o_ptr->curse_flags.set(get_curse(1, o_ptr));
80 if (gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
81 o_ptr->curse_flags.set(get_curse(2, o_ptr));
86 * @brief エゴオブジェクトに追加能力/耐性を付加する
87 * @param o_ptr オブジェクト情報への参照ポインタ
88 * @param gen_flags 生成フラグ(参照渡し)
90 static void ego_invest_extra_abilities(ObjectType *o_ptr, EnumClassFlagGroup<ItemGenerationTraitType> &gen_flags)
92 if (gen_flags.has(ItemGenerationTraitType::ONE_SUSTAIN)) {
95 if (gen_flags.has(ItemGenerationTraitType::XTRA_POWER)) {
98 if (gen_flags.has(ItemGenerationTraitType::XTRA_H_RES)) {
99 one_high_resistance(o_ptr);
101 if (gen_flags.has(ItemGenerationTraitType::XTRA_E_RES)) {
102 one_ele_resistance(o_ptr);
104 if (gen_flags.has(ItemGenerationTraitType::XTRA_D_RES)) {
105 one_dragon_ele_resistance(o_ptr);
107 if (gen_flags.has(ItemGenerationTraitType::XTRA_L_RES)) {
108 one_lordly_high_resistance(o_ptr);
110 if (gen_flags.has(ItemGenerationTraitType::XTRA_RES)) {
111 one_resistance(o_ptr);
113 if (gen_flags.has(ItemGenerationTraitType::LIGHT_WEIGHT)) {
114 make_weight_ligten(o_ptr);
116 if (gen_flags.has(ItemGenerationTraitType::HEAVY_WEIGHT)) {
117 make_weight_heavy(o_ptr);
119 if (gen_flags.has(ItemGenerationTraitType::XTRA_AC)) {
122 if (gen_flags.has(ItemGenerationTraitType::HIGH_TELEPATHY)) {
123 add_high_telepathy(o_ptr);
125 if (gen_flags.has(ItemGenerationTraitType::LOW_TELEPATHY)) {
126 add_low_telepathy(o_ptr);
128 if (gen_flags.has(ItemGenerationTraitType::XTRA_L_ESP)) {
131 if (gen_flags.has(ItemGenerationTraitType::ADD_DICE)) {
134 if (gen_flags.has(ItemGenerationTraitType::DOUBLED_DICE)) {
137 if (gen_flags.has(ItemGenerationTraitType::XTRA_DICE)) {
140 } while (one_in_(o_ptr->dd));
142 if (gen_flags.has(ItemGenerationTraitType::XTRA_DICE_SIDE)) {
145 } while (one_in_(o_ptr->ds));
155 * @brief エゴアイテムの追加能力/耐性フラグを解釈する
156 * @param player_ptr プレイヤー情報への参照ポインタ
157 * @param o_ptr オブジェクト情報への参照ポインタ
158 * @param e_ptr エゴアイテム情報への参照ポインタ
159 * @param gen_flags 生成フラグ(参照渡し)
161 static void ego_interpret_extra_abilities(ObjectType *o_ptr, ego_item_type *e_ptr, EnumClassFlagGroup<ItemGenerationTraitType> &gen_flags)
163 for (auto &xtra : e_ptr->xtra_flags) {
164 if (xtra.mul == 0 || xtra.dev == 0) {
168 if (randint0(xtra.dev) >= xtra.mul) { //! @note mul/devで適用
172 auto n = xtra.tr_flags.size();
174 auto f = xtra.tr_flags[randint0(n)];
175 auto except = (f == TR_VORPAL && o_ptr->tval != ItemKindType::SWORD);
177 o_ptr->art_flags.set(f);
181 for (auto f : xtra.trg_flags) {
188 * @brief 0 および負数に対応した randint1()
191 * n == 0 のとき、常に 0 を返す。
192 * n > 0 のとき、[1, n] の乱数を返す。
193 * n < 0 のとき、[n,-1] の乱数を返す。
195 static int randint1_signed(const int n)
201 return n > 0 ? randint1(n) : -randint1(-n);
205 * @brief 追加込みでエゴがフラグを保持しているか判定する
206 * @param o_ptr オブジェクト情報への参照ポインタ
207 * @param e_ptr エゴアイテム情報への参照ポインタ
209 * @return 持つならtrue、持たないならfalse
211 static bool ego_has_flag(ObjectType *o_ptr, ego_item_type *e_ptr, tr_type flag)
213 if (o_ptr->art_flags.has(flag)) {
216 if (e_ptr->flags.has(flag)) {
223 * @brief エゴに追加攻撃のpvalを付加する
224 * @param player_ptr プレイヤー情報への参照ポインタ
225 * @param o_ptr オブジェクト情報への参照ポインタ
226 * @param e_ptr エゴアイテム情報への参照ポインタ
229 void ego_invest_extra_attack(ObjectType *o_ptr, ego_item_type *e_ptr, DEPTH lev)
231 if (!o_ptr->is_weapon()) {
232 o_ptr->pval = e_ptr->max_pval >= 0 ? 1 : randint1_signed(e_ptr->max_pval);
236 if (o_ptr->ego_idx == EgoType::ATTACKS) {
237 o_ptr->pval = randint1(e_ptr->max_pval * lev / 100 + 1);
238 if (o_ptr->pval > 3) {
241 if ((o_ptr->tval == ItemKindType::SWORD) && (o_ptr->sval == SV_HAYABUSA)) {
242 o_ptr->pval += randint1(2);
247 if (ego_has_flag(o_ptr, e_ptr, TR_EARTHQUAKE)) {
248 o_ptr->pval += randint1(e_ptr->max_pval);
252 if (ego_has_flag(o_ptr, e_ptr, TR_SLAY_EVIL) || ego_has_flag(o_ptr, e_ptr, TR_KILL_EVIL)) {
254 if ((lev > 60) && one_in_(3) && ((o_ptr->dd * (o_ptr->ds + 1)) < 15)) {
260 o_ptr->pval += randint1(2);
264 * @brief オブジェクトをエゴアイテムにする
265 * @param player_ptr プレイヤー情報への参照ポインタ
266 * @param o_ptr オブジェクト情報への参照ポインタ
269 void apply_ego(ObjectType *o_ptr, DEPTH lev)
271 auto e_ptr = &e_info[o_ptr->ego_idx];
272 auto gen_flags = e_ptr->gen_flags;
274 ego_interpret_extra_abilities(o_ptr, e_ptr, gen_flags);
277 o_ptr->ident |= (IDENT_BROKEN);
280 ego_invest_curse(o_ptr, gen_flags);
281 ego_invest_extra_abilities(o_ptr, gen_flags);
283 if (e_ptr->act_idx > RandomArtActType::NONE) {
284 o_ptr->activation_id = e_ptr->act_idx;
287 o_ptr->to_h += (HIT_PROB)e_ptr->base_to_h;
288 o_ptr->to_d += (int)e_ptr->base_to_d;
289 o_ptr->to_a += (ARMOUR_CLASS)e_ptr->base_to_a;
291 auto is_powerful = e_ptr->gen_flags.has(ItemGenerationTraitType::POWERFUL);
292 auto is_cursed = (o_ptr->is_cursed() || o_ptr->is_broken()) && !is_powerful;
294 if (e_ptr->max_to_h) {
295 o_ptr->to_h -= randint1(e_ptr->max_to_h);
297 if (e_ptr->max_to_d) {
298 o_ptr->to_d -= randint1(e_ptr->max_to_d);
300 if (e_ptr->max_to_a) {
301 o_ptr->to_a -= randint1(e_ptr->max_to_a);
303 if (e_ptr->max_pval) {
304 o_ptr->pval -= randint1(e_ptr->max_pval);
308 if (e_ptr->max_to_h > 0 && o_ptr->to_h < 0) {
309 o_ptr->to_h = 0 - o_ptr->to_h;
311 if (e_ptr->max_to_d > 0 && o_ptr->to_d < 0) {
312 o_ptr->to_d = 0 - o_ptr->to_d;
314 if (e_ptr->max_to_a > 0 && o_ptr->to_a < 0) {
315 o_ptr->to_a = 0 - o_ptr->to_a;
319 o_ptr->to_h += (HIT_PROB)randint1_signed(e_ptr->max_to_h);
320 o_ptr->to_d += (int)randint1_signed(e_ptr->max_to_d);
321 o_ptr->to_a += (ARMOUR_CLASS)randint1_signed(e_ptr->max_to_a);
323 if (gen_flags.has(ItemGenerationTraitType::MOD_ACCURACY)) {
324 while (o_ptr->to_h < o_ptr->to_d + 10) {
328 o_ptr->to_h = std::max<short>(o_ptr->to_h, 15);
331 if (gen_flags.has(ItemGenerationTraitType::MOD_VELOCITY)) {
332 while (o_ptr->to_d < o_ptr->to_h + 10) {
336 o_ptr->to_d = std::max(o_ptr->to_d, 15);
339 if ((o_ptr->ego_idx == EgoType::PROTECTION) || (o_ptr->ego_idx == EgoType::S_PROTECTION) || (o_ptr->ego_idx == EgoType::H_PROTECTION)) {
340 o_ptr->to_a = std::max<short>(o_ptr->to_a, 15);
343 if (e_ptr->max_pval) {
344 if (o_ptr->ego_idx == EgoType::BAT) {
345 o_ptr->pval = randint1(e_ptr->max_pval);
346 if (o_ptr->sval == SV_ELVEN_CLOAK) {
347 o_ptr->pval += randint1(2);
350 if (ego_has_flag(o_ptr, e_ptr, TR_BLOWS)) {
351 ego_invest_extra_attack(o_ptr, e_ptr, lev);
353 if (e_ptr->max_pval > 0) {
354 o_ptr->pval += randint1(e_ptr->max_pval);
355 } else if (e_ptr->max_pval < 0) {
356 o_ptr->pval -= randint1(0 - e_ptr->max_pval);
362 if ((o_ptr->ego_idx == EgoType::SPEED) && (lev < 50)) {
363 o_ptr->pval = randint1(o_ptr->pval);
366 if ((o_ptr->tval == ItemKindType::SWORD) && (o_ptr->sval == SV_HAYABUSA) && (o_ptr->pval > 2) && (o_ptr->ego_idx != EgoType::ATTACKS)) {