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"
12 * @brief 上質以上のオブジェクトに与えるための各種ボーナスを正規乱数も加えて算出する。
13 * Help determine an "enchantment bonus" for an object.
15 * @param level ボーナス値に加味する基準生成階
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
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
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
30 * It is always possible (albeit unlikely) to get the "full" enchantment.\n
32 * A sample distribution of values from "m_bonus(10, N)" is shown below:\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
54 int m_bonus(int max, DEPTH level)
56 int bonus, stand, extra, value;
58 /* Paranoia -- enforce maximal "level" */
59 if (level > MAX_DEPTH - 1) {
60 level = MAX_DEPTH - 1;
63 /* The "bonus" moves towards the max */
64 bonus = ((max * level) / MAX_DEPTH);
66 /* Hack -- determine fraction of error */
67 extra = ((max * level) % MAX_DEPTH);
69 /* Hack -- simulate floating point computations */
70 if (randint0(MAX_DEPTH) < extra) {
74 /* The "stand" is equal to one quarter of the max */
77 /* Hack -- determine fraction of error */
80 /* Hack -- simulate floating point computations */
81 if (randint0(4) < extra) {
85 /* Choose an "interesting" value */
86 value = randnor(bonus, stand);
88 /* Enforce the minimum value */
93 /* Enforce the maximum value */
101 * @brief 対象のオブジェクトにランダムな能力維持を一つ付加する。/ Choose one random sustain
103 * @param o_ptr 対象のオブジェクト構造体ポインタ
105 void one_sustain(ItemEntity *o_ptr)
107 switch (randint0(A_MAX)) {
109 o_ptr->art_flags.set(TR_SUST_STR);
112 o_ptr->art_flags.set(TR_SUST_INT);
115 o_ptr->art_flags.set(TR_SUST_WIS);
118 o_ptr->art_flags.set(TR_SUST_DEX);
121 o_ptr->art_flags.set(TR_SUST_CON);
124 o_ptr->art_flags.set(TR_SUST_CHR);
130 * @brief オブジェクトにランダムな強いESPを与える
131 * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
132 * @return TR_ESP_NONLIVINGがついたならばTRUE
134 bool add_esp_strong(ItemEntity *o_ptr)
138 switch (randint1(3)) {
140 o_ptr->art_flags.set(TR_ESP_EVIL);
143 o_ptr->art_flags.set(TR_TELEPATHY);
146 o_ptr->art_flags.set(TR_ESP_NONLIVING);
155 * @brief オブジェクトにランダムな弱いESPを与える
156 * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
157 * @param extra TRUEならばESPの最大付与数が増える(TRUE -> 3+1d6 / FALSE -> 1d3)
159 void add_esp_weak(ItemEntity *o_ptr, bool extra)
162 tr_type weak_esp_list[] = {
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));
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);
181 o_ptr->art_flags.set(weak_esp_list[choice]);
182 weak_esp_list[choice] = weak_esp_list[i];
187 * @brief 高級なテレパシー群を付ける
188 * @param o_ptr 対象のオブジェクト構造体ポインタ
191 * ESPまたは邪ESPは1d3の種族ESPを得る。
192 * 無ESPは3+1d6の種族ESPを得る。
194 void add_high_telepathy(ItemEntity *o_ptr)
196 if (add_esp_strong(o_ptr)) {
197 add_esp_weak(o_ptr, true);
199 add_esp_weak(o_ptr, false);
205 * @param o_ptr 対象のオブジェクト構造体ポインタ
208 * ESP、邪ESP、無ESPまたは1d3の種族ESP。
210 void add_low_telepathy(ItemEntity *o_ptr)
213 add_esp_strong(o_ptr);
215 add_esp_weak(o_ptr, false);
220 * @brief 対象のオブジェクトに元素耐性を一つ付加する。/ Choose one random element resistance
221 * @details 候補は火炎、冷気、電撃、酸のいずれかであり、重複の抑止はない。
222 * @param o_ptr 対象のオブジェクト構造体ポインタ
224 void one_ele_resistance(ItemEntity *o_ptr)
226 switch (randint0(4)) {
228 o_ptr->art_flags.set(TR_RES_ACID);
231 o_ptr->art_flags.set(TR_RES_ELEC);
234 o_ptr->art_flags.set(TR_RES_COLD);
237 o_ptr->art_flags.set(TR_RES_FIRE);
243 * @brief 対象のオブジェクトにドラゴン装備向け元素耐性を一つ付加する。/ Choose one random element or poison resistance
244 * @details 候補は1/7の確率で毒、6/7の確率で火炎、冷気、電撃、酸のいずれか(one_ele_resistance()のコール)であり、重複の抑止はない。
245 * @param o_ptr 対象のオブジェクト構造体ポインタ
247 void one_dragon_ele_resistance(ItemEntity *o_ptr)
250 o_ptr->art_flags.set(TR_RES_POIS);
252 one_ele_resistance(o_ptr);
257 * @brief 対象のオブジェクトにランダムな上位耐性を一つ付加する。/ Choose one random high resistance
258 * @details 重複の抑止はない。候補は毒、閃光、暗黒、破片、盲目、混乱、地獄、因果混乱、カオス、劣化、恐怖、時間逆転、水、呪力のいずれか。
259 * @param o_ptr 対象のオブジェクト構造体ポインタ
261 void one_high_resistance(ItemEntity *o_ptr)
263 switch (randint0(15)) {
265 o_ptr->art_flags.set(TR_RES_POIS);
268 o_ptr->art_flags.set(TR_RES_LITE);
271 o_ptr->art_flags.set(TR_RES_DARK);
274 o_ptr->art_flags.set(TR_RES_SHARDS);
277 o_ptr->art_flags.set(TR_RES_BLIND);
280 o_ptr->art_flags.set(TR_RES_CONF);
283 o_ptr->art_flags.set(TR_RES_SOUND);
286 o_ptr->art_flags.set(TR_RES_NETHER);
289 o_ptr->art_flags.set(TR_RES_NEXUS);
292 o_ptr->art_flags.set(TR_RES_CHAOS);
295 o_ptr->art_flags.set(TR_RES_DISEN);
298 o_ptr->art_flags.set(TR_RES_FEAR);
301 o_ptr->art_flags.set(TR_RES_TIME);
304 o_ptr->art_flags.set(TR_RES_WATER);
307 o_ptr->art_flags.set(TR_RES_CURSE);
313 * @brief ドラゴン装備にランダムな耐性を与える
314 * @param o_ptr 強化を与えたいオブジェクトの構造体参照ポインタ
316 void dragon_resist(ItemEntity *o_ptr)
320 one_dragon_ele_resistance(o_ptr);
322 one_high_resistance(o_ptr);
324 } while (one_in_(2));
328 * @brief 対象のオブジェクトに耐性を一つ付加する。/ Choose one random resistance
329 * @details 1/3で元素耐性(one_ele_resistance())、2/3で上位耐性(one_high_resistance)
331 * @param o_ptr 対象のオブジェクト構造体ポインタ
333 void one_resistance(ItemEntity *o_ptr)
336 one_ele_resistance(o_ptr);
338 one_high_resistance(o_ptr);
343 * @brief 対象のオブジェクトに能力を一つ付加する。/ Choose one random ability
344 * @details 候補は浮遊、永久光源+1、透明視、警告、遅消化、急回復、麻痺知らず、経験値維持のいずれか。
346 * @param o_ptr 対象のオブジェクト構造体ポインタ
348 void one_ability(ItemEntity *o_ptr)
350 switch (randint0(10)) {
352 o_ptr->art_flags.set(TR_LEVITATION);
355 o_ptr->art_flags.set(TR_LITE_1);
358 o_ptr->art_flags.set(TR_SEE_INVIS);
361 o_ptr->art_flags.set(TR_WARNING);
364 o_ptr->art_flags.set(TR_SLOW_DIGEST);
367 o_ptr->art_flags.set(TR_REGEN);
370 o_ptr->art_flags.set(TR_FREE_ACT);
373 o_ptr->art_flags.set(TR_HOLD_EXP);
383 * @brief 対象のオブジェクトに弱いESPを一つ付加する。/ Choose one lower rank esp
384 * @details 候補は動物、アンデッド、悪魔、オーク、トロル、巨人、
385 * ドラゴン、人間、善良、ユニークESPのいずれかであり、重複の抑止はない。
386 * @param o_ptr 対象のオブジェクト構造体ポインタ
388 void one_low_esp(ItemEntity *o_ptr)
390 switch (randint1(10)) {
392 o_ptr->art_flags.set(TR_ESP_ANIMAL);
395 o_ptr->art_flags.set(TR_ESP_UNDEAD);
398 o_ptr->art_flags.set(TR_ESP_DEMON);
401 o_ptr->art_flags.set(TR_ESP_ORC);
404 o_ptr->art_flags.set(TR_ESP_TROLL);
407 o_ptr->art_flags.set(TR_ESP_GIANT);
410 o_ptr->art_flags.set(TR_ESP_DRAGON);
413 o_ptr->art_flags.set(TR_ESP_HUMAN);
416 o_ptr->art_flags.set(TR_ESP_GOOD);
419 o_ptr->art_flags.set(TR_ESP_UNIQUE);
425 * @brief 対象のオブジェクトに発動を一つ付加する。/ Choose one random activation
426 * @details 候補多数。ランダムアーティファクトのバイアスには一切依存せず、
427 * whileループによる構造で能力的に強力なものほど確率を落としている。
428 * @param o_ptr 対象のオブジェクト構造体ポインタ
430 void one_activation(ItemEntity *o_ptr)
432 RandomArtActType type = RandomArtActType::NONE;
433 PERCENTAGE chance = 0;
434 while (randint1(100) >= chance) {
435 type = i2enum<RandomArtActType>(randint1(enum2i(RandomArtActType::MAX) - 1));
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:
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:
470 case RandomArtActType::TERROR:
471 case RandomArtActType::PROT_EVIL:
472 case RandomArtActType::ID_PLAIN:
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:
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:
490 case RandomArtActType::SUMMON_ANIMAL:
491 case RandomArtActType::ANIM_DEAD:
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:
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:
519 case RandomArtActType::CURE_1000:
520 case RandomArtActType::XTRA_SPEED:
521 case RandomArtActType::DETECT_XTRA:
522 case RandomArtActType::DIM_DOOR:
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:
538 o_ptr->activation_id = type;
539 o_ptr->art_flags.set(TR_ACTIVATE);
544 * @brief 対象のオブジェクトに王者の指輪向けの上位耐性を一つ付加する。/ Choose one random high resistance
545 * @details 候補は閃光、暗黒、破片、盲目、混乱、地獄、因果混乱、カオス、恐怖、時間逆転、水、呪力であり
546 * 王者の指輪にあらかじめついている耐性をone_high_resistance()から除外したものである。
547 * ランダム付加そのものに重複の抑止はない。
548 * @param o_ptr 対象のオブジェクト構造体ポインタ
550 void one_lordly_high_resistance(ItemEntity *o_ptr)
552 switch (randint0(13)) {
554 o_ptr->art_flags.set(TR_RES_LITE);
557 o_ptr->art_flags.set(TR_RES_DARK);
560 o_ptr->art_flags.set(TR_RES_SHARDS);
563 o_ptr->art_flags.set(TR_RES_BLIND);
566 o_ptr->art_flags.set(TR_RES_CONF);
569 o_ptr->art_flags.set(TR_RES_SOUND);
572 o_ptr->art_flags.set(TR_RES_NETHER);
575 o_ptr->art_flags.set(TR_RES_NEXUS);
578 o_ptr->art_flags.set(TR_RES_CHAOS);
581 o_ptr->art_flags.set(TR_RES_FEAR);
584 o_ptr->art_flags.set(TR_RES_TIME);
587 o_ptr->art_flags.set(TR_RES_WATER);
590 o_ptr->art_flags.set(TR_RES_CURSE);
596 * @brief オブジェクトの重量を軽くする
597 * @param o_ptr オブジェクト情報への参照ポインタ
599 void make_weight_ligten(ItemEntity *o_ptr)
601 o_ptr->weight = (2 * o_ptr->get_baseitem().weight / 3);
605 * @brief オブジェクトの重量を重くする
606 * @param o_ptr オブジェクト情報への参照ポインタ
608 void make_weight_heavy(ItemEntity *o_ptr)
610 o_ptr->weight = (4 * o_ptr->get_baseitem().weight / 3);
614 * @brief オブジェクトのベースACを増やす
615 * @param o_ptr オブジェクト情報への参照ポインタ
619 void add_xtra_ac(ItemEntity *o_ptr)
621 o_ptr->ac += std::max<short>(5, o_ptr->ac / 4);