OSDN Git Service

Merge pull request #1929 from habu1010/feature/fix-smith-object-stack
[hengbandforosx/hengbandosx.git] / src / cmd-item / cmd-item.cpp
1 /*!
2  *  @brief プレイヤーのアイテムに関するコマンドの実装1 / Inventory and equipment commands
3  *  @date 2014/01/02
4  *  @author
5  * Copyright (c) 1997 Ben Harrison, James E. Wilson, Robert A. Koeneke
6  *
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  */
11
12 #include "cmd-item/cmd-item.h"
13 #include "action/action-limited.h"
14 #include "action/activation-execution.h"
15 #include "action/weapon-shield.h"
16 #include "cmd-action/cmd-open-close.h"
17 #include "cmd-action/cmd-pet.h"
18 #include "cmd-item/cmd-eat.h"
19 #include "cmd-item/cmd-quaff.h"
20 #include "cmd-item/cmd-read.h"
21 #include "cmd-item/cmd-zaprod.h"
22 #include "cmd-item/cmd-zapwand.h"
23 #include "combat/shoot.h"
24 #include "core/asking-player.h"
25 #include "core/player-redraw-types.h"
26 #include "core/player-update-types.h"
27 #include "core/window-redrawer.h"
28 #include "flavor/flavor-describer.h"
29 #include "flavor/object-flavor-types.h"
30 #include "floor/floor-object.h"
31 #include "game-option/input-options.h"
32 #include "inventory/inventory-object.h"
33 #include "inventory/inventory-slot-types.h"
34 #include "io/input-key-acceptor.h"
35 #include "io/input-key-requester.h"
36 #include "locale/japanese.h"
37 #include "mind/snipe-types.h"
38 #include "object-activation/activation-switcher.h"
39 #include "object-hook/hook-magic.h"
40 #include "object-use/quaff-execution.h"
41 #include "object-use/read-execution.h"
42 #include "object-use/use-execution.h"
43 #include "object-use/zaprod-execution.h"
44 #include "object-use/zapwand-execution.h"
45 #include "object/item-tester-hooker.h"
46 #include "object/item-use-flags.h"
47 #include "perception/identification.h"
48 #include "perception/object-perception.h"
49 #include "player-base/player-class.h"
50 #include "player-info/class-info.h"
51 #include "player-info/race-types.h"
52 #include "player-info/samurai-data-type.h"
53 #include "player-info/self-info.h"
54 #include "player-status/player-energy.h"
55 #include "player/attack-defense-types.h"
56 #include "player/player-personality-types.h"
57 #include "player/player-status.h"
58 #include "player/special-defense-types.h"
59 #include "racial/racial-android.h"
60 #include "realm/realm-hex-numbers.h"
61 #include "realm/realm-types.h"
62 #include "status/action-setter.h"
63 #include "system/object-type-definition.h"
64 #include "system/player-type-definition.h"
65 #include "term/screen-processor.h"
66 #include "util/bit-flags-calculator.h"
67 #include "util/int-char-converter.h"
68 #include "util/quarks.h"
69 #include "util/string-processor.h"
70 #include "view/display-inventory.h"
71 #include "view/display-messages.h"
72
73 /*!
74  * @brief 持ち物一覧を表示するコマンドのメインルーチン / Display inventory_list
75  */
76 void do_cmd_inven(PlayerType *player_ptr)
77 {
78     char out_val[160];
79     command_wrk = false;
80     if (easy_floor)
81         command_wrk = USE_INVEN;
82
83     screen_save();
84     (void)show_inventory(player_ptr, 0, USE_FULL, AllMatchItemTester());
85     WEIGHT weight = calc_inventory_weight(player_ptr);
86     WEIGHT weight_lim = calc_weight_limit(player_ptr);
87 #ifdef JP
88     sprintf(out_val, "持ち物: 合計 %3d.%1d kg (限界の%ld%%) コマンド: ", lb_to_kg_integer(weight), lb_to_kg_fraction(weight),
89 #else
90     sprintf(out_val, "Inventory: carrying %d.%d pounds (%ld%% of capacity). Command: ", weight / 10, weight % 10,
91 #endif
92         (long int)(weight * 100) / weight_lim);
93
94     prt(out_val, 0, 0);
95     command_new = inkey();
96     screen_load();
97     if (command_new != ESCAPE) {
98         command_see = true;
99         return;
100     }
101
102     TERM_LEN wid, hgt;
103     term_get_size(&wid, &hgt);
104     command_new = 0;
105     command_gap = wid - 30;
106 }
107
108 /*!
109  * @brief アイテムを落とすコマンドのメインルーチン / Drop an item
110  */
111 void do_cmd_drop(PlayerType *player_ptr)
112 {
113     OBJECT_IDX item;
114     int amt = 1;
115     object_type *o_ptr;
116     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU });
117
118     concptr q = _("どのアイテムを落としますか? ", "Drop which item? ");
119     concptr s = _("落とせるアイテムを持っていない。", "You have nothing to drop.");
120     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | IGNORE_BOTHHAND_SLOT));
121     if (!o_ptr)
122         return;
123
124     if ((item >= INVEN_MAIN_HAND) && o_ptr->is_cursed()) {
125         msg_print(_("ふーむ、どうやら呪われているようだ。", "Hmmm, it seems to be cursed."));
126         return;
127     }
128
129     if (o_ptr->number > 1) {
130         amt = get_quantity(nullptr, o_ptr->number);
131         if (amt <= 0)
132             return;
133     }
134
135     PlayerEnergy(player_ptr).set_player_turn_energy(50);
136     drop_from_inventory(player_ptr, item, amt);
137     if (item >= INVEN_MAIN_HAND) {
138         verify_equip_slot(player_ptr, item);
139         calc_android_exp(player_ptr);
140     }
141
142     player_ptr->redraw |= (PR_EQUIPPY);
143 }
144
145 /*!
146  * @brief アイテムを調査するコマンドのメインルーチン / Observe an item which has been *identify*-ed
147  */
148 void do_cmd_observe(PlayerType *player_ptr)
149 {
150     OBJECT_IDX item;
151     object_type *o_ptr;
152     GAME_TEXT o_name[MAX_NLEN];
153     concptr q = _("どのアイテムを調べますか? ", "Examine which item? ");
154     concptr s = _("調べられるアイテムがない。", "You have nothing to examine.");
155     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
156     if (!o_ptr)
157         return;
158
159     if (!o_ptr->is_fully_known()) {
160         msg_print(_("このアイテムについて特に知っていることはない。", "You have no special knowledge about that item."));
161         return;
162     }
163
164     describe_flavor(player_ptr, o_name, o_ptr, 0);
165     msg_format(_("%sを調べている...", "Examining %s..."), o_name);
166     if (!screen_object(player_ptr, o_ptr, SCROBJ_FORCE_DETAIL))
167         msg_print(_("特に変わったところはないようだ。", "You see nothing special."));
168 }
169
170 /*!
171  * @brief アイテムの銘を消すコマンドのメインルーチン
172  * Remove the inscription from an object XXX Mention item (when done)?
173  */
174 void do_cmd_uninscribe(PlayerType *player_ptr)
175 {
176     OBJECT_IDX item;
177     object_type *o_ptr;
178     concptr q = _("どのアイテムの銘を消しますか? ", "Un-inscribe which item? ");
179     concptr s = _("銘を消せるアイテムがない。", "You have nothing to un-inscribe.");
180     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
181     if (!o_ptr)
182         return;
183
184     if (!o_ptr->inscription) {
185         msg_print(_("このアイテムには消すべき銘がない。", "That item had no inscription to remove."));
186         return;
187     }
188
189     msg_print(_("銘を消した。", "Inscription removed."));
190     o_ptr->inscription = 0;
191     set_bits(player_ptr->update, PU_COMBINE);
192     set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_FLOOR_ITEM_LIST);
193     set_bits(player_ptr->update, PU_BONUS);
194 }
195
196 /*!
197  * @brief アイテムの銘を刻むコマンドのメインルーチン
198  * Inscribe an object with a comment
199  */
200 void do_cmd_inscribe(PlayerType *player_ptr)
201 {
202     OBJECT_IDX item;
203     object_type *o_ptr;
204     GAME_TEXT o_name[MAX_NLEN];
205     char out_val[MAX_INSCRIPTION + 1] = "";
206     concptr q = _("どのアイテムに銘を刻みますか? ", "Inscribe which item? ");
207     concptr s = _("銘を刻めるアイテムがない。", "You have nothing to inscribe.");
208     o_ptr = choose_object(player_ptr, &item, q, s, (USE_EQUIP | USE_INVEN | USE_FLOOR | IGNORE_BOTHHAND_SLOT));
209     if (!o_ptr)
210         return;
211
212     describe_flavor(player_ptr, o_name, o_ptr, OD_OMIT_INSCRIPTION);
213     msg_format(_("%sに銘を刻む。", "Inscribing %s."), o_name);
214     msg_print(nullptr);
215     strcpy(out_val, "");
216     if (o_ptr->inscription)
217         angband_strcpy(out_val, quark_str(o_ptr->inscription), MAX_INSCRIPTION);
218
219     if (get_string(_("銘: ", "Inscription: "), out_val, MAX_INSCRIPTION)) {
220         o_ptr->inscription = quark_add(out_val);
221         set_bits(player_ptr->update, PU_COMBINE);
222         set_bits(player_ptr->window_flags, PW_INVEN | PW_EQUIP | PW_FLOOR_ITEM_LIST);
223         set_bits(player_ptr->update, PU_BONUS);
224     }
225 }
226
227 /*!
228  * @brief アイテムを汎用的に「使う」コマンドのメインルーチン /
229  * Use an item
230  * @details
231  * XXX - Add actions for other item types
232  */
233 void do_cmd_use(PlayerType *player_ptr)
234 {
235     OBJECT_IDX item;
236     object_type *o_ptr;
237     if (player_ptr->wild_mode || cmd_limit_arena(player_ptr))
238         return;
239
240     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
241
242     concptr q = _("どれを使いますか?", "Use which item? ");
243     concptr s = _("使えるものがありません。", "You have nothing to use.");
244     o_ptr = choose_object(
245         player_ptr, &item, q, s, (USE_INVEN | USE_EQUIP | USE_FLOOR | IGNORE_BOTHHAND_SLOT), FuncItemTester(item_tester_hook_use, player_ptr));
246     if (!o_ptr)
247         return;
248
249     switch (o_ptr->tval) {
250     case ItemKindType::SPIKE:
251         do_cmd_spike(player_ptr);
252         break;
253     case ItemKindType::FOOD:
254         exe_eat_food(player_ptr, item);
255         break;
256     case ItemKindType::WAND:
257         ObjectZapWandEntity(player_ptr).execute(item);
258         break;
259     case ItemKindType::STAFF:
260         ObjectUseEntity(player_ptr, item).execute();
261         break;
262     case ItemKindType::ROD:
263         ObjectZapRodEntity(player_ptr).execute(item);
264         break;
265     case ItemKindType::POTION:
266         ObjectQuaffEntity(player_ptr).execute(item);
267         break;
268     case ItemKindType::SCROLL:
269         if (cmd_limit_blind(player_ptr) || cmd_limit_confused(player_ptr))
270             return;
271
272         ObjectReadEntity(player_ptr, item).execute(true);
273         break;
274     case ItemKindType::SHOT:
275     case ItemKindType::ARROW:
276     case ItemKindType::BOLT:
277         exe_fire(player_ptr, item, &player_ptr->inventory_list[INVEN_BOW], SP_NONE);
278         break;
279     default:
280         exe_activate(player_ptr, item);
281         break;
282     }
283 }
284
285 /*!
286  * @brief 装備を発動するコマンドのメインルーチン /
287  * @param player_ptr プレイヤーへの参照ポインタ
288  */
289 void do_cmd_activate(PlayerType *player_ptr)
290 {
291     OBJECT_IDX item;
292     if (player_ptr->wild_mode || cmd_limit_arena(player_ptr))
293         return;
294
295     PlayerClass(player_ptr).break_samurai_stance({ SamuraiStanceType::MUSOU, SamuraiStanceType::KOUKIJIN });
296
297     concptr q = _("どのアイテムを始動させますか? ", "Activate which item? ");
298     concptr s = _("始動できるアイテムを装備していない。", "You have nothing to activate.");
299     if (!choose_object(player_ptr, &item, q, s, (USE_EQUIP | IGNORE_BOTHHAND_SLOT), FuncItemTester(&object_type::is_activatable)))
300         return;
301
302     exe_activate(player_ptr, item);
303 }