OSDN Git Service

[Refactor] #2645 display_object_list() を整形した
[hengbandforosx/hengbandosx.git] / src / object-enchant / item-magic-applier.cpp
1 /*!
2  * @brief ベースアイテムを強化する処理
3  * @date 2022/03/22
4  * @author Hourier
5  */
6
7 #include "object-enchant/item-magic-applier.h"
8 #include "artifact/fixed-art-generator.h"
9 #include "dungeon/dungeon.h"
10 #include "object-enchant/enchanter-base.h"
11 #include "object-enchant/enchanter-factory.h"
12 #include "object-enchant/item-apply-magic.h"
13 #include "object-enchant/object-curse.h"
14 #include "object-enchant/special-object-flags.h"
15 #include "object/object-kind.h"
16 #include "player/player-status-flags.h"
17 #include "system/artifact-type-definition.h"
18 #include "system/floor-type-definition.h"
19 #include "system/player-type-definition.h"
20 #include "util/bit-flags-calculator.h"
21 #include "world/world.h"
22
23 /*!
24  * @brief コンストラクタ
25  * @param player_ptr プレイヤーへの参照ポインタ
26  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
27  * @param lev 生成基準階
28  * @param mode 生成オプション
29  */
30 ItemMagicApplier::ItemMagicApplier(PlayerType *player_ptr, ObjectType *o_ptr, DEPTH lev, BIT_FLAGS mode)
31     : player_ptr(player_ptr)
32     , o_ptr(o_ptr)
33     , lev(lev)
34     , mode(mode)
35 {
36     if (player_ptr->ppersonality == PERSONALITY_MUNCHKIN) {
37         this->lev += randint0(player_ptr->lev / 2 + 10);
38     }
39
40     if (this->lev > MAX_DEPTH - 1) {
41         this->lev = MAX_DEPTH - 1;
42     }
43 }
44
45 /*!
46  * @brief 生成されたベースアイテムに魔法的な強化を与えるメインルーチン
47  * @details エゴ&アーティファクトの生成、呪い、pval強化
48  */
49 void ItemMagicApplier::execute()
50 {
51     auto [chance_good, chance_great] = this->calculate_chances();
52     auto power = this->calculate_power(chance_good, chance_great);
53     auto rolls = this->calculate_rolls(power);
54     this->try_make_artifact(rolls);
55     if (this->set_fixed_artifact_generation_info()) {
56         return;
57     }
58
59     auto enchanter = EnchanterFactory::create_enchanter(this->player_ptr, this->o_ptr, this->lev, power);
60     enchanter->apply_magic();
61     if (this->o_ptr->is_ego()) {
62         apply_ego(this->o_ptr, this->lev);
63         return;
64     }
65
66     this->apply_cursed();
67 }
68
69 /*!
70  * @brief 上質及び高級品の生成確率 [%]を算出する
71  * @return 上質と高級品の生成確率組み合わせ
72  */
73 std::tuple<int, int> ItemMagicApplier::calculate_chances()
74 {
75     auto chance_good = this->lev + 10;
76     if (chance_good > d_info[this->player_ptr->dungeon_idx].obj_good) {
77         chance_good = d_info[this->player_ptr->dungeon_idx].obj_good;
78     }
79
80     auto chance_great = chance_good * 2 / 3;
81     if ((this->player_ptr->ppersonality != PERSONALITY_MUNCHKIN) && (chance_great > d_info[this->player_ptr->dungeon_idx].obj_great)) {
82         chance_great = d_info[this->player_ptr->dungeon_idx].obj_great;
83     }
84
85     if (has_good_luck(this->player_ptr)) {
86         chance_good += 5;
87         chance_great += 2;
88     } else if (this->player_ptr->muta.has(PlayerMutationType::BAD_LUCK)) {
89         chance_good -= 5;
90         chance_great -= 2;
91     }
92
93     return std::make_tuple(chance_good, chance_great);
94 }
95
96 /*!
97  * @brief 上質/高級品/アーティファクト生成パワー計算
98  * @param chance_good 上質品が生成される確率 [%]
99  * @param chance_great 高級品が生成される確率 [%]
100  * @return 生成パワー
101  * @details アーティファクト生成はデバッグ専用
102  */
103 int ItemMagicApplier::calculate_power(const int chance_good, const int chance_great)
104 {
105     auto power = 0;
106     if (any_bits(this->mode, AM_GOOD) || magik(chance_good)) {
107         power = 1;
108         if (any_bits(this->mode, AM_GREAT) || magik(chance_great)) {
109             power = 2;
110             if (any_bits(this->mode, AM_SPECIAL)) {
111                 power = 3;
112             }
113         }
114     } else if (magik(chance_good)) {
115         power = -1;
116         if (magik(chance_great)) {
117             power = -2;
118         }
119     }
120
121     if (any_bits(this->mode, AM_CURSED)) {
122         if (power > 0) {
123             power = 0 - power;
124         } else {
125             power--;
126         }
127     }
128
129     return power;
130 }
131
132 /*!
133  * @brief 生成パワーを元にアーティファクト生成の試行回数を算出する
134  * @param power 生成パワー
135  */
136 int ItemMagicApplier::calculate_rolls(const int power)
137 {
138     auto rolls = 0;
139     if (power >= 2) {
140         rolls = 1;
141     }
142
143     if (any_bits(this->mode, AM_GREAT | AM_SPECIAL)) {
144         rolls = 4;
145     }
146
147     if (any_bits(this->mode, AM_NO_FIXED_ART) || this->o_ptr->is_fixed_artifact()) {
148         rolls = 0;
149     }
150
151     return rolls;
152 }
153
154 /*!
155  * @brief アーティファクト生成を試みる
156  * @param power 試行回数
157  */
158 void ItemMagicApplier::try_make_artifact(const int rolls)
159 {
160     for (auto i = 0; i < rolls; i++) {
161         if (make_artifact(this->player_ptr, this->o_ptr)) {
162             break;
163         }
164
165         if (!has_good_luck(this->player_ptr) || !one_in_(77)) {
166             continue;
167         }
168
169         if (make_artifact(this->player_ptr, this->o_ptr)) {
170             break;
171         }
172     }
173 }
174
175 /*!
176  * @brief 固定アーティファクトの生成情報を記憶する
177  */
178 bool ItemMagicApplier::set_fixed_artifact_generation_info()
179 {
180     if (!this->o_ptr->is_fixed_artifact()) {
181         return false;
182     }
183
184     apply_artifact(this->player_ptr, this->o_ptr);
185     auto &a_ref = a_info.at(this->o_ptr->fixed_artifact_idx);
186     a_ref.is_generated = true;
187     if (w_ptr->character_dungeon) {
188         a_ref.floor_id = this->player_ptr->floor_id;
189     }
190
191     return true;
192 }
193
194 /*!
195  * @brief アイテムに呪いフラグを付与する
196  */
197 void ItemMagicApplier::apply_cursed()
198 {
199     if (this->o_ptr->k_idx == 0) {
200         return;
201     }
202
203     const auto *k_ptr = &k_info[this->o_ptr->k_idx];
204     if (!k_info[this->o_ptr->k_idx].cost) {
205         set_bits(this->o_ptr->ident, IDENT_BROKEN);
206     }
207
208     if (k_ptr->gen_flags.has(ItemGenerationTraitType::CURSED)) {
209         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
210     }
211
212     if (k_ptr->gen_flags.has(ItemGenerationTraitType::HEAVY_CURSE)) {
213         this->o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
214     }
215
216     if (k_ptr->gen_flags.has(ItemGenerationTraitType::PERMA_CURSE)) {
217         this->o_ptr->curse_flags.set(CurseTraitType::PERMA_CURSE);
218     }
219
220     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE0)) {
221         this->o_ptr->curse_flags.set(get_curse(0, this->o_ptr));
222     }
223
224     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE1)) {
225         this->o_ptr->curse_flags.set(get_curse(1, this->o_ptr));
226     }
227
228     if (k_ptr->gen_flags.has(ItemGenerationTraitType::RANDOM_CURSE2)) {
229         this->o_ptr->curse_flags.set(get_curse(2, this->o_ptr));
230     }
231 }