OSDN Git Service

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