OSDN Git Service

Merge pull request #3532 from sikabane-works/release/3.0.0.87-alpha
[hengbandforosx/hengbandosx.git] / src / object-enchant / others / apply-magic-ring.cpp
1 /*!
2  * @brief 指輪を強化生成する処理
3  * @date 2021/04/30
4  * @author Hourier
5  */
6
7 #include "object-enchant/others/apply-magic-ring.h"
8 #include "artifact/random-art-generator.h"
9 #include "object-enchant/object-boost.h"
10 #include "object-enchant/object-ego.h"
11 #include "object-enchant/special-object-flags.h"
12 #include "object-enchant/trc-types.h"
13 #include "sv-definition/sv-ring-types.h"
14 #include "system/baseitem-info.h"
15 #include "system/item-entity.h"
16 #include "system/player-type-definition.h"
17 #include "util/bit-flags-calculator.h"
18
19 /*
20  * @brief コンストラクタ
21  * @param player_ptr プレイヤーへの参照ポインタ
22  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
23  * @param level 生成基準階
24  * @param power 生成ランク
25  */
26 RingEnchanter::RingEnchanter(PlayerType *player_ptr, ItemEntity *o_ptr, DEPTH level, int power)
27     : player_ptr(player_ptr)
28     , o_ptr(o_ptr)
29     , level(level)
30     , power(power)
31 {
32 }
33
34 /*!
35  * @brief 指輪に生成ランクごとの強化を与える
36  * Apply magic to an item known to be a "ring" or "amulet"
37  * @param player_ptr プレイヤーへの参照ポインタ
38  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
39  * @param level 生成基準階
40  * @param power 生成ランク
41  * @return なし
42  * @details power > 2はデバッグ専用.
43  */
44 void RingEnchanter::apply_magic()
45 {
46     if ((this->power == 0) && (randint0(100) < 50)) {
47         this->power = -1;
48     }
49
50     this->sval_enchant();
51     if ((this->power > 2) || (one_in_(400) && (this->power > 0) && !this->o_ptr->is_cursed() && (this->level > 79))) {
52         this->o_ptr->pval = std::min<short>(this->o_ptr->pval, 4);
53         become_random_artifact(this->player_ptr, this->o_ptr, false);
54         return;
55     }
56
57     if ((this->power == 2) && one_in_(2)) {
58         give_ego_index();
59         this->o_ptr->curse_flags.clear();
60         return;
61     }
62
63     if ((this->power == -2) && one_in_(2)) {
64         give_cursed();
65     }
66 }
67
68 void RingEnchanter::sval_enchant()
69 {
70     const auto sval = this->o_ptr->bi_key.sval();
71     if (!sval.has_value()) {
72         return;
73     }
74
75     switch (sval.value()) {
76     case SV_RING_ATTACKS:
77         this->o_ptr->pval = (PARAMETER_VALUE)m_bonus(2, this->level);
78         if (one_in_(15)) {
79             this->o_ptr->pval++;
80         }
81
82         if (this->o_ptr->pval < 1) {
83             this->o_ptr->pval = 1;
84         }
85
86         if (this->power < 0) {
87             set_bits(this->o_ptr->ident, IDENT_BROKEN);
88             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
89             this->o_ptr->pval = 0 - (this->o_ptr->pval);
90         }
91
92         break;
93     case SV_RING_STR:
94     case SV_RING_CON:
95     case SV_RING_DEX:
96         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(5, this->level);
97         if (this->power < 0) {
98             set_bits(this->o_ptr->ident, IDENT_BROKEN);
99             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
100             this->o_ptr->pval = 0 - (this->o_ptr->pval);
101         }
102
103         break;
104     case SV_RING_SPEED:
105         this->o_ptr->pval = randint1(5) + (PARAMETER_VALUE)m_bonus(5, this->level);
106         while (randint0(100) < 50) {
107             this->o_ptr->pval++;
108         }
109
110         if (this->power < 0) {
111             set_bits(this->o_ptr->ident, IDENT_BROKEN);
112             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
113             this->o_ptr->pval = 0 - (this->o_ptr->pval);
114             break;
115         }
116
117         break;
118     case SV_RING_LORDLY:
119         do {
120             one_lordly_high_resistance(this->o_ptr);
121         } while (one_in_(4));
122
123         this->o_ptr->to_a = 10 + randint1(5) + (ARMOUR_CLASS)m_bonus(10, this->level);
124         break;
125     case SV_RING_WARNING:
126         if (one_in_(3)) {
127             one_low_esp(this->o_ptr);
128         }
129
130         break;
131     case SV_RING_SEARCHING:
132         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(5, this->level);
133         if (this->power < 0) {
134             set_bits(this->o_ptr->ident, IDENT_BROKEN);
135             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
136             this->o_ptr->pval = 0 - (this->o_ptr->pval);
137         }
138
139         break;
140     case SV_RING_FLAMES:
141     case SV_RING_ACID:
142     case SV_RING_ICE:
143     case SV_RING_ELEC:
144         this->o_ptr->to_a = 5 + randint1(5) + (ARMOUR_CLASS)m_bonus(10, this->level);
145         break;
146     case SV_RING_WEAKNESS:
147     case SV_RING_STUPIDITY:
148         set_bits(this->o_ptr->ident, IDENT_BROKEN);
149         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
150         this->o_ptr->pval = 0 - (1 + (PARAMETER_VALUE)m_bonus(5, this->level));
151         if (this->power > 0) {
152             this->power = 0 - this->power;
153         }
154
155         break;
156     case SV_RING_WOE:
157         set_bits(this->o_ptr->ident, IDENT_BROKEN);
158         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
159         this->o_ptr->to_a = 0 - (5 + (ARMOUR_CLASS)m_bonus(10, this->level));
160         this->o_ptr->pval = 0 - (1 + (PARAMETER_VALUE)m_bonus(5, this->level));
161         if (this->power > 0) {
162             this->power = 0 - this->power;
163         }
164
165         break;
166     case SV_RING_DAMAGE:
167         this->o_ptr->to_d = 1 + randint1(5) + (int)m_bonus(16, this->level);
168         if (this->power < 0) {
169             set_bits(this->o_ptr->ident, IDENT_BROKEN);
170             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
171             this->o_ptr->to_d = 0 - this->o_ptr->to_d;
172         }
173
174         break;
175     case SV_RING_ACCURACY:
176         this->o_ptr->to_h = 1 + randint1(5) + (HIT_PROB)m_bonus(16, this->level);
177         if (this->power < 0) {
178             set_bits(this->o_ptr->ident, IDENT_BROKEN);
179             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
180             this->o_ptr->to_h = 0 - this->o_ptr->to_h;
181         }
182
183         break;
184     case SV_RING_PROTECTION:
185         this->o_ptr->to_a = 5 + randint1(8) + (ARMOUR_CLASS)m_bonus(10, this->level);
186         if (this->power < 0) {
187             set_bits(this->o_ptr->ident, IDENT_BROKEN);
188             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
189             this->o_ptr->to_a = 0 - this->o_ptr->to_a;
190         }
191
192         break;
193     case SV_RING_SLAYING:
194         this->o_ptr->to_d = randint1(5) + (int)m_bonus(12, this->level);
195         this->o_ptr->to_h = randint1(5) + (HIT_PROB)m_bonus(12, this->level);
196
197         if (this->power < 0) {
198             set_bits(this->o_ptr->ident, IDENT_BROKEN);
199             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
200             this->o_ptr->to_h = 0 - this->o_ptr->to_h;
201             this->o_ptr->to_d = 0 - this->o_ptr->to_d;
202         }
203
204         break;
205     case SV_RING_MUSCLE:
206     case SV_RING_LAW:
207         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(3, this->level);
208         if (one_in_(4)) {
209             this->o_ptr->pval++;
210         }
211
212         if (this->power < 0) {
213             set_bits(this->o_ptr->ident, IDENT_BROKEN);
214             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
215             this->o_ptr->pval = 0 - this->o_ptr->pval;
216         }
217
218         break;
219     case SV_RING_AGGRAVATION:
220         set_bits(this->o_ptr->ident, IDENT_BROKEN);
221         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
222         if (this->power > 0) {
223             this->power = 0 - this->power;
224         }
225
226         break;
227     default:
228         break;
229     }
230 }
231
232 void RingEnchanter::give_ego_index()
233 {
234     while (!this->o_ptr->is_ego()) {
235         int tmp = m_bonus(10, this->level);
236         const auto &baseitem = this->o_ptr->get_baseitem();
237         switch (randint1(28)) {
238         case 1:
239         case 2:
240             this->o_ptr->ego_idx = EgoType::RING_THROW;
241             break;
242         case 3:
243         case 4:
244             if (baseitem.flags.has(TR_REGEN)) {
245                 break;
246             }
247
248             this->o_ptr->ego_idx = EgoType::RING_REGEN;
249             break;
250         case 5:
251         case 6:
252             if (baseitem.flags.has(TR_LITE_1)) {
253                 break;
254             }
255
256             this->o_ptr->ego_idx = EgoType::RING_LITE;
257             break;
258         case 7:
259         case 8:
260             if (baseitem.flags.has(TR_TELEPORT)) {
261                 break;
262             }
263
264             this->o_ptr->ego_idx = EgoType::RING_TELEPORT;
265             break;
266         case 9:
267         case 10:
268             if (this->o_ptr->to_h) {
269                 break;
270             }
271
272             this->o_ptr->ego_idx = EgoType::RING_TO_H;
273             break;
274         case 11:
275         case 12:
276             if (this->o_ptr->to_d) {
277                 break;
278             }
279
280             this->o_ptr->ego_idx = EgoType::RING_TO_D;
281             break;
282         case 13:
283             if ((this->o_ptr->to_h) || (this->o_ptr->to_d)) {
284                 break;
285             }
286
287             this->o_ptr->ego_idx = EgoType::RING_SLAY;
288             break;
289         case 14:
290             if ((baseitem.flags.has(TR_STR)) || this->o_ptr->to_h || this->o_ptr->to_d) {
291                 break;
292             }
293
294             this->o_ptr->ego_idx = EgoType::RING_WIZARD;
295             break;
296         case 15:
297             if (baseitem.flags.has(TR_ACTIVATE)) {
298                 break;
299             }
300
301             this->o_ptr->ego_idx = EgoType::RING_HERO;
302             break;
303         case 16:
304             if (baseitem.flags.has(TR_ACTIVATE)) {
305                 break;
306             }
307
308             if (tmp > 8) {
309                 this->o_ptr->ego_idx = EgoType::RING_MANA_BALL;
310                 break;
311             }
312
313             if (tmp > 4) {
314                 this->o_ptr->ego_idx = EgoType::RING_MANA_BOLT;
315                 break;
316             }
317
318             this->o_ptr->ego_idx = EgoType::RING_MAGIC_MIS;
319             break;
320         case 17:
321             if (baseitem.flags.has(TR_ACTIVATE)) {
322                 break;
323             }
324
325             if (baseitem.flags.has_not(TR_RES_FIRE) && (baseitem.flags.has(TR_RES_COLD) || baseitem.flags.has(TR_RES_ELEC) || baseitem.flags.has(TR_RES_ACID))) {
326                 break;
327             }
328
329             if (tmp > 7) {
330                 this->o_ptr->ego_idx = EgoType::RING_DRAGON_F;
331                 break;
332             }
333
334             if (tmp > 3) {
335                 this->o_ptr->ego_idx = EgoType::RING_FIRE_BALL;
336                 break;
337             }
338
339             this->o_ptr->ego_idx = EgoType::RING_FIRE_BOLT;
340             break;
341         case 18:
342             if (baseitem.flags.has(TR_ACTIVATE)) {
343                 break;
344             }
345
346             if (baseitem.flags.has_not(TR_RES_COLD) && (baseitem.flags.has(TR_RES_FIRE) || baseitem.flags.has(TR_RES_ELEC) || baseitem.flags.has(TR_RES_ACID))) {
347                 break;
348             }
349
350             if (tmp > 7) {
351                 this->o_ptr->ego_idx = EgoType::RING_DRAGON_C;
352                 break;
353             }
354
355             if (tmp > 3) {
356                 this->o_ptr->ego_idx = EgoType::RING_COLD_BALL;
357                 break;
358             }
359
360             this->o_ptr->ego_idx = EgoType::RING_COLD_BOLT;
361             break;
362         case 19:
363             if (baseitem.flags.has(TR_ACTIVATE)) {
364                 break;
365             }
366
367             if (baseitem.flags.has_not(TR_RES_ELEC) && (baseitem.flags.has(TR_RES_COLD) || baseitem.flags.has(TR_RES_FIRE) || baseitem.flags.has(TR_RES_ACID))) {
368                 break;
369             }
370
371             if (tmp > 4) {
372                 this->o_ptr->ego_idx = EgoType::RING_ELEC_BALL;
373                 break;
374             }
375
376             this->o_ptr->ego_idx = EgoType::RING_ELEC_BOLT;
377             break;
378         case 20:
379             if (baseitem.flags.has(TR_ACTIVATE)) {
380                 break;
381             }
382
383             if (baseitem.flags.has_not(TR_RES_ACID) && (baseitem.flags.has(TR_RES_COLD) || baseitem.flags.has(TR_RES_ELEC) || baseitem.flags.has(TR_RES_FIRE))) {
384                 break;
385             }
386
387             if (tmp > 4) {
388                 this->o_ptr->ego_idx = EgoType::RING_ACID_BALL;
389                 break;
390             }
391
392             this->o_ptr->ego_idx = EgoType::RING_ACID_BOLT;
393             break;
394         case 21:
395         case 22:
396         case 23:
397         case 24:
398         case 25:
399         case 26:
400             give_high_ego_index();
401             break;
402         }
403     }
404 }
405
406 void RingEnchanter::give_high_ego_index()
407 {
408     const auto sval = this->o_ptr->bi_key.sval();
409     if (!sval.has_value()) {
410         return;
411     }
412
413     switch (sval.value()) {
414     case SV_RING_SPEED:
415         if (!one_in_(3)) {
416             break;
417         }
418
419         this->o_ptr->ego_idx = EgoType::RING_D_SPEED;
420         break;
421     case SV_RING_DAMAGE:
422     case SV_RING_ACCURACY:
423     case SV_RING_SLAYING:
424         if (one_in_(2)) {
425             break;
426         }
427
428         if (one_in_(2)) {
429             this->o_ptr->ego_idx = EgoType::RING_HERO;
430             break;
431         }
432
433         this->o_ptr->ego_idx = EgoType::RING_BERSERKER;
434         this->o_ptr->to_h -= 2 + randint1(4);
435         this->o_ptr->to_d += 2 + randint1(4);
436         break;
437     case SV_RING_PROTECTION:
438         this->o_ptr->ego_idx = EgoType::RING_SUPER_AC;
439         this->o_ptr->to_a += 7 + m_bonus(5, this->level);
440         break;
441     case SV_RING_RES_FEAR:
442         this->o_ptr->ego_idx = EgoType::RING_HERO;
443         break;
444     case SV_RING_SHOTS:
445         if (one_in_(2)) {
446             break;
447         }
448
449         this->o_ptr->ego_idx = EgoType::RING_HUNTER;
450         break;
451     case SV_RING_SEARCHING:
452         this->o_ptr->ego_idx = EgoType::RING_STEALTH;
453         break;
454     case SV_RING_TELEPORTATION:
455         this->o_ptr->ego_idx = EgoType::RING_TELE_AWAY;
456         break;
457     case SV_RING_RES_BLINDNESS:
458         this->o_ptr->ego_idx = one_in_(2) ? EgoType::RING_RES_LITE : EgoType::RING_RES_DARK;
459         break;
460     case SV_RING_LORDLY:
461         if (!one_in_(20)) {
462             break;
463         }
464
465         one_lordly_high_resistance(this->o_ptr);
466         one_lordly_high_resistance(this->o_ptr);
467         this->o_ptr->ego_idx = EgoType::RING_TRUE;
468         break;
469     case SV_RING_FLAMES:
470         if (one_in_(2)) {
471             break;
472         }
473
474         this->o_ptr->ego_idx = EgoType::RING_DRAGON_F;
475         break;
476     case SV_RING_ICE:
477         if (one_in_(2)) {
478             break;
479         }
480
481         this->o_ptr->ego_idx = EgoType::RING_DRAGON_C;
482         break;
483     case SV_RING_WARNING:
484         if (one_in_(2)) {
485             break;
486         }
487
488         this->o_ptr->ego_idx = EgoType::RING_M_DETECT;
489         break;
490     default:
491         break;
492     }
493 }
494
495 void RingEnchanter::give_cursed()
496 {
497     if (this->o_ptr->to_h > 0) {
498         this->o_ptr->to_h = 0 - this->o_ptr->to_h;
499     }
500
501     if (this->o_ptr->to_d > 0) {
502         this->o_ptr->to_d = 0 - this->o_ptr->to_d;
503     }
504
505     if (this->o_ptr->to_a > 0) {
506         this->o_ptr->to_a = 0 - this->o_ptr->to_a;
507     }
508
509     if (this->o_ptr->pval > 0) {
510         this->o_ptr->pval = 0 - this->o_ptr->pval;
511     }
512
513     while (!this->o_ptr->is_ego()) {
514         const auto &baseitem = this->o_ptr->get_baseitem();
515         switch (randint1(5)) {
516         case 1:
517             if (baseitem.flags.has(TR_DRAIN_EXP)) {
518                 break;
519             }
520             this->o_ptr->ego_idx = EgoType::RING_DRAIN_EXP;
521             break;
522         case 2:
523             this->o_ptr->ego_idx = EgoType::RING_NO_MELEE;
524             break;
525         case 3:
526             if (baseitem.flags.has(TR_AGGRAVATE)) {
527                 break;
528             }
529             this->o_ptr->ego_idx = EgoType::RING_AGGRAVATE;
530             break;
531         case 4:
532             if (baseitem.flags.has(TR_TY_CURSE)) {
533                 break;
534             }
535             this->o_ptr->ego_idx = EgoType::RING_TY_CURSE;
536             break;
537         case 5:
538             this->o_ptr->ego_idx = EgoType::RING_ALBINO;
539             break;
540         }
541     }
542
543     set_bits(this->o_ptr->ident, IDENT_BROKEN);
544     this->o_ptr->curse_flags.set({ CurseTraitType::CURSED, CurseTraitType::HEAVY_CURSE });
545 }