OSDN Git Service

5de1fcabe328be4f9c974147e63d1f8f30af4c79
[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 "object/object-kind.h"
14 #include "sv-definition/sv-ring-types.h"
15 #include "system/object-type-definition.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, ObjectType *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     switch (this->o_ptr->sval) {
71     case SV_RING_ATTACKS:
72         this->o_ptr->pval = (PARAMETER_VALUE)m_bonus(2, this->level);
73         if (one_in_(15)) {
74             this->o_ptr->pval++;
75         }
76
77         if (this->o_ptr->pval < 1) {
78             this->o_ptr->pval = 1;
79         }
80
81         if (this->power < 0) {
82             set_bits(this->o_ptr->ident, IDENT_BROKEN);
83             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
84             this->o_ptr->pval = 0 - (this->o_ptr->pval);
85         }
86
87         break;
88     case SV_RING_STR:
89     case SV_RING_CON:
90     case SV_RING_DEX:
91         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(5, this->level);
92         if (this->power < 0) {
93             set_bits(this->o_ptr->ident, IDENT_BROKEN);
94             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
95             this->o_ptr->pval = 0 - (this->o_ptr->pval);
96         }
97
98         break;
99     case SV_RING_SPEED:
100         this->o_ptr->pval = randint1(5) + (PARAMETER_VALUE)m_bonus(5, this->level);
101         while (randint0(100) < 50) {
102             this->o_ptr->pval++;
103         }
104
105         if (this->power < 0) {
106             set_bits(this->o_ptr->ident, IDENT_BROKEN);
107             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
108             this->o_ptr->pval = 0 - (this->o_ptr->pval);
109             break;
110         }
111
112         break;
113     case SV_RING_LORDLY:
114         do {
115             one_lordly_high_resistance(this->o_ptr);
116         } while (one_in_(4));
117
118         this->o_ptr->to_a = 10 + randint1(5) + (ARMOUR_CLASS)m_bonus(10, this->level);
119         break;
120     case SV_RING_WARNING:
121         if (one_in_(3)) {
122             one_low_esp(this->o_ptr);
123         }
124
125         break;
126     case SV_RING_SEARCHING:
127         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(5, this->level);
128         if (this->power < 0) {
129             set_bits(this->o_ptr->ident, IDENT_BROKEN);
130             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
131             this->o_ptr->pval = 0 - (this->o_ptr->pval);
132         }
133
134         break;
135     case SV_RING_FLAMES:
136     case SV_RING_ACID:
137     case SV_RING_ICE:
138     case SV_RING_ELEC:
139         this->o_ptr->to_a = 5 + randint1(5) + (ARMOUR_CLASS)m_bonus(10, this->level);
140         break;
141     case SV_RING_WEAKNESS:
142     case SV_RING_STUPIDITY:
143         set_bits(this->o_ptr->ident, IDENT_BROKEN);
144         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
145         this->o_ptr->pval = 0 - (1 + (PARAMETER_VALUE)m_bonus(5, this->level));
146         if (this->power > 0) {
147             this->power = 0 - this->power;
148         }
149
150         break;
151     case SV_RING_WOE:
152         set_bits(this->o_ptr->ident, IDENT_BROKEN);
153         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
154         this->o_ptr->to_a = 0 - (5 + (ARMOUR_CLASS)m_bonus(10, this->level));
155         this->o_ptr->pval = 0 - (1 + (PARAMETER_VALUE)m_bonus(5, this->level));
156         if (this->power > 0) {
157             this->power = 0 - this->power;
158         }
159
160         break;
161     case SV_RING_DAMAGE:
162         this->o_ptr->to_d = 1 + randint1(5) + (HIT_POINT)m_bonus(16, this->level);
163         if (this->power < 0) {
164             set_bits(this->o_ptr->ident, IDENT_BROKEN);
165             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
166             this->o_ptr->to_d = 0 - this->o_ptr->to_d;
167         }
168
169         break;
170     case SV_RING_ACCURACY:
171         this->o_ptr->to_h = 1 + randint1(5) + (HIT_PROB)m_bonus(16, this->level);
172         if (this->power < 0) {
173             set_bits(this->o_ptr->ident, IDENT_BROKEN);
174             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
175             this->o_ptr->to_h = 0 - this->o_ptr->to_h;
176         }
177
178         break;
179     case SV_RING_PROTECTION:
180         this->o_ptr->to_a = 5 + randint1(8) + (ARMOUR_CLASS)m_bonus(10, this->level);
181         if (this->power < 0) {
182             set_bits(this->o_ptr->ident, IDENT_BROKEN);
183             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
184             this->o_ptr->to_a = 0 - this->o_ptr->to_a;
185         }
186
187         break;
188     case SV_RING_SLAYING:
189         this->o_ptr->to_d = randint1(5) + (HIT_POINT)m_bonus(12, this->level);
190         this->o_ptr->to_h = randint1(5) + (HIT_PROB)m_bonus(12, this->level);
191
192         if (this->power < 0) {
193             set_bits(this->o_ptr->ident, IDENT_BROKEN);
194             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
195             this->o_ptr->to_h = 0 - this->o_ptr->to_h;
196             this->o_ptr->to_d = 0 - this->o_ptr->to_d;
197         }
198
199         break;
200     case SV_RING_MUSCLE:
201     case SV_RING_LAW:
202         this->o_ptr->pval = 1 + (PARAMETER_VALUE)m_bonus(3, this->level);
203         if (one_in_(4)) {
204             this->o_ptr->pval++;
205         }
206
207         if (this->power < 0) {
208             set_bits(this->o_ptr->ident, IDENT_BROKEN);
209             this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
210             this->o_ptr->pval = 0 - this->o_ptr->pval;
211         }
212
213         break;
214     case SV_RING_AGGRAVATION:
215         set_bits(this->o_ptr->ident, IDENT_BROKEN);
216         this->o_ptr->curse_flags.set(CurseTraitType::CURSED);
217         if (this->power > 0) {
218             this->power = 0 - this->power;
219         }
220
221         break;
222     default:
223         break;
224     }
225 }
226
227 void RingEnchanter::give_ego_index()
228 {
229     while (!this->o_ptr->name2) {
230         int tmp = m_bonus(10, this->level);
231         auto *k_ptr = &k_info[this->o_ptr->k_idx];
232         switch (randint1(28)) {
233         case 1:
234         case 2:
235             this->o_ptr->name2 = EGO_RING_THROW;
236             break;
237         case 3:
238         case 4:
239             if (k_ptr->flags.has(TR_REGEN)) {
240                 break;
241             }
242
243             this->o_ptr->name2 = EGO_RING_REGEN;
244             break;
245         case 5:
246         case 6:
247             if (k_ptr->flags.has(TR_LITE_1)) {
248                 break;
249             }
250
251             this->o_ptr->name2 = EGO_RING_LITE;
252             break;
253         case 7:
254         case 8:
255             if (k_ptr->flags.has(TR_TELEPORT)) {
256                 break;
257             }
258
259             this->o_ptr->name2 = EGO_RING_TELEPORT;
260             break;
261         case 9:
262         case 10:
263             if (this->o_ptr->to_h) {
264                 break;
265             }
266
267             this->o_ptr->name2 = EGO_RING_TO_H;
268             break;
269         case 11:
270         case 12:
271             if (this->o_ptr->to_d) {
272                 break;
273             }
274
275             this->o_ptr->name2 = EGO_RING_TO_D;
276             break;
277         case 13:
278             if ((this->o_ptr->to_h) || (this->o_ptr->to_d)) {
279                 break;
280             }
281
282             this->o_ptr->name2 = EGO_RING_SLAY;
283             break;
284         case 14:
285             if ((k_ptr->flags.has(TR_STR)) || this->o_ptr->to_h || this->o_ptr->to_d) {
286                 break;
287             }
288
289             this->o_ptr->name2 = EGO_RING_WIZARD;
290             break;
291         case 15:
292             if (k_ptr->flags.has(TR_ACTIVATE)) {
293                 break;
294             }
295
296             this->o_ptr->name2 = EGO_RING_HERO;
297             break;
298         case 16:
299             if (k_ptr->flags.has(TR_ACTIVATE)) {
300                 break;
301             }
302
303             if (tmp > 8) {
304                 this->o_ptr->name2 = EGO_RING_MANA_BALL;
305                 break;
306             }
307
308             if (tmp > 4) {
309                 this->o_ptr->name2 = EGO_RING_MANA_BOLT;
310                 break;
311             }
312
313             this->o_ptr->name2 = EGO_RING_MAGIC_MIS;
314             break;
315         case 17:
316             if (k_ptr->flags.has(TR_ACTIVATE)) {
317                 break;
318             }
319
320             if (k_ptr->flags.has_not(TR_RES_FIRE) && (k_ptr->flags.has(TR_RES_COLD) || k_ptr->flags.has(TR_RES_ELEC) || k_ptr->flags.has(TR_RES_ACID))) {
321                 break;
322             }
323
324             if (tmp > 7) {
325                 this->o_ptr->name2 = EGO_RING_DRAGON_F;
326                 break;
327             }
328
329             if (tmp > 3) {
330                 this->o_ptr->name2 = EGO_RING_FIRE_BALL;
331                 break;
332             }
333
334             this->o_ptr->name2 = EGO_RING_FIRE_BOLT;
335             break;
336         case 18:
337             if (k_ptr->flags.has(TR_ACTIVATE)) {
338                 break;
339             }
340
341             if (k_ptr->flags.has_not(TR_RES_COLD) && (k_ptr->flags.has(TR_RES_FIRE) || k_ptr->flags.has(TR_RES_ELEC) || k_ptr->flags.has(TR_RES_ACID))) {
342                 break;
343             }
344
345             if (tmp > 7) {
346                 this->o_ptr->name2 = EGO_RING_DRAGON_C;
347                 break;
348             }
349
350             if (tmp > 3) {
351                 this->o_ptr->name2 = EGO_RING_COLD_BALL;
352                 break;
353             }
354
355             this->o_ptr->name2 = EGO_RING_COLD_BOLT;
356             break;
357         case 19:
358             if (k_ptr->flags.has(TR_ACTIVATE)) {
359                 break;
360             }
361
362             if (k_ptr->flags.has_not(TR_RES_ELEC) && (k_ptr->flags.has(TR_RES_COLD) || k_ptr->flags.has(TR_RES_FIRE) || k_ptr->flags.has(TR_RES_ACID))) {
363                 break;
364             }
365
366             if (tmp > 4) {
367                 this->o_ptr->name2 = EGO_RING_ELEC_BALL;
368                 break;
369             }
370
371             this->o_ptr->name2 = EGO_RING_ELEC_BOLT;
372             break;
373         case 20:
374             if (k_ptr->flags.has(TR_ACTIVATE)) {
375                 break;
376             }
377
378             if (k_ptr->flags.has_not(TR_RES_ACID) && (k_ptr->flags.has(TR_RES_COLD) || k_ptr->flags.has(TR_RES_ELEC) || k_ptr->flags.has(TR_RES_FIRE))) {
379                 break;
380             }
381
382             if (tmp > 4) {
383                 this->o_ptr->name2 = EGO_RING_ACID_BALL;
384                 break;
385             }
386
387             this->o_ptr->name2 = EGO_RING_ACID_BOLT;
388             break;
389         case 21:
390         case 22:
391         case 23:
392         case 24:
393         case 25:
394         case 26:
395             give_high_ego_index();
396             break;
397         }
398     }
399 }
400
401 void RingEnchanter::give_high_ego_index()
402 {
403     switch (this->o_ptr->sval) {
404     case SV_RING_SPEED:
405         if (!one_in_(3)) {
406             break;
407         }
408
409         this->o_ptr->name2 = EGO_RING_D_SPEED;
410         break;
411     case SV_RING_DAMAGE:
412     case SV_RING_ACCURACY:
413     case SV_RING_SLAYING:
414         if (one_in_(2)) {
415             break;
416         }
417
418         if (one_in_(2)) {
419             this->o_ptr->name2 = EGO_RING_HERO;
420             break;
421         }
422
423         this->o_ptr->name2 = EGO_RING_BERSERKER;
424         this->o_ptr->to_h -= 2 + randint1(4);
425         this->o_ptr->to_d += 2 + randint1(4);
426         break;
427     case SV_RING_PROTECTION:
428         this->o_ptr->name2 = EGO_RING_SUPER_AC;
429         this->o_ptr->to_a += 7 + m_bonus(5, this->level);
430         break;
431     case SV_RING_RES_FEAR:
432         this->o_ptr->name2 = EGO_RING_HERO;
433         break;
434     case SV_RING_SHOTS:
435         if (one_in_(2)) {
436             break;
437         }
438
439         this->o_ptr->name2 = EGO_RING_HUNTER;
440         break;
441     case SV_RING_SEARCHING:
442         this->o_ptr->name2 = EGO_RING_STEALTH;
443         break;
444     case SV_RING_TELEPORTATION:
445         this->o_ptr->name2 = EGO_RING_TELE_AWAY;
446         break;
447     case SV_RING_RES_BLINDNESS:
448         this->o_ptr->name2 = one_in_(2) ? EGO_RING_RES_LITE : EGO_RING_RES_DARK;
449         break;
450     case SV_RING_LORDLY:
451         if (!one_in_(20)) {
452             break;
453         }
454
455         one_lordly_high_resistance(this->o_ptr);
456         one_lordly_high_resistance(this->o_ptr);
457         this->o_ptr->name2 = EGO_RING_TRUE;
458         break;
459     case SV_RING_FLAMES:
460         if (one_in_(2)) {
461             break;
462         }
463
464         this->o_ptr->name2 = EGO_RING_DRAGON_F;
465         break;
466     case SV_RING_ICE:
467         if (one_in_(2)) {
468             break;
469         }
470
471         this->o_ptr->name2 = EGO_RING_DRAGON_C;
472         break;
473     case SV_RING_WARNING:
474         if (one_in_(2)) {
475             break;
476         }
477
478         this->o_ptr->name2 = EGO_RING_M_DETECT;
479         break;
480     default:
481         break;
482     }
483 }
484
485 void RingEnchanter::give_cursed()
486 {
487     if (this->o_ptr->to_h > 0) {
488         this->o_ptr->to_h = 0 - this->o_ptr->to_h;
489     }
490
491     if (this->o_ptr->to_d > 0) {
492         this->o_ptr->to_d = 0 - this->o_ptr->to_d;
493     }
494
495     if (this->o_ptr->to_a > 0) {
496         this->o_ptr->to_a = 0 - this->o_ptr->to_a;
497     }
498
499     if (this->o_ptr->pval > 0) {
500         this->o_ptr->pval = 0 - this->o_ptr->pval;
501     }
502
503     while (!this->o_ptr->name2) {
504         auto *k_ptr = &k_info[this->o_ptr->k_idx];
505         switch (randint1(5)) {
506         case 1:
507             if (k_ptr->flags.has(TR_DRAIN_EXP))
508                 break;
509             this->o_ptr->name2 = EGO_RING_DRAIN_EXP;
510             break;
511         case 2:
512             this->o_ptr->name2 = EGO_RING_NO_MELEE;
513             break;
514         case 3:
515             if (k_ptr->flags.has(TR_AGGRAVATE))
516                 break;
517             this->o_ptr->name2 = EGO_RING_AGGRAVATE;
518             break;
519         case 4:
520             if (k_ptr->flags.has(TR_TY_CURSE))
521                 break;
522             this->o_ptr->name2 = EGO_RING_TY_CURSE;
523             break;
524         case 5:
525             this->o_ptr->name2 = EGO_RING_ALBINO;
526             break;
527         }
528     }
529
530     set_bits(this->o_ptr->ident, IDENT_BROKEN);
531     this->o_ptr->curse_flags.set({ CurseTraitType::CURSED, CurseTraitType::HEAVY_CURSE });
532 }