OSDN Git Service

Merge pull request #3752 from Hourier/Replace-Pos2D-Beta2
[hengbandforosx/hengbandosx.git] / src / spell-realm / spells-craft.cpp
1 #include "spell-realm/spells-craft.h"
2 #include "avatar/avatar.h"
3 #include "core/disturbance.h"
4 #include "core/stuff-handler.h"
5 #include "flavor/flavor-describer.h"
6 #include "flavor/object-flavor-types.h"
7 #include "floor/floor-object.h"
8 #include "game-option/disturbance-options.h"
9 #include "inventory/inventory-slot-types.h"
10 #include "io/input-key-acceptor.h"
11 #include "object-enchant/object-ego.h"
12 #include "object/item-use-flags.h"
13 #include "player-info/equipment-info.h"
14 #include "player/attack-defense-types.h"
15 #include "player/special-defense-types.h"
16 #include "racial/racial-android.h"
17 #include "spell/spells-object.h"
18 #include "sv-definition/sv-protector-types.h"
19 #include "system/item-entity.h"
20 #include "system/player-type-definition.h"
21 #include "system/redrawing-flags-updater.h"
22 #include "term/screen-processor.h"
23 #include "term/term-color-types.h"
24 #include "view/display-messages.h"
25
26 /*!
27  * @brief 一時的元素スレイの継続時間をセットする / Set a temporary elemental brand. Clear all other brands. Print status messages. -LM-
28  * @param attack_type スレイのタイプID
29  * @param v 継続時間
30  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
31  */
32 bool set_ele_attack(PlayerType *player_ptr, uint32_t attack_type, TIME_EFFECT v)
33 {
34     v = (v > 10000) ? 10000 : (v < 0) ? 0
35                                       : v;
36
37     if ((player_ptr->special_attack & (ATTACK_ACID)) && (attack_type != ATTACK_ACID)) {
38         player_ptr->special_attack &= ~(ATTACK_ACID);
39         msg_print(_("酸で攻撃できなくなった。", "Your temporary acidic brand fades away."));
40     }
41
42     if ((player_ptr->special_attack & (ATTACK_ELEC)) && (attack_type != ATTACK_ELEC)) {
43         player_ptr->special_attack &= ~(ATTACK_ELEC);
44         msg_print(_("電撃で攻撃できなくなった。", "Your temporary electrical brand fades away."));
45     }
46
47     if ((player_ptr->special_attack & (ATTACK_FIRE)) && (attack_type != ATTACK_FIRE)) {
48         player_ptr->special_attack &= ~(ATTACK_FIRE);
49         msg_print(_("火炎で攻撃できなくなった。", "Your temporary fiery brand fades away."));
50     }
51
52     if ((player_ptr->special_attack & (ATTACK_COLD)) && (attack_type != ATTACK_COLD)) {
53         player_ptr->special_attack &= ~(ATTACK_COLD);
54         msg_print(_("冷気で攻撃できなくなった。", "Your temporary frost brand fades away."));
55     }
56
57     if ((player_ptr->special_attack & (ATTACK_POIS)) && (attack_type != ATTACK_POIS)) {
58         player_ptr->special_attack &= ~(ATTACK_POIS);
59         msg_print(_("毒で攻撃できなくなった。", "Your temporary poison brand fades away."));
60     }
61
62     if ((v) && (attack_type)) {
63         player_ptr->special_attack |= (attack_type);
64         player_ptr->ele_attack = v;
65         std::string element;
66         switch (attack_type) {
67         case ATTACK_ACID:
68             element = _("酸", "melt with acid!");
69             break;
70         case ATTACK_ELEC:
71             element = _("電撃", "shock your foes!");
72             break;
73         case ATTACK_FIRE:
74             element = _("火炎", "burn with fire!");
75             break;
76         case ATTACK_COLD:
77             element = _("冷気", "chill to the bone!");
78             break;
79         case ATTACK_POIS:
80             element = _("毒", "poison your enemies!");
81             break;
82         default: // @todo 本来はruntime_error を飛ばすべきだが、既存コードと同じように動くことを優先した.
83             element = _("(なし)", "do nothing special.");
84             break;
85         }
86
87         constexpr auto mes = _("%sで攻撃できるようになった!", "For a while, the blows you deal will %s");
88         msg_format(mes, element.data());
89     }
90
91     if (disturb_state) {
92         disturb(player_ptr, false, false);
93     }
94
95     auto &rfu = RedrawingFlagsUpdater::get_instance();
96     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
97     rfu.set_flag(StatusRecalculatingFlag::BONUS);
98     handle_stuff(player_ptr);
99
100     return true;
101 }
102
103 /*!
104  * @brief 一時的元素免疫の継続時間をセットする / Set a temporary elemental brand.  Clear all other brands.  Print status messages. -LM-
105  * @param immune_type 免疫のタイプID
106  * @param v 継続時間
107  * @return ステータスに影響を及ぼす変化があった場合TRUEを返す。
108  */
109 bool set_ele_immune(PlayerType *player_ptr, uint32_t immune_type, TIME_EFFECT v)
110 {
111     v = (v > 10000) ? 10000 : (v < 0) ? 0
112                                       : v;
113
114     if ((player_ptr->special_defense & (DEFENSE_ACID)) && (immune_type != DEFENSE_ACID)) {
115         player_ptr->special_defense &= ~(DEFENSE_ACID);
116         msg_print(_("酸の攻撃で傷つけられるようになった。。", "You are no longer immune to acid."));
117     }
118
119     if ((player_ptr->special_defense & (DEFENSE_ELEC)) && (immune_type != DEFENSE_ELEC)) {
120         player_ptr->special_defense &= ~(DEFENSE_ELEC);
121         msg_print(_("電撃の攻撃で傷つけられるようになった。。", "You are no longer immune to electricity."));
122     }
123
124     if ((player_ptr->special_defense & (DEFENSE_FIRE)) && (immune_type != DEFENSE_FIRE)) {
125         player_ptr->special_defense &= ~(DEFENSE_FIRE);
126         msg_print(_("火炎の攻撃で傷つけられるようになった。。", "You are no longer immune to fire."));
127     }
128
129     if ((player_ptr->special_defense & (DEFENSE_COLD)) && (immune_type != DEFENSE_COLD)) {
130         player_ptr->special_defense &= ~(DEFENSE_COLD);
131         msg_print(_("冷気の攻撃で傷つけられるようになった。。", "You are no longer immune to cold."));
132     }
133
134     if ((player_ptr->special_defense & (DEFENSE_POIS)) && (immune_type != DEFENSE_POIS)) {
135         player_ptr->special_defense &= ~(DEFENSE_POIS);
136         msg_print(_("毒の攻撃で傷つけられるようになった。。", "You are no longer immune to poison."));
137     }
138
139     if ((v) && (immune_type)) {
140         player_ptr->special_defense |= (immune_type);
141         player_ptr->ele_immune = v;
142         std::string element;
143         switch (immune_type) {
144         case ATTACK_ACID:
145             element = _("酸", "acid!");
146             break;
147         case ATTACK_ELEC:
148             element = _("電撃", "electricity!");
149             break;
150         case ATTACK_FIRE:
151             element = _("火炎", "fire!");
152             break;
153         case ATTACK_COLD:
154             element = _("冷気", "cold!");
155             break;
156         case ATTACK_POIS:
157             element = _("毒", "poison!");
158             break;
159         default: // @todo 本来はruntime_error を飛ばすべきだが、既存コードと同じように動くことを優先した.
160             element = _("(なし)", "nothing special.");
161             break;
162         }
163
164         msg_format(_("%sの攻撃を受けつけなくなった!", "For a while, you are immune to %s"), element.data());
165     }
166
167     if (disturb_state) {
168         disturb(player_ptr, false, false);
169     }
170
171     auto &rfu = RedrawingFlagsUpdater::get_instance();
172     rfu.set_flag(MainWindowRedrawingFlag::TIMED_EFFECT);
173     rfu.set_flag(StatusRecalculatingFlag::BONUS);
174     handle_stuff(player_ptr);
175
176     return true;
177 }
178
179 /*
180  * Choose a warrior-mage elemental attack. -LM-
181  */
182 bool choose_ele_attack(PlayerType *player_ptr)
183 {
184     if (!has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && !has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
185         msg_format(_("武器を持たないと魔法剣は使えない。", "You cannot use temporary branding with no weapon."));
186         return false;
187     }
188
189     screen_save();
190     int num = (player_ptr->lev - 20) / 5;
191     c_prt(TERM_RED, _("        a) 焼棄", "        a) Fire Brand"), 2, 14);
192
193     if (num >= 2) {
194         c_prt(TERM_L_WHITE, _("        b) 凍結", "        b) Cold Brand"), 3, 14);
195     } else {
196         prt("", 3, 14);
197     }
198
199     if (num >= 3) {
200         c_prt(TERM_GREEN, _("        c) 毒殺", "        c) Poison Brand"), 4, 14);
201     } else {
202         prt("", 4, 14);
203     }
204
205     if (num >= 4) {
206         c_prt(TERM_L_DARK, _("        d) 溶解", "        d) Acid Brand"), 5, 14);
207     } else {
208         prt("", 5, 14);
209     }
210
211     if (num >= 5) {
212         c_prt(TERM_BLUE, _("        e) 電撃", "        e) Elec Brand"), 6, 14);
213     } else {
214         prt("", 6, 14);
215     }
216
217     prt("", 7, 14);
218     prt("", 8, 14);
219     prt("", 9, 14);
220
221     prt("", 1, 0);
222     prt(_("        どの元素攻撃をしますか?", "        Choose a temporary elemental brand "), 1, 14);
223
224     char choice = inkey();
225
226     if ((choice == 'a') || (choice == 'A')) {
227         set_ele_attack(player_ptr, ATTACK_FIRE, player_ptr->lev / 2 + randint1(player_ptr->lev / 2));
228     } else if (((choice == 'b') || (choice == 'B')) && (num >= 2)) {
229         set_ele_attack(player_ptr, ATTACK_COLD, player_ptr->lev / 2 + randint1(player_ptr->lev / 2));
230     } else if (((choice == 'c') || (choice == 'C')) && (num >= 3)) {
231         set_ele_attack(player_ptr, ATTACK_POIS, player_ptr->lev / 2 + randint1(player_ptr->lev / 2));
232     } else if (((choice == 'd') || (choice == 'D')) && (num >= 4)) {
233         set_ele_attack(player_ptr, ATTACK_ACID, player_ptr->lev / 2 + randint1(player_ptr->lev / 2));
234     } else if (((choice == 'e') || (choice == 'E')) && (num >= 5)) {
235         set_ele_attack(player_ptr, ATTACK_ELEC, player_ptr->lev / 2 + randint1(player_ptr->lev / 2));
236     } else {
237         msg_print(_("魔法剣を使うのをやめた。", "You cancel the temporary branding."));
238         screen_load();
239         return false;
240     }
241
242     screen_load();
243     return true;
244 }
245 /*
246  * Choose a elemental immune. -LM-
247  */
248 bool choose_ele_immune(PlayerType *player_ptr, TIME_EFFECT immune_turn)
249 {
250     screen_save();
251
252     c_prt(TERM_RED, _("        a) 火炎", "        a) Immunity to fire"), 2, 14);
253     c_prt(TERM_L_WHITE, _("        b) 冷気", "        b) Immunity to cold"), 3, 14);
254     c_prt(TERM_L_DARK, _("        c) 酸", "        c) Immunity to acid"), 4, 14);
255     c_prt(TERM_BLUE, _("        d) 電撃", "        d) Immunity to elec"), 5, 14);
256
257     prt("", 6, 14);
258     prt("", 7, 14);
259     prt("", 8, 14);
260     prt("", 9, 14);
261
262     prt("", 1, 0);
263     prt(_("        どの元素の免疫をつけますか?", "        Choose a temporary elemental immunity "), 1, 14);
264
265     char choice = inkey();
266
267     if ((choice == 'a') || (choice == 'A')) {
268         set_ele_immune(player_ptr, DEFENSE_FIRE, immune_turn);
269     } else if ((choice == 'b') || (choice == 'B')) {
270         set_ele_immune(player_ptr, DEFENSE_COLD, immune_turn);
271     } else if ((choice == 'c') || (choice == 'C')) {
272         set_ele_immune(player_ptr, DEFENSE_ACID, immune_turn);
273     } else if ((choice == 'd') || (choice == 'D')) {
274         set_ele_immune(player_ptr, DEFENSE_ELEC, immune_turn);
275     } else {
276         msg_print(_("免疫を付けるのをやめた。", "You cancel the temporary immunity."));
277         screen_load();
278         return false;
279     }
280
281     screen_load();
282     return true;
283 }
284
285 /*!
286  * @brief 盾磨き処理 /
287  * pulish shield
288  * @return ターン消費を要する処理を行ったならばTRUEを返す
289  */
290 bool pulish_shield(PlayerType *player_ptr)
291 {
292     constexpr auto q = _("どの盾を磨きますか?", "Polish which shield? ");
293     constexpr auto s = _("磨く盾がありません。", "You have no shield to polish.");
294     const auto options = USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT;
295     short i_idx;
296     auto *o_ptr = choose_object(player_ptr, &i_idx, q, s, options, TvalItemTester(ItemKindType::SHIELD));
297     if (o_ptr == nullptr) {
298         return false;
299     }
300
301     const auto item_name = describe_flavor(player_ptr, o_ptr, OD_OMIT_PREFIX | OD_NAME_ONLY);
302     auto is_pulish_successful = o_ptr->is_valid() && !o_ptr->is_fixed_or_random_artifact() && !o_ptr->is_ego();
303     is_pulish_successful &= !o_ptr->is_cursed();
304     is_pulish_successful &= (o_ptr->bi_key.sval() != SV_MIRROR_SHIELD);
305     if (is_pulish_successful) {
306 #ifdef JP
307         msg_format("%sは輝いた!", item_name.data());
308 #else
309         msg_format("%s %s shine%s!", ((i_idx >= 0) ? "Your" : "The"), item_name.data(), ((o_ptr->number > 1) ? "" : "s"));
310 #endif
311         o_ptr->ego_idx = EgoType::REFLECTION;
312         enchant_equipment(o_ptr, randint0(3) + 4, ENCH_TOAC);
313         o_ptr->discount = 99;
314         chg_virtue(player_ptr, Virtue::ENCHANT, 2);
315         return true;
316     }
317
318     if (flush_failure) {
319         flush();
320     }
321
322     msg_print(_("失敗した。", "Failed."));
323     chg_virtue(player_ptr, Virtue::ENCHANT, -2);
324     calc_android_exp(player_ptr);
325     return false;
326 }