OSDN Git Service

Merge branch 'master' of https://github.com/hengband/hengband
[hengbandforosx/hengbandosx.git] / src / object-enchant / object-curse.cpp
1 #include "object-enchant/object-curse.h"
2 #include "flavor/flavor-describer.h"
3 #include "flavor/object-flavor-types.h"
4 #include "inventory/inventory-slot-types.h"
5 #include "object-enchant/item-feeling.h"
6 #include "object-enchant/tr-types.h"
7 #include "object-enchant/trc-types.h"
8 #include "object-hook/hook-armor.h"
9 #include "object-hook/hook-weapon.h"
10 #include "object/object-flags.h"
11 #include "system/item-entity.h"
12 #include "system/player-type-definition.h"
13 #include "system/redrawing-flags-updater.h"
14 #include "util/bit-flags-calculator.h"
15 #include "util/enum-converter.h"
16 #include "view/display-messages.h"
17
18 namespace {
19 const EnumClassFlagGroup<CurseTraitType> TRC_SPECIAL_MASK({ CurseTraitType::TY_CURSE, CurseTraitType::AGGRAVATE });
20 const EnumClassFlagGroup<CurseTraitType> TRC_HEAVY_MASK({ CurseTraitType::TY_CURSE, CurseTraitType::AGGRAVATE, CurseTraitType::DRAIN_EXP, CurseTraitType::ADD_H_CURSE, CurseTraitType::CALL_DEMON, CurseTraitType::CALL_DRAGON, CurseTraitType::CALL_UNDEAD, CurseTraitType::TELEPORT });
21 }
22
23 /*!
24  * @brief アイテムに付加される可能性のある呪いを指定する。
25  * @param power 呪いの段階
26  * @param o_ptr 呪いをかけられる装備オブジェクトの構造体参照ポインタ
27  * @return 与える呪いのID
28  */
29 CurseTraitType get_curse(int power, ItemEntity *o_ptr)
30 {
31     CurseTraitType new_curse;
32
33     while (true) {
34         new_curse = i2enum<CurseTraitType>(rand_range(enum2i(CurseTraitType::TY_CURSE), enum2i(CurseTraitType::MAX) - 1));
35         if (power == 2) {
36             if (TRC_HEAVY_MASK.has_not(new_curse)) {
37                 continue;
38             }
39         } else if (power == 1) {
40             if (TRC_SPECIAL_MASK.has(new_curse)) {
41                 continue;
42             }
43         } else if (power == 0) {
44             if (TRC_HEAVY_MASK.has(new_curse)) {
45                 continue;
46             }
47         }
48
49         if (new_curse == CurseTraitType::LOW_MELEE && !o_ptr->is_weapon()) {
50             continue;
51         }
52         if (new_curse == CurseTraitType::LOW_AC && !o_ptr->is_protector()) {
53             continue;
54         }
55         break;
56     }
57
58     return new_curse;
59 }
60
61 /*!
62  * @brief 装備への呪い付加判定と付加処理
63  * @param player_ptr プレイヤーへの参照ポインタ
64  * @param chance 呪いの基本確率
65  * @param heavy_chance さらに重い呪いとなる確率
66  */
67 void curse_equipment(PlayerType *player_ptr, PERCENTAGE chance, PERCENTAGE heavy_chance)
68 {
69     if (randint1(100) > chance) {
70         return;
71     }
72
73     auto *o_ptr = &player_ptr->inventory_list[INVEN_MAIN_HAND + randint0(12)];
74     if (!o_ptr->is_valid()) {
75         return;
76     }
77
78     auto oflags = object_flags(o_ptr);
79     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
80
81     /* Extra, biased saving throw for blessed items */
82     if (oflags.has(TR_BLESSED)) {
83 #ifdef JP
84         msg_format("祝福された%sは呪いを跳ね返した!", item_name.data());
85 #else
86         msg_format("Your blessed %s resist%s cursing!", item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
87 #endif
88         /* Hmmm -- can we wear multiple items? If not, this is unnecessary */
89         return;
90     }
91
92     bool changed = false;
93     int curse_power = 0;
94     if ((randint1(100) <= heavy_chance) && (o_ptr->is_fixed_or_random_artifact() || o_ptr->is_ego())) {
95         if (o_ptr->curse_flags.has_not(CurseTraitType::HEAVY_CURSE)) {
96             changed = true;
97         }
98         o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
99         o_ptr->curse_flags.set(CurseTraitType::CURSED);
100         curse_power++;
101     } else {
102         if (!o_ptr->is_cursed()) {
103             changed = true;
104         }
105         o_ptr->curse_flags.set(CurseTraitType::CURSED);
106     }
107
108     if (heavy_chance >= 50) {
109         curse_power++;
110     }
111
112     auto new_curse = get_curse(curse_power, o_ptr);
113     if (o_ptr->curse_flags.has_not(new_curse)) {
114         changed = true;
115         o_ptr->curse_flags.set(new_curse);
116     }
117
118     if (changed) {
119         msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding %s..."), item_name.data());
120         o_ptr->feeling = FEEL_NONE;
121     }
122
123     RedrawingFlagsUpdater::get_instance().set_flag(StatusRecalculatingFlag::BONUS);
124 }