OSDN Git Service

Merge pull request #3297 from Hourier/Move-Update-Flags-3
[hengbandforosx/hengbandosx.git] / src / object-enchant / object-boost.cpp
1 #include "object-enchant/object-boost.h"
2 #include "artifact/random-art-effects.h"
3 #include "object-enchant/tr-types.h"
4 #include "player-ability/player-ability-types.h"
5 #include "system/baseitem-info.h"
6 #include "system/floor-type-definition.h"
7 #include "system/item-entity.h"
8 #include "util/bit-flags-calculator.h"
9 #include "util/enum-converter.h"
10
11 /*!
12  * @brief 上質以上のオブジェクトに与えるための各種ボーナスを正規乱数も加えて算出する。
13  * Help determine an "enchantment bonus" for an object.
14  * @param max ボーナス値の限度
15  * @param level ボーナス値に加味する基準生成階
16  * @return 算出されたボーナス値
17  * @details
18  * To avoid floating point but still provide a smooth distribution of bonuses,\n
19  * we simply round the results of ENERGY_DIVISION in such a way as to "average" the\n
20  * correct floating point value.\n
21  *\n
22  * This function has been changed.  It uses "randnor()" to choose values from\n
23  * a normal distribution, whose mean moves from zero towards the max as the\n
24  * level increases, and whose standard deviation is equal to 1/4 of the max,\n
25  * and whose values are forced to lie between zero and the max, inclusive.\n
26  *\n
27  * Since the "level" rarely passes 100 before Morgoth is dead, it is very\n
28  * rare to get the "full" enchantment on an object, even a deep levels.\n
29  *\n
30  * It is always possible (albeit unlikely) to get the "full" enchantment.\n
31  *\n
32  * A sample distribution of values from "m_bonus(10, N)" is shown below:\n
33  *\n
34  *   N       0     1     2     3     4     5     6     7     8     9    10\n
35  * ---    ----  ----  ----  ----  ----  ----  ----  ----  ----  ----  ----\n
36  *   0   66.37 13.01  9.73  5.47  2.89  1.31  0.72  0.26  0.12  0.09  0.03\n
37  *   8   46.85 24.66 12.13  8.13  4.20  2.30  1.05  0.36  0.19  0.08  0.05\n
38  *  16   30.12 27.62 18.52 10.52  6.34  3.52  1.95  0.90  0.31  0.15  0.05\n
39  *  24   22.44 15.62 30.14 12.92  8.55  5.30  2.39  1.63  0.62  0.28  0.11\n
40  *  32   16.23 11.43 23.01 22.31 11.19  7.18  4.46  2.13  1.20  0.45  0.41\n
41  *  40   10.76  8.91 12.80 29.51 16.00  9.69  5.90  3.43  1.47  0.88  0.65\n
42  *  48    7.28  6.81 10.51 18.27 27.57 11.76  7.85  4.99  2.80  1.22  0.94\n
43  *  56    4.41  4.73  8.52 11.96 24.94 19.78 11.06  7.18  3.68  1.96  1.78\n
44  *  64    2.81  3.07  5.65  9.17 13.01 31.57 13.70  9.30  6.04  3.04  2.64\n
45  *  72    1.87  1.99  3.68  7.15 10.56 20.24 25.78 12.17  7.52  4.42  4.62\n
46  *  80    1.02  1.23  2.78  4.75  8.37 12.04 27.61 18.07 10.28  6.52  7.33\n
47  *  88    0.70  0.57  1.56  3.12  6.34 10.06 15.76 30.46 12.58  8.47 10.38\n
48  *  96    0.27  0.60  1.25  2.28  4.30  7.60 10.77 22.52 22.51 11.37 16.53\n
49  * 104    0.22  0.42  0.77  1.36  2.62  5.33  8.93 13.05 29.54 15.23 22.53\n
50  * 112    0.15  0.20  0.56  0.87  2.00  3.83  6.86 10.06 17.89 27.31 30.27\n
51  * 120    0.03  0.11  0.31  0.46  1.31  2.48  4.60  7.78 11.67 25.53 45.72\n
52  * 128    0.02  0.01  0.13  0.33  0.83  1.41  3.24  6.17  9.57 14.22 64.07\n
53  */
54 int m_bonus(int max, DEPTH level)
55 {
56     int bonus, stand, extra, value;
57
58     /* Paranoia -- enforce maximal "level" */
59     if (level > MAX_DEPTH - 1) {
60         level = MAX_DEPTH - 1;
61     }
62
63     /* The "bonus" moves towards the max */
64     bonus = ((max * level) / MAX_DEPTH);
65
66     /* Hack -- determine fraction of error */
67     extra = ((max * level) % MAX_DEPTH);
68
69     /* Hack -- simulate floating point computations */
70     if (randint0(MAX_DEPTH) < extra) {
71         bonus++;
72     }
73
74     /* The "stand" is equal to one quarter of the max */
75     stand = (max / 4);
76
77     /* Hack -- determine fraction of error */
78     extra = (max % 4);
79
80     /* Hack -- simulate floating point computations */
81     if (randint0(4) < extra) {
82         stand++;
83     }
84
85     /* Choose an "interesting" value */
86     value = randnor(bonus, stand);
87
88     /* Enforce the minimum value */
89     if (value < 0) {
90         return 0;
91     }
92
93     /* Enforce the maximum value */
94     if (value > max) {
95         return max;
96     }
97     return value;
98 }
99
100 /*!
101  * @brief 対象のオブジェクトにランダムな能力維持を一つ付加する。/ Choose one random sustain
102  * @details 重複の抑止はない。
103  * @param o_ptr 対象のオブジェクト構造体ポインタ
104  */
105 void one_sustain(ItemEntity *o_ptr)
106 {
107     switch (randint0(A_MAX)) {
108     case 0:
109         o_ptr->art_flags.set(TR_SUST_STR);
110         break;
111     case 1:
112         o_ptr->art_flags.set(TR_SUST_INT);
113         break;
114     case 2:
115         o_ptr->art_flags.set(TR_SUST_WIS);
116         break;
117     case 3:
118         o_ptr->art_flags.set(TR_SUST_DEX);
119         break;
120     case 4:
121         o_ptr->art_flags.set(TR_SUST_CON);
122         break;
123     case 5:
124         o_ptr->art_flags.set(TR_SUST_CHR);
125         break;
126     }
127 }
128
129 /*!
130  * @brief オブジェクトにランダムな強いESPを与える
131  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
132  * @return TR_ESP_NONLIVINGがついたならばTRUE
133  */
134 bool add_esp_strong(ItemEntity *o_ptr)
135 {
136     bool nonliv = false;
137
138     switch (randint1(3)) {
139     case 1:
140         o_ptr->art_flags.set(TR_ESP_EVIL);
141         break;
142     case 2:
143         o_ptr->art_flags.set(TR_TELEPATHY);
144         break;
145     case 3:
146         o_ptr->art_flags.set(TR_ESP_NONLIVING);
147         nonliv = true;
148         break;
149     }
150
151     return nonliv;
152 }
153
154 /*!
155  * @brief オブジェクトにランダムな弱いESPを与える
156  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
157  * @param extra TRUEならばESPの最大付与数が増える(TRUE -> 3+1d6 / FALSE -> 1d3)
158  */
159 void add_esp_weak(ItemEntity *o_ptr, bool extra)
160 {
161     int i;
162     tr_type weak_esp_list[] = {
163         TR_ESP_ANIMAL,
164         TR_ESP_UNDEAD,
165         TR_ESP_DEMON,
166         TR_ESP_ORC,
167         TR_ESP_TROLL,
168         TR_ESP_GIANT,
169         TR_ESP_DRAGON,
170         TR_ESP_HUMAN,
171         TR_ESP_GOOD,
172         TR_ESP_UNIQUE,
173     };
174     const int MAX_ESP_WEAK = sizeof(weak_esp_list) / sizeof(weak_esp_list[0]);
175     const int add_count = std::min(MAX_ESP_WEAK, (extra) ? (3 + randint1(randint1(6))) : randint1(3));
176
177     /* Add unduplicated weak esp flags randomly */
178     for (i = 0; i < add_count; ++i) {
179         int choice = rand_range(i, MAX_ESP_WEAK - 1);
180
181         o_ptr->art_flags.set(weak_esp_list[choice]);
182         weak_esp_list[choice] = weak_esp_list[i];
183     }
184 }
185
186 /*!
187  * @brief 高級なテレパシー群を付ける
188  * @param o_ptr 対象のオブジェクト構造体ポインタ
189  * @details
190  * テレパシーの冠など。
191  * ESPまたは邪ESPは1d3の種族ESPを得る。
192  * 無ESPは3+1d6の種族ESPを得る。
193  */
194 void add_high_telepathy(ItemEntity *o_ptr)
195 {
196     if (add_esp_strong(o_ptr)) {
197         add_esp_weak(o_ptr, true);
198     } else {
199         add_esp_weak(o_ptr, false);
200     }
201 }
202
203 /*!
204  * @brief テレパシー群を付ける
205  * @param o_ptr 対象のオブジェクト構造体ポインタ
206  * @details
207  * 鋭敏の帽子など。
208  * ESP、邪ESP、無ESPまたは1d3の種族ESP。
209  */
210 void add_low_telepathy(ItemEntity *o_ptr)
211 {
212     if (one_in_(2)) {
213         add_esp_strong(o_ptr);
214     } else {
215         add_esp_weak(o_ptr, false);
216     }
217 }
218
219 /*!
220  * @brief 対象のオブジェクトに元素耐性を一つ付加する。/ Choose one random element resistance
221  * @details 候補は火炎、冷気、電撃、酸のいずれかであり、重複の抑止はない。
222  * @param o_ptr 対象のオブジェクト構造体ポインタ
223  */
224 void one_ele_resistance(ItemEntity *o_ptr)
225 {
226     switch (randint0(4)) {
227     case 0:
228         o_ptr->art_flags.set(TR_RES_ACID);
229         break;
230     case 1:
231         o_ptr->art_flags.set(TR_RES_ELEC);
232         break;
233     case 2:
234         o_ptr->art_flags.set(TR_RES_COLD);
235         break;
236     case 3:
237         o_ptr->art_flags.set(TR_RES_FIRE);
238         break;
239     }
240 }
241
242 /*!
243  * @brief 対象のオブジェクトにドラゴン装備向け元素耐性を一つ付加する。/ Choose one random element or poison resistance
244  * @details 候補は1/7の確率で毒、6/7の確率で火炎、冷気、電撃、酸のいずれか(one_ele_resistance()のコール)であり、重複の抑止はない。
245  * @param o_ptr 対象のオブジェクト構造体ポインタ
246  */
247 void one_dragon_ele_resistance(ItemEntity *o_ptr)
248 {
249     if (one_in_(7)) {
250         o_ptr->art_flags.set(TR_RES_POIS);
251     } else {
252         one_ele_resistance(o_ptr);
253     }
254 }
255
256 /*!
257  * @brief 対象のオブジェクトにランダムな上位耐性を一つ付加する。/ Choose one random high resistance
258  * @details 重複の抑止はない。候補は毒、閃光、暗黒、破片、盲目、混乱、地獄、因果混乱、カオス、劣化、恐怖、時間逆転、水、呪力のいずれか。
259  * @param o_ptr 対象のオブジェクト構造体ポインタ
260  */
261 void one_high_resistance(ItemEntity *o_ptr)
262 {
263     switch (randint0(15)) {
264     case 0:
265         o_ptr->art_flags.set(TR_RES_POIS);
266         break;
267     case 1:
268         o_ptr->art_flags.set(TR_RES_LITE);
269         break;
270     case 2:
271         o_ptr->art_flags.set(TR_RES_DARK);
272         break;
273     case 3:
274         o_ptr->art_flags.set(TR_RES_SHARDS);
275         break;
276     case 4:
277         o_ptr->art_flags.set(TR_RES_BLIND);
278         break;
279     case 5:
280         o_ptr->art_flags.set(TR_RES_CONF);
281         break;
282     case 6:
283         o_ptr->art_flags.set(TR_RES_SOUND);
284         break;
285     case 7:
286         o_ptr->art_flags.set(TR_RES_NETHER);
287         break;
288     case 8:
289         o_ptr->art_flags.set(TR_RES_NEXUS);
290         break;
291     case 9:
292         o_ptr->art_flags.set(TR_RES_CHAOS);
293         break;
294     case 10:
295         o_ptr->art_flags.set(TR_RES_DISEN);
296         break;
297     case 11:
298         o_ptr->art_flags.set(TR_RES_FEAR);
299         break;
300     case 12:
301         o_ptr->art_flags.set(TR_RES_TIME);
302         break;
303     case 13:
304         o_ptr->art_flags.set(TR_RES_WATER);
305         break;
306     case 14:
307         o_ptr->art_flags.set(TR_RES_CURSE);
308         break;
309     }
310 }
311
312 /*!
313  * @brief ドラゴン装備にランダムな耐性を与える
314  * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
315  */
316 void dragon_resist(ItemEntity *o_ptr)
317 {
318     do {
319         if (one_in_(4)) {
320             one_dragon_ele_resistance(o_ptr);
321         } else {
322             one_high_resistance(o_ptr);
323         }
324     } while (one_in_(2));
325 }
326
327 /*!
328  * @brief 対象のオブジェクトに耐性を一つ付加する。/ Choose one random resistance
329  * @details 1/3で元素耐性(one_ele_resistance())、2/3で上位耐性(one_high_resistance)
330  * をコールする。重複の抑止はない。
331  * @param o_ptr 対象のオブジェクト構造体ポインタ
332  */
333 void one_resistance(ItemEntity *o_ptr)
334 {
335     if (one_in_(3)) {
336         one_ele_resistance(o_ptr);
337     } else {
338         one_high_resistance(o_ptr);
339     }
340 }
341
342 /*!
343  * @brief 対象のオブジェクトに能力を一つ付加する。/ Choose one random ability
344  * @details 候補は浮遊、永久光源+1、透明視、警告、遅消化、急回復、麻痺知らず、経験値維持のいずれか。
345  * 重複の抑止はない。
346  * @param o_ptr 対象のオブジェクト構造体ポインタ
347  */
348 void one_ability(ItemEntity *o_ptr)
349 {
350     switch (randint0(10)) {
351     case 0:
352         o_ptr->art_flags.set(TR_LEVITATION);
353         break;
354     case 1:
355         o_ptr->art_flags.set(TR_LITE_1);
356         break;
357     case 2:
358         o_ptr->art_flags.set(TR_SEE_INVIS);
359         break;
360     case 3:
361         o_ptr->art_flags.set(TR_WARNING);
362         break;
363     case 4:
364         o_ptr->art_flags.set(TR_SLOW_DIGEST);
365         break;
366     case 5:
367         o_ptr->art_flags.set(TR_REGEN);
368         break;
369     case 6:
370         o_ptr->art_flags.set(TR_FREE_ACT);
371         break;
372     case 7:
373         o_ptr->art_flags.set(TR_HOLD_EXP);
374         break;
375     case 8:
376     case 9:
377         one_low_esp(o_ptr);
378         break;
379     }
380 }
381
382 /*!
383  * @brief 対象のオブジェクトに弱いESPを一つ付加する。/ Choose one lower rank esp
384  * @details 候補は動物、アンデッド、悪魔、オーク、トロル、巨人、
385  * ドラゴン、人間、善良、ユニークESPのいずれかであり、重複の抑止はない。
386  * @param o_ptr 対象のオブジェクト構造体ポインタ
387  */
388 void one_low_esp(ItemEntity *o_ptr)
389 {
390     switch (randint1(10)) {
391     case 1:
392         o_ptr->art_flags.set(TR_ESP_ANIMAL);
393         break;
394     case 2:
395         o_ptr->art_flags.set(TR_ESP_UNDEAD);
396         break;
397     case 3:
398         o_ptr->art_flags.set(TR_ESP_DEMON);
399         break;
400     case 4:
401         o_ptr->art_flags.set(TR_ESP_ORC);
402         break;
403     case 5:
404         o_ptr->art_flags.set(TR_ESP_TROLL);
405         break;
406     case 6:
407         o_ptr->art_flags.set(TR_ESP_GIANT);
408         break;
409     case 7:
410         o_ptr->art_flags.set(TR_ESP_DRAGON);
411         break;
412     case 8:
413         o_ptr->art_flags.set(TR_ESP_HUMAN);
414         break;
415     case 9:
416         o_ptr->art_flags.set(TR_ESP_GOOD);
417         break;
418     case 10:
419         o_ptr->art_flags.set(TR_ESP_UNIQUE);
420         break;
421     }
422 }
423
424 /*!
425  * @brief 対象のオブジェクトに発動を一つ付加する。/ Choose one random activation
426  * @details 候補多数。ランダムアーティファクトのバイアスには一切依存せず、
427  * whileループによる構造で能力的に強力なものほど確率を落としている。
428  * @param o_ptr 対象のオブジェクト構造体ポインタ
429  */
430 void one_activation(ItemEntity *o_ptr)
431 {
432     RandomArtActType type = RandomArtActType::NONE;
433     PERCENTAGE chance = 0;
434     while (randint1(100) >= chance) {
435         type = i2enum<RandomArtActType>(randint1(enum2i(RandomArtActType::MAX) - 1));
436         switch (type) {
437         case RandomArtActType::SUNLIGHT:
438         case RandomArtActType::BO_MISS_1:
439         case RandomArtActType::BA_POIS_1:
440         case RandomArtActType::BO_ELEC_1:
441         case RandomArtActType::BO_ACID_1:
442         case RandomArtActType::BO_COLD_1:
443         case RandomArtActType::BO_FIRE_1:
444         case RandomArtActType::CONFUSE:
445         case RandomArtActType::SLEEP:
446         case RandomArtActType::QUAKE:
447         case RandomArtActType::CURE_LW:
448         case RandomArtActType::CURE_MW:
449         case RandomArtActType::CURE_POISON:
450         case RandomArtActType::BERSERK:
451         case RandomArtActType::LIGHT:
452         case RandomArtActType::MAP_LIGHT:
453         case RandomArtActType::DEST_DOOR:
454         case RandomArtActType::STONE_MUD:
455         case RandomArtActType::TELEPORT:
456             chance = 101;
457             break;
458         case RandomArtActType::BA_COLD_1:
459         case RandomArtActType::BA_FIRE_1:
460         case RandomArtActType::HYPODYNAMIA_1:
461         case RandomArtActType::TELE_AWAY:
462         case RandomArtActType::ESP:
463         case RandomArtActType::RESIST_ALL:
464         case RandomArtActType::DETECT_ALL:
465         case RandomArtActType::RECALL:
466         case RandomArtActType::SATIATE:
467         case RandomArtActType::RECHARGE:
468             chance = 85;
469             break;
470         case RandomArtActType::TERROR:
471         case RandomArtActType::PROT_EVIL:
472         case RandomArtActType::ID_PLAIN:
473             chance = 75;
474             break;
475         case RandomArtActType::HYPODYNAMIA_2:
476         case RandomArtActType::DRAIN_1:
477         case RandomArtActType::BO_MISS_2:
478         case RandomArtActType::BA_FIRE_2:
479         case RandomArtActType::REST_EXP:
480             chance = 66;
481             break;
482         case RandomArtActType::BA_FIRE_3:
483         case RandomArtActType::BA_COLD_3:
484         case RandomArtActType::BA_ELEC_3:
485         case RandomArtActType::WHIRLWIND:
486         case RandomArtActType::DRAIN_2:
487         case RandomArtActType::CHARM_ANIMAL:
488             chance = 50;
489             break;
490         case RandomArtActType::SUMMON_ANIMAL:
491         case RandomArtActType::ANIM_DEAD:
492             chance = 40;
493             break;
494         case RandomArtActType::DISP_EVIL:
495         case RandomArtActType::BA_MISS_3:
496         case RandomArtActType::DISP_GOOD:
497         case RandomArtActType::BANISH_EVIL:
498         case RandomArtActType::GENOCIDE:
499         case RandomArtActType::MASS_GENO:
500         case RandomArtActType::CHARM_UNDEAD:
501         case RandomArtActType::CHARM_OTHER:
502         case RandomArtActType::SUMMON_PHANTOM:
503         case RandomArtActType::REST_ALL:
504         case RandomArtActType::RUNE_EXPLO:
505             chance = 33;
506             break;
507         case RandomArtActType::CALL_CHAOS:
508         case RandomArtActType::ROCKET:
509         case RandomArtActType::CHARM_ANIMALS:
510         case RandomArtActType::CHARM_OTHERS:
511         case RandomArtActType::SUMMON_ELEMENTAL:
512         case RandomArtActType::CURE_700:
513         case RandomArtActType::SPEED:
514         case RandomArtActType::MID_SPEED:
515         case RandomArtActType::ID_FULL:
516         case RandomArtActType::RUNE_PROT:
517             chance = 25;
518             break;
519         case RandomArtActType::CURE_1000:
520         case RandomArtActType::XTRA_SPEED:
521         case RandomArtActType::DETECT_XTRA:
522         case RandomArtActType::DIM_DOOR:
523             chance = 10;
524             break;
525         case RandomArtActType::TREE_CREATION:
526         case RandomArtActType::SUMMON_DEMON:
527         case RandomArtActType::SUMMON_UNDEAD:
528         case RandomArtActType::WRAITH:
529         case RandomArtActType::INVULN:
530         case RandomArtActType::ALCHEMY:
531             chance = 5;
532             break;
533         default:
534             chance = 0;
535         }
536     }
537
538     o_ptr->activation_id = type;
539     o_ptr->art_flags.set(TR_ACTIVATE);
540     o_ptr->timeout = 0;
541 }
542
543 /*!
544  * @brief 対象のオブジェクトに王者の指輪向けの上位耐性を一つ付加する。/ Choose one random high resistance
545  * @details 候補は閃光、暗黒、破片、盲目、混乱、地獄、因果混乱、カオス、恐怖、時間逆転、水、呪力であり
546  * 王者の指輪にあらかじめついている耐性をone_high_resistance()から除外したものである。
547  * ランダム付加そのものに重複の抑止はない。
548  * @param o_ptr 対象のオブジェクト構造体ポインタ
549  */
550 void one_lordly_high_resistance(ItemEntity *o_ptr)
551 {
552     switch (randint0(13)) {
553     case 0:
554         o_ptr->art_flags.set(TR_RES_LITE);
555         break;
556     case 1:
557         o_ptr->art_flags.set(TR_RES_DARK);
558         break;
559     case 2:
560         o_ptr->art_flags.set(TR_RES_SHARDS);
561         break;
562     case 3:
563         o_ptr->art_flags.set(TR_RES_BLIND);
564         break;
565     case 4:
566         o_ptr->art_flags.set(TR_RES_CONF);
567         break;
568     case 5:
569         o_ptr->art_flags.set(TR_RES_SOUND);
570         break;
571     case 6:
572         o_ptr->art_flags.set(TR_RES_NETHER);
573         break;
574     case 7:
575         o_ptr->art_flags.set(TR_RES_NEXUS);
576         break;
577     case 8:
578         o_ptr->art_flags.set(TR_RES_CHAOS);
579         break;
580     case 9:
581         o_ptr->art_flags.set(TR_RES_FEAR);
582         break;
583     case 10:
584         o_ptr->art_flags.set(TR_RES_TIME);
585         break;
586     case 11:
587         o_ptr->art_flags.set(TR_RES_WATER);
588         break;
589     case 12:
590         o_ptr->art_flags.set(TR_RES_CURSE);
591         break;
592     }
593 }
594
595 /*!
596  * @brief オブジェクトの重量を軽くする
597  * @param o_ptr オブジェクト情報への参照ポインタ
598  */
599 void make_weight_ligten(ItemEntity *o_ptr)
600 {
601     o_ptr->weight = (2 * o_ptr->get_baseitem().weight / 3);
602 }
603
604 /*!
605  * @brief オブジェクトの重量を重くする
606  * @param o_ptr オブジェクト情報への参照ポインタ
607  */
608 void make_weight_heavy(ItemEntity *o_ptr)
609 {
610     o_ptr->weight = (4 * o_ptr->get_baseitem().weight / 3);
611 }
612
613 /*!
614  * @brief オブジェクトのベースACを増やす
615  * @param o_ptr オブジェクト情報への参照ポインタ
616  * @details
617  * 1/4を加算。最低+5を保証。
618  */
619 void add_xtra_ac(ItemEntity *o_ptr)
620 {
621     o_ptr->ac += std::max<short>(5, o_ptr->ac / 4);
622 }