OSDN Git Service

Merge pull request #1893 from sikabane-works/release/3.0.0Alpha47
[hengbandforosx/hengbandosx.git] / src / cmd-item / cmd-equipment.cpp
1 #include "cmd-item/cmd-equipment.h"
2 #include "action/weapon-shield.h"
3 #include "artifact/fixed-art-types.h"
4 #include "autopick/autopick.h"
5 #include "avatar/avatar.h"
6 #include "core/asking-player.h"
7 #include "core/player-redraw-types.h"
8 #include "core/player-update-types.h"
9 #include "core/window-redrawer.h"
10 #include "dungeon/quest.h" //!< @todo 違和感、何故アイテムを装備するとクエストの成功判定が走るのか?.
11 #include "flavor/flavor-describer.h"
12 #include "flavor/object-flavor-types.h"
13 #include "floor/floor-object.h"
14 #include "game-option/birth-options.h"
15 #include "game-option/input-options.h"
16 #include "inventory/inventory-describer.h"
17 #include "inventory/inventory-object.h"
18 #include "inventory/inventory-slot-types.h"
19 #include "io/input-key-acceptor.h"
20 #include "io/input-key-requester.h"
21 #include "locale/japanese.h"
22 #include "main/sound-definitions-table.h"
23 #include "main/sound-of-music.h"
24 #include "object-enchant/item-feeling.h"
25 #include "object-enchant/special-object-flags.h"
26 #include "object-enchant/trc-types.h"
27 #include "object-hook/hook-armor.h"
28 #include "object-hook/hook-weapon.h"
29 #include "object/item-tester-hooker.h"
30 #include "object/item-use-flags.h"
31 #include "object/object-flags.h"
32 #include "object/object-info.h"
33 #include "object/object-mark-types.h"
34 #include "perception/object-perception.h"
35 #include "player-base/player-class.h"
36 #include "player-info/equipment-info.h"
37 #include "player-info/samurai-data-type.h"
38 #include "player-status/player-energy.h"
39 #include "player-status/player-hand-types.h"
40 #include "player/attack-defense-types.h"
41 #include "player/player-status.h"
42 #include "player/special-defense-types.h"
43 #include "racial/racial-android.h"
44 #include "spell-kind/spells-perception.h"
45 #include "status/action-setter.h"
46 #include "status/shape-changer.h"
47 #include "system/object-type-definition.h"
48 #include "system/player-type-definition.h"
49 #include "term/screen-processor.h"
50 #include "util/int-char-converter.h"
51 #include "view/display-inventory.h"
52 #include "view/display-messages.h"
53
54 /*!
55  * @brief 装備時にアイテムを呪う処理
56  */
57 static void do_curse_on_equip(OBJECT_IDX slot, object_type *o_ptr, PlayerType *player_ptr)
58 {
59     if (set_anubis_and_chariot(player_ptr) && ((slot == INVEN_MAIN_HAND) || (slot == INVEN_SUB_HAND))) {
60
61         object_type *anubis = &(player_ptr->inventory_list[INVEN_MAIN_HAND]);
62         object_type *chariot = &(player_ptr->inventory_list[INVEN_SUB_HAND]);
63
64         anubis->curse_flags.set(CurseTraitType::PERSISTENT_CURSE);
65         anubis->curse_flags.set(CurseTraitType::HEAVY_CURSE);
66         chariot->curse_flags.set(CurseTraitType::PERSISTENT_CURSE);
67         chariot->curse_flags.set(CurseTraitType::HEAVY_CURSE);
68         chariot->curse_flags.set(CurseTraitType::BERS_RAGE);
69         chariot->curse_flags.set(CurseTraitType::LOW_AC);
70         chariot->curse_flags.set(CurseTraitType::VUL_CURSE);
71         
72         msg_format(_("『銀の戦車』プラス『アヌビス神』二刀流ッ!", "*Silver Chariot* plus *Anubis God* Two Swords!"));
73         player_ptr->update |= (PU_BONUS);
74         return;
75     }
76
77     if ((object_flags(o_ptr).has(TR_PERSISTENT_CURSE) || o_ptr->curse_flags.has(CurseTraitType::PERSISTENT_CURSE)) 
78         && o_ptr->curse_flags.has_not(CurseTraitType::HEAVY_CURSE)) {
79
80         GAME_TEXT o_name[MAX_NLEN];
81         describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
82         o_ptr->curse_flags.set(CurseTraitType::HEAVY_CURSE);
83         msg_format(_("悪意に満ちた黒いオーラが%sをとりまいた...", "There is a malignant black aura surrounding your %s..."), o_name);
84         o_ptr->feeling = FEEL_NONE;
85         player_ptr->update |= (PU_BONUS);
86     }
87 }
88
89 /*!
90  * @brief 装備一覧を表示するコマンドのメインルーチン / Display equipment
91  */
92 void do_cmd_equip(PlayerType *player_ptr)
93 {
94     char out_val[160];
95     command_wrk = true;
96     if (easy_floor)
97         command_wrk = USE_EQUIP;
98
99     screen_save();
100     (void)show_equipment(player_ptr, 0, USE_FULL, AllMatchItemTester());
101     auto weight = calc_inventory_weight(player_ptr);
102     auto weight_lim = calc_weight_limit(player_ptr);
103 #ifdef JP
104     sprintf(out_val, "装備: 合計 %3d.%1d kg (限界の%d%%) コマンド: ", lb_to_kg_integer(weight), lb_to_kg_fraction(weight), weight * 100 / weight_lim);
105 #else
106     sprintf(out_val, "Equipment: carrying %d.%d pounds (%d%% of capacity). Command: ", weight / 10, weight % 10, weight * 100 / weight_lim);
107 #endif
108
109     prt(out_val, 0, 0);
110     command_new = inkey();
111     screen_load();
112
113     if (command_new != ESCAPE) {
114         command_see = true;
115         return;
116     }
117
118     TERM_LEN wid, hgt;
119     term_get_size(&wid, &hgt);
120     command_new = 0;
121     command_gap = wid - 30;
122 }
123
124 /*!
125  * @brief 装備するコマンドのメインルーチン / Wield or wear a single item from the pack or floor
126  * @param player_ptr プレイヤーへの参照ポインタ
127  */
128 void do_cmd_wield(PlayerType *player_ptr)
129 {
130     OBJECT_IDX item, slot;
131     object_type forge;
132     object_type *q_ptr;
133     object_type *o_ptr;
134     concptr act;
135     GAME_TEXT o_name[MAX_NLEN];
136     OBJECT_IDX need_switch_wielding = 0;
137     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
138
139     concptr q = _("どれを装備しますか? ", "Wear/Wield which item? ");
140     concptr s = _("装備可能なアイテムがない。", "You have nothing you can wear or wield.");
141     o_ptr = choose_object(player_ptr, &item, q, s, (USE_INVEN | USE_FLOOR), FuncItemTester(item_tester_hook_wear, player_ptr));
142     if (!o_ptr)
143         return;
144
145     slot = wield_slot(player_ptr, o_ptr);
146
147     const auto o_ptr_mh = &player_ptr->inventory_list[INVEN_MAIN_HAND];
148     const auto o_ptr_sh = &player_ptr->inventory_list[INVEN_SUB_HAND];
149
150     switch (o_ptr->tval) {
151     case ItemKindType::CAPTURE:
152     case ItemKindType::SHIELD:
153     case ItemKindType::CARD:
154         if (has_melee_weapon(player_ptr, INVEN_MAIN_HAND) && has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
155             q = _("どちらの武器と取り替えますか?", "Replace which weapon? ");
156             s = _("おっと。", "Oops.");
157             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT), FuncItemTester(&object_type::is_melee_weapon)))
158                 return;
159
160             if (slot == INVEN_MAIN_HAND)
161                 need_switch_wielding = INVEN_SUB_HAND;
162         } else if (has_melee_weapon(player_ptr, INVEN_SUB_HAND))
163             slot = INVEN_MAIN_HAND;
164         else if (o_ptr_mh->k_idx && o_ptr_sh->k_idx &&
165                  ((o_ptr->tval == ItemKindType::CAPTURE) || (!o_ptr_mh->is_melee_weapon() && !o_ptr_sh->is_melee_weapon()))) {
166             q = _("どちらの手に装備しますか?", "Equip which hand? ");
167             s = _("おっと。", "Oops.");
168             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP), FuncItemTester(&object_type::is_wieldable_in_etheir_hand)))
169                 return;
170         }
171
172         break;
173     case ItemKindType::DIGGING:
174     case ItemKindType::HAFTED:
175     case ItemKindType::POLEARM:
176     case ItemKindType::SWORD:
177         if (slot == INVEN_SUB_HAND) {
178             if (!get_check(_("二刀流で戦いますか?", "Dual wielding? ")))
179                 slot = INVEN_MAIN_HAND;
180         } else if (!o_ptr_mh->k_idx && has_melee_weapon(player_ptr, INVEN_SUB_HAND)) {
181             if (!get_check(_("二刀流で戦いますか?", "Dual wielding? ")))
182                 slot = INVEN_SUB_HAND;
183         } else if (o_ptr_mh->k_idx && o_ptr_sh->k_idx) {
184             q = _("どちらの手に装備しますか?", "Equip which hand? ");
185             s = _("おっと。", "Oops.");
186             if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP), FuncItemTester(&object_type::is_wieldable_in_etheir_hand)))
187                 return;
188
189             if ((slot == INVEN_SUB_HAND) && !has_melee_weapon(player_ptr, INVEN_MAIN_HAND))
190                 need_switch_wielding = INVEN_MAIN_HAND;
191         }
192
193         break;
194     case ItemKindType::RING:
195         if (player_ptr->inventory_list[INVEN_SUB_RING].k_idx && player_ptr->inventory_list[INVEN_MAIN_RING].k_idx)
196             q = _("どちらの指輪と取り替えますか?", "Replace which ring? ");
197         else
198             q = _("どちらの手に装備しますか?", "Equip which hand? ");
199
200         s = _("おっと。", "Oops.");
201         player_ptr->select_ring_slot = true;
202         if (!choose_object(player_ptr, &slot, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT))) {
203             player_ptr->select_ring_slot = false;
204             return;
205         }
206
207         player_ptr->select_ring_slot = false;
208         break;
209
210     default:
211         break;
212     }
213
214     if (player_ptr->inventory_list[slot].is_cursed()) {
215         describe_flavor(player_ptr, o_name, &player_ptr->inventory_list[slot], OD_OMIT_PREFIX | OD_NAME_ONLY);
216 #ifdef JP
217         msg_format("%s%sは呪われているようだ。", describe_use(player_ptr, slot), o_name);
218 #else
219         msg_format("The %s you are %s appears to be cursed.", o_name, describe_use(player_ptr, slot));
220 #endif
221         return;
222     }
223
224     if (confirm_wear && ((o_ptr->is_cursed() && o_ptr->is_known()) || ((o_ptr->ident & IDENT_SENSE) && (FEEL_BROKEN <= o_ptr->feeling) && (o_ptr->feeling <= FEEL_CURSED)))) {
225         char dummy[MAX_NLEN + 80];
226         describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
227         sprintf(dummy, _("本当に%s{呪われている}を使いますか?", "Really use the %s {cursed}? "), o_name);
228
229         if (!get_check(dummy))
230             return;
231     }
232
233     if ((o_ptr->name1 == ART_STONEMASK) && o_ptr->is_known() && (player_ptr->prace != PlayerRaceType::VAMPIRE) && (player_ptr->prace != PlayerRaceType::ANDROID)) {
234         char dummy[MAX_NLEN + 100];
235         describe_flavor(player_ptr, o_name, o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
236         sprintf(dummy,
237             _("%sを装備すると吸血鬼になります。よろしいですか?", "%s will transform you into a vampire permanently when equipped. Do you become a vampire? "),
238             o_name);
239
240         if (!get_check(dummy))
241             return;
242     }
243
244     sound(SOUND_WIELD);
245     if (need_switch_wielding && !player_ptr->inventory_list[need_switch_wielding].is_cursed()) {
246         object_type *slot_o_ptr = &player_ptr->inventory_list[slot];
247         object_type *switch_o_ptr = &player_ptr->inventory_list[need_switch_wielding];
248         object_type object_tmp;
249         object_type *otmp_ptr = &object_tmp;
250         GAME_TEXT switch_name[MAX_NLEN];
251         describe_flavor(player_ptr, switch_name, switch_o_ptr, (OD_OMIT_PREFIX | OD_NAME_ONLY));
252         otmp_ptr->copy_from(switch_o_ptr);
253         switch_o_ptr->copy_from(slot_o_ptr);
254         slot_o_ptr->copy_from(otmp_ptr);
255         msg_format(_("%sを%sに構えなおした。", "You wield %s at %s hand."), switch_name,
256             (slot == INVEN_MAIN_HAND) ? (left_hander ? _("左手", "left") : _("右手", "right")) : (left_hander ? _("右手", "right") : _("左手", "left")));
257         slot = need_switch_wielding;
258     }
259
260     check_find_art_quest_completion(player_ptr, o_ptr);
261     if (player_ptr->ppersonality == PERSONALITY_MUNCHKIN) {
262         identify_item(player_ptr, o_ptr);
263         autopick_alter_item(player_ptr, item, false);
264     }
265
266     PlayerEnergy(player_ptr).set_player_turn_energy(100);
267     q_ptr = &forge;
268     q_ptr->copy_from(o_ptr);
269     q_ptr->number = 1;
270     if (item >= 0) {
271         inven_item_increase(player_ptr, item, -1);
272         inven_item_optimize(player_ptr, item);
273     } else {
274         floor_item_increase(player_ptr, 0 - item, -1);
275         floor_item_optimize(player_ptr, 0 - item);
276     }
277
278     o_ptr = &player_ptr->inventory_list[slot];
279     if (o_ptr->k_idx)
280         (void)inven_takeoff(player_ptr, slot, 255);
281
282     o_ptr->copy_from(q_ptr);
283     o_ptr->marked |= OM_TOUCHED;
284     player_ptr->equip_cnt++;
285
286 #define STR_WIELD_HAND_RIGHT _("%s(%c)を右手に装備した。", "You are wielding %s (%c) in your right hand.")
287 #define STR_WIELD_HAND_LEFT _("%s(%c)を左手に装備した。", "You are wielding %s (%c) in your left hand.")
288 #define STR_WIELD_HANDS_TWO _("%s(%c)を両手で構えた。", "You are wielding %s (%c) with both hands.")
289
290     switch (slot) {
291     case INVEN_MAIN_HAND:
292         if (o_ptr->allow_two_hands_wielding() && (empty_hands(player_ptr, false) == EMPTY_HAND_SUB) && can_two_hands_wielding(player_ptr))
293             act = STR_WIELD_HANDS_TWO;
294         else
295             act = (left_hander ? STR_WIELD_HAND_LEFT : STR_WIELD_HAND_RIGHT);
296
297         break;
298     case INVEN_SUB_HAND:
299         if (o_ptr->allow_two_hands_wielding() && (empty_hands(player_ptr, false) == EMPTY_HAND_MAIN) && can_two_hands_wielding(player_ptr))
300             act = STR_WIELD_HANDS_TWO;
301         else
302             act = (left_hander ? STR_WIELD_HAND_RIGHT : STR_WIELD_HAND_LEFT);
303
304         break;
305     case INVEN_BOW:
306         act = _("%s(%c)を射撃用に装備した。", "You are shooting with %s (%c).");
307         break;
308     case INVEN_LITE:
309         act = _("%s(%c)を光源にした。", "Your light source is %s (%c).");
310         break;
311     default:
312         act = _("%s(%c)を装備した。", "You are wearing %s (%c).");
313         break;
314     }
315
316     describe_flavor(player_ptr, o_name, o_ptr, 0);
317     msg_format(act, o_name, index_to_label(slot));
318     if (o_ptr->is_cursed()) {
319         msg_print(_("うわ! すさまじく冷たい!", "Oops! It feels deathly cold!"));
320         chg_virtue(player_ptr, V_HARMONY, -1);
321         o_ptr->ident |= (IDENT_SENSE);
322     }
323
324     do_curse_on_equip(slot, o_ptr, player_ptr);
325
326     if ((o_ptr->name1 == ART_STONEMASK) && (player_ptr->prace != PlayerRaceType::VAMPIRE) && (player_ptr->prace != PlayerRaceType::ANDROID))
327         change_race(player_ptr, PlayerRaceType::VAMPIRE, "");
328
329     calc_android_exp(player_ptr);
330     player_ptr->update |= PU_BONUS | PU_TORCH | PU_MANA;
331     player_ptr->redraw |= PR_EQUIPPY;
332     player_ptr->window_flags |= PW_INVEN | PW_EQUIP | PW_PLAYER;
333 }
334
335 /*!
336  * @brief 装備を外すコマンドのメインルーチン / Take off an item
337  */
338 void do_cmd_takeoff(PlayerType *player_ptr)
339 {
340     OBJECT_IDX item;
341     object_type *o_ptr;
342     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
343
344     concptr q = _("どれを装備からはずしますか? ", "Take off which item? ");
345     concptr s = _("はずせる装備がない。", "You are not wearing anything to take off.");
346     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT));
347     if (!o_ptr)
348         return;
349
350     PlayerEnergy energy(player_ptr);
351     if (o_ptr->is_cursed()) {
352         if (o_ptr->curse_flags.has(CurseTraitType::PERMA_CURSE) || (player_ptr->pclass != PlayerClassType::BERSERKER)) {
353             msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
354             return;
355         }
356
357         if ((o_ptr->curse_flags.has(CurseTraitType::HEAVY_CURSE) && one_in_(7)) || one_in_(4)) {
358             msg_print(_("呪われた装備を力づくで剥がした!", "You tore off a piece of cursed equipment by sheer strength!"));
359             o_ptr->ident |= (IDENT_SENSE);
360             o_ptr->curse_flags.clear();
361             o_ptr->feeling = FEEL_NONE;
362             player_ptr->update |= PU_BONUS;
363             player_ptr->window_flags |= PW_EQUIP;
364             msg_print(_("呪いを打ち破った。", "You break the curse."));
365         } else {
366             msg_print(_("装備を外せなかった。", "You couldn't remove the equipment."));
367             energy.set_player_turn_energy(50);
368             return;
369         }
370     }
371
372     sound(SOUND_TAKE_OFF);
373     energy.set_player_turn_energy(50);
374     (void)inven_takeoff(player_ptr, item, 255);
375     verify_equip_slot(player_ptr, item);
376     calc_android_exp(player_ptr);
377     player_ptr->update |= PU_BONUS | PU_TORCH | PU_MANA;
378     player_ptr->redraw |= PR_EQUIPPY;
379     player_ptr->window_flags |= PW_INVEN | PW_EQUIP | PW_PLAYER;
380 }