6 #include "object-enchant/object-ego.h"
7 #include "artifact/random-art-effects.h"
8 #include "object-enchant/object-boost.h"
9 #include "object-enchant/object-curse.h"
10 #include "object-enchant/special-object-flags.h"
11 #include "object-enchant/trc-types.h"
12 #include "object-hook/hook-weapon.h"
13 #include "object/tval-types.h"
14 #include "sv-definition/sv-protector-types.h"
15 #include "sv-definition/sv-weapon-types.h"
16 #include "system/item-entity.h"
17 #include "util/bit-flags-calculator.h"
18 #include "util/enum-converter.h"
19 #include "util/probability-table.h"
22 std::map<EgoType, EgoItemDefinition> egos_info;
25 * @brief アイテムのエゴをレア度の重みに合わせてランダムに選択する
26 * Choose random ego type
27 * @param slot 取得したいエゴの装備部位
28 * @param good TRUEならば通常のエゴ、FALSEならば呪いのエゴが選択対象となる。
29 * @return 選択されたエゴ情報のID、万一選択できなかった場合は0が返る。
31 EgoType get_random_ego(byte slot, bool good)
33 ProbabilityTable<EgoType> prob_table;
34 for (const auto &[e_idx, ego] : egos_info) {
35 if (ego.idx == EgoType::NONE || ego.slot != slot || ego.rarity <= 0) {
40 ItemGenerationTraitType::CURSED,
41 ItemGenerationTraitType::HEAVY_CURSE,
42 ItemGenerationTraitType::PERMA_CURSE
44 const auto worthless = ego.rating == 0 || ego.gen_flags.has_any_of(curses);
45 if (good != worthless) {
46 prob_table.entry_item(ego.idx, (255 / ego.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(ItemEntity *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(ItemEntity *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 ego エゴアイテム情報への参照
159 * @param gen_flags 生成フラグ(参照渡し)
161 static void ego_interpret_extra_abilities(ItemEntity *o_ptr, const EgoItemDefinition &ego, EnumClassFlagGroup<ItemGenerationTraitType> &gen_flags)
163 for (const auto &xtra : ego.xtra_flags) {
164 if (xtra.mul == 0 || xtra.dev == 0) {
168 if (randint0(xtra.dev) >= xtra.mul) { //! @note mul/devで適用
172 if (!xtra.tr_flags.empty()) {
173 const auto f = rand_choice(xtra.tr_flags);
174 const auto except = (f == TR_VORPAL) && (o_ptr->bi_key.tval() != ItemKindType::SWORD);
176 o_ptr->art_flags.set(f);
180 for (auto f : xtra.trg_flags) {
187 * @brief 0 および負数に対応した randint1()
190 * n == 0 のとき、常に 0 を返す。
191 * n > 0 のとき、[1, n] の乱数を返す。
192 * n < 0 のとき、[n,-1] の乱数を返す。
194 static int randint1_signed(const int n)
200 return n > 0 ? randint1(n) : -randint1(-n);
204 * @brief 追加込みでエゴがフラグを保持しているか判定する
205 * @param o_ptr オブジェクト情報への参照ポインタ
206 * @param ego エゴアイテム情報への参照
208 * @return 持つならtrue、持たないならfalse
210 static bool ego_has_flag(ItemEntity *o_ptr, const EgoItemDefinition &ego, tr_type flag)
212 if (o_ptr->art_flags.has(flag)) {
215 if (ego.flags.has(flag)) {
222 * @brief エゴに追加攻撃のpvalを付加する
223 * @param player_ptr プレイヤー情報への参照ポインタ
224 * @param o_ptr オブジェクト情報への参照ポインタ
225 * @param ego エゴアイテム情報への参照
228 void ego_invest_extra_attack(ItemEntity *o_ptr, const EgoItemDefinition &ego, DEPTH lev)
230 if (!o_ptr->is_weapon()) {
231 o_ptr->pval = ego.max_pval >= 0 ? 1 : randint1_signed(ego.max_pval);
235 if (o_ptr->ego_idx == EgoType::ATTACKS) {
236 o_ptr->pval = randint1(ego.max_pval * lev / 100 + 1);
237 if (o_ptr->pval > 3) {
241 if (o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_HAYABUSA)) {
242 o_ptr->pval += randint1(2);
248 if (ego_has_flag(o_ptr, ego, TR_EARTHQUAKE)) {
249 o_ptr->pval += randint1(ego.max_pval);
253 if (ego_has_flag(o_ptr, ego, TR_SLAY_EVIL) || ego_has_flag(o_ptr, ego, TR_KILL_EVIL)) {
255 if ((lev > 60) && one_in_(3) && ((o_ptr->dd * (o_ptr->ds + 1)) < 15)) {
261 o_ptr->pval += randint1(2);
265 * @brief オブジェクトをエゴアイテムにする
266 * @param player_ptr プレイヤー情報への参照ポインタ
267 * @param o_ptr オブジェクト情報への参照ポインタ
270 void apply_ego(ItemEntity *o_ptr, DEPTH lev)
272 const auto &ego = o_ptr->get_ego();
273 auto gen_flags = ego.gen_flags;
275 ego_interpret_extra_abilities(o_ptr, ego, gen_flags);
278 o_ptr->ident |= (IDENT_BROKEN);
281 ego_invest_curse(o_ptr, gen_flags);
282 ego_invest_extra_abilities(o_ptr, gen_flags);
284 if (ego.act_idx > RandomArtActType::NONE) {
285 o_ptr->activation_id = ego.act_idx;
288 o_ptr->to_h += (HIT_PROB)ego.base_to_h;
289 o_ptr->to_d += (int)ego.base_to_d;
290 o_ptr->to_a += (ARMOUR_CLASS)ego.base_to_a;
292 auto is_powerful = ego.gen_flags.has(ItemGenerationTraitType::POWERFUL);
293 auto is_cursed = (o_ptr->is_cursed() || o_ptr->is_broken()) && !is_powerful;
296 o_ptr->to_h -= randint1(ego.max_to_h);
299 o_ptr->to_d -= randint1(ego.max_to_d);
302 o_ptr->to_a -= randint1(ego.max_to_a);
305 o_ptr->pval -= randint1(ego.max_pval);
309 if (ego.max_to_h > 0 && o_ptr->to_h < 0) {
310 o_ptr->to_h = 0 - o_ptr->to_h;
312 if (ego.max_to_d > 0 && o_ptr->to_d < 0) {
313 o_ptr->to_d = 0 - o_ptr->to_d;
315 if (ego.max_to_a > 0 && o_ptr->to_a < 0) {
316 o_ptr->to_a = 0 - o_ptr->to_a;
320 o_ptr->to_h += (HIT_PROB)randint1_signed(ego.max_to_h);
321 o_ptr->to_d += (int)randint1_signed(ego.max_to_d);
322 o_ptr->to_a += (ARMOUR_CLASS)randint1_signed(ego.max_to_a);
324 if (gen_flags.has(ItemGenerationTraitType::MOD_ACCURACY)) {
325 while (o_ptr->to_h < o_ptr->to_d + 10) {
329 o_ptr->to_h = std::max<short>(o_ptr->to_h, 15);
332 if (gen_flags.has(ItemGenerationTraitType::MOD_VELOCITY)) {
333 while (o_ptr->to_d < o_ptr->to_h + 10) {
337 o_ptr->to_d = std::max(o_ptr->to_d, 15);
340 if ((o_ptr->ego_idx == EgoType::PROTECTION) || (o_ptr->ego_idx == EgoType::S_PROTECTION) || (o_ptr->ego_idx == EgoType::H_PROTECTION)) {
341 o_ptr->to_a = std::max<short>(o_ptr->to_a, 15);
345 if (o_ptr->ego_idx == EgoType::BAT) {
346 o_ptr->pval = randint1(ego.max_pval);
347 if (o_ptr->bi_key.sval() == SV_ELVEN_CLOAK) {
348 o_ptr->pval += randint1(2);
351 if (ego_has_flag(o_ptr, ego, TR_BLOWS)) {
352 ego_invest_extra_attack(o_ptr, ego, lev);
354 if (ego.max_pval > 0) {
355 o_ptr->pval += randint1(ego.max_pval);
356 } else if (ego.max_pval < 0) {
357 o_ptr->pval -= randint1(0 - ego.max_pval);
363 if ((o_ptr->ego_idx == EgoType::SPEED) && (lev < 50)) {
364 o_ptr->pval = randint1(o_ptr->pval);
367 if ((o_ptr->bi_key == BaseitemKey(ItemKindType::SWORD, SV_HAYABUSA)) && (o_ptr->pval > 2) && (o_ptr->ego_idx != EgoType::ATTACKS)) {