OSDN Git Service

Merge pull request #3569 from sikabane-works/release/3.0.0.88-alpha
[hengbandforosx/hengbandosx.git] / src / spell-kind / magic-item-recharger.cpp
1 /*!
2  * @brief 魔法効果の実装/ Spell code (part 3)
3  * @date 2014/07/26
4  * @author
5  * <pre>
6  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
7  * This software may be copied and distributed for educational, research,
8  * and not for profit purposes provided that this copyright and statement
9  * are included in all such copies.  Other copyrights may also apply.
10  * </pre>
11  */
12
13 #include "spell-kind/magic-item-recharger.h"
14 #include "core/stuff-handler.h"
15 #include "flavor/flavor-describer.h"
16 #include "flavor/object-flavor-types.h"
17 #include "floor/floor-object.h"
18 #include "inventory/inventory-object.h"
19 #include "object-enchant/special-object-flags.h"
20 #include "object-hook/hook-magic.h"
21 #include "object/item-tester-hooker.h"
22 #include "object/item-use-flags.h"
23 #include "player-base/player-class.h"
24 #include "system/angband-exceptions.h"
25 #include "system/baseitem-info.h"
26 #include "system/item-entity.h"
27 #include "system/player-type-definition.h"
28 #include "view/display-messages.h"
29
30 /*!
31  * @brief 魔力充填処理 /
32  * Recharge a wand/staff/rod from the pack or on the floor.
33  * This function has been rewritten in Oangband and ZAngband.
34  * @param player_ptr プレイヤーへの参照ポインタ
35  * @param power 充填パワー
36  * @return ターン消費を要する処理まで進んだらTRUEを返す
37  *
38  * Sorcery/Arcane -- Recharge  --> recharge(plev * 4)
39  * Chaos -- Arcane Binding     --> recharge(90)
40  *
41  * Scroll of recharging        --> recharge(130)
42  * Artifact activation/Thingol --> recharge(130)
43  *
44  * It is harder to recharge high level, and highly charged wands,
45  * staffs, and rods.  The more wands in a stack, the more easily and
46  * strongly they recharge.  Staffs, however, each get fewer charges if
47  * stacked.
48  *
49  * Beware of "sliding index errors".
50  */
51 bool recharge(PlayerType *player_ptr, int power)
52 {
53     concptr q = _("どのアイテムに魔力を充填しますか? ", "Recharge which item? ");
54     concptr s = _("魔力を充填すべきアイテムがない。", "You have nothing to recharge.");
55
56     OBJECT_IDX item;
57     auto *o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(&ItemEntity::can_recharge));
58     if (o_ptr == nullptr) {
59         return false;
60     }
61
62     const auto &baseitem = o_ptr->get_baseitem();
63     const auto lev = baseitem.level;
64
65     TIME_EFFECT recharge_amount;
66     int recharge_strength;
67     auto is_recharge_successful = true;
68     const auto tval = o_ptr->bi_key.tval();
69     if (tval == ItemKindType::ROD) {
70         recharge_strength = ((power > lev / 2) ? (power - lev / 2) : 0) / 5;
71         if (one_in_(recharge_strength)) {
72             is_recharge_successful = false;
73         } else {
74             recharge_amount = (power * damroll(3, 2));
75             if (o_ptr->timeout > recharge_amount) {
76                 o_ptr->timeout -= recharge_amount;
77             } else {
78                 o_ptr->timeout = 0;
79             }
80         }
81     } else {
82         if ((tval == ItemKindType::WAND) && (o_ptr->number > 1)) {
83             recharge_strength = (100 + power - lev - (8 * o_ptr->pval / o_ptr->number)) / 15;
84         } else {
85             recharge_strength = (100 + power - lev - (8 * o_ptr->pval)) / 15;
86         }
87
88         if (recharge_strength < 0) {
89             recharge_strength = 0;
90         }
91
92         if (one_in_(recharge_strength)) {
93             is_recharge_successful = false;
94         } else {
95             recharge_amount = randint1(1 + baseitem.pval / 2);
96             if ((tval == ItemKindType::WAND) && (o_ptr->number > 1)) {
97                 recharge_amount += (randint1(recharge_amount * (o_ptr->number - 1))) / 2;
98                 if (recharge_amount < 1) {
99                     recharge_amount = 1;
100                 }
101                 if (recharge_amount > 12) {
102                     recharge_amount = 12;
103                 }
104             }
105
106             if ((tval == ItemKindType::STAFF) && (o_ptr->number > 1)) {
107                 recharge_amount /= (TIME_EFFECT)o_ptr->number;
108                 if (recharge_amount < 1) {
109                     recharge_amount = 1;
110                 }
111             }
112
113             o_ptr->pval += recharge_amount;
114             o_ptr->ident &= ~(IDENT_KNOWN);
115             o_ptr->ident &= ~(IDENT_EMPTY);
116         }
117     }
118
119     if (is_recharge_successful) {
120         return update_player();
121     }
122
123     if (o_ptr->is_fixed_artifact()) {
124         const auto item_name = describe_flavor(player_ptr, o_ptr, OD_NAME_ONLY);
125         msg_format(_("魔力が逆流した!%sは完全に魔力を失った。", "The recharging backfires - %s is completely drained!"), item_name.data());
126         if ((tval == ItemKindType::ROD) && (o_ptr->timeout < 10000)) {
127             o_ptr->timeout = (o_ptr->timeout + 100) * 2;
128         } else if (o_ptr->is_wand_staff()) {
129             o_ptr->pval = 0;
130         }
131         return update_player();
132     }
133
134     const auto item_name = describe_flavor(player_ptr, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
135     auto fail_type = 1;
136     if (PlayerClass(player_ptr).is_wizard()) {
137         /* 10% chance to blow up one rod, otherwise draining. */
138         if (tval == ItemKindType::ROD) {
139             if (one_in_(10)) {
140                 fail_type = 2;
141             } else {
142                 fail_type = 1;
143             }
144         }
145         /* 75% chance to blow up one wand, otherwise draining. */
146         else if (tval == ItemKindType::WAND) {
147             if (!one_in_(3)) {
148                 fail_type = 2;
149             } else {
150                 fail_type = 1;
151             }
152         }
153         /* 50% chance to blow up one staff, otherwise no effect. */
154         else if (tval == ItemKindType::STAFF) {
155             if (one_in_(2)) {
156                 fail_type = 2;
157             } else {
158                 fail_type = 0;
159             }
160         }
161     } else {
162         /* 33% chance to blow up one rod, otherwise draining. */
163         if (tval == ItemKindType::ROD) {
164             if (one_in_(3)) {
165                 fail_type = 2;
166             } else {
167                 fail_type = 1;
168             }
169         }
170         /* 20% chance of the entire stack, else destroy one wand. */
171         else if (tval == ItemKindType::WAND) {
172             if (one_in_(5)) {
173                 fail_type = 3;
174             } else {
175                 fail_type = 2;
176             }
177         }
178         /* Blow up one staff. */
179         else if (tval == ItemKindType::STAFF) {
180             fail_type = 2;
181         }
182     }
183
184     switch (fail_type) {
185     case 0:
186         break;
187     case 1:
188         if (tval == ItemKindType::ROD) {
189             msg_print(_("魔力が逆噴射して、ロッドからさらに魔力を吸い取ってしまった!", "The recharge backfires, draining the rod further!"));
190
191             if (o_ptr->timeout < 10000) {
192                 o_ptr->timeout = (o_ptr->timeout + 100) * 2;
193             }
194         } else if (tval == ItemKindType::WAND) {
195             msg_format(_("%sは破損を免れたが、魔力が全て失われた。", "You save your %s from destruction, but all charges are lost."), item_name.data());
196             o_ptr->pval = 0;
197         }
198
199         break;
200     case 2:
201         if (o_ptr->number > 1) {
202             msg_format(_("乱暴な魔法のために%sが一本壊れた!", "Wild magic consumes one of your %s!"), item_name.data());
203         } else {
204             msg_format(_("乱暴な魔法のために%sが壊れた!", "Wild magic consumes your %s!"), item_name.data());
205         }
206
207         if (tval == ItemKindType::ROD) {
208             o_ptr->timeout = (o_ptr->number - 1) * baseitem.pval;
209         }
210
211         if (tval == ItemKindType::WAND) {
212             o_ptr->pval = 0;
213         }
214
215         vary_item(player_ptr, item, -1);
216         break;
217     case 3:
218         if (o_ptr->number > 1) {
219             msg_format(_("乱暴な魔法のために%sが全て壊れた!", "Wild magic consumes all your %s!"), item_name.data());
220         } else {
221             msg_format(_("乱暴な魔法のために%sが壊れた!", "Wild magic consumes your %s!"), item_name.data());
222         }
223
224         vary_item(player_ptr, item, -999);
225         break;
226     default:
227         THROW_EXCEPTION(std::logic_error, "Invalid fail type!");
228     }
229
230     return update_player();
231 }