1 #include "inventory/item-getter.h"
2 #include "core/stuff-handler.h"
3 #include "core/window-redrawer.h"
4 #include "game-option/input-options.h"
5 #include "game-option/option-flags.h"
6 #include "game-option/text-display-options.h"
7 #include "inventory/floor-item-getter.h"
8 #include "inventory/inventory-slot-types.h"
9 #include "inventory/inventory-util.h"
10 #include "inventory/item-selection-util.h"
11 #include "io/command-repeater.h"
12 #include "io/input-key-acceptor.h"
13 #include "io/input-key-requester.h"
14 #include "main/sound-of-music.h"
15 #include "object/item-tester-hooker.h"
16 #include "object/item-use-flags.h"
17 #include "object/object-info.h"
18 #include "object/object-mark-types.h"
19 #include "player/player-status-flags.h"
20 #include "system/floor-type-definition.h"
21 #include "system/grid-type-definition.h"
22 #include "system/item-entity.h"
23 #include "system/player-type-definition.h"
24 #include "term/gameterm.h"
25 #include "term/screen-processor.h"
26 #include "term/z-form.h"
27 #include "util/int-char-converter.h"
28 #include "util/string-processor.h"
29 #include "view/display-inventory.h"
30 #include "view/display-messages.h"
31 #include "window/display-sub-windows.h"
34 * @brief オブジェクト選択のモード設定
35 * @param item_selection_ptr アイテム選択への参照ポインタ
37 static void check_item_selection_mode(item_selection_type *item_selection_ptr)
39 if (item_selection_ptr->mode & USE_EQUIP) {
40 item_selection_ptr->equip = true;
43 if (item_selection_ptr->mode & USE_INVEN) {
44 item_selection_ptr->inven = true;
47 if (item_selection_ptr->mode & USE_FLOOR) {
48 item_selection_ptr->floor = true;
53 * @brief アイテムへにタグ付けがされているかの調査処理 (のはず)
54 * @param player_ptr プレイヤーへの参照ポインタ
55 * @param item_selection_ptr アイテムへの参照ポインタ
56 * @return プレイヤーによりアイテムが選択されたならTRUEを返す
57 * @todo 適切な関数名をどうしても付けられなかったので暫定でauxとした
59 static bool check_item_tag_aux(PlayerType *player_ptr, item_selection_type *item_selection_ptr, const ItemTester &item_tester)
61 if (!item_selection_ptr->floor || (*item_selection_ptr->cp >= 0)) {
66 item_selection_ptr->k = 0 - (*item_selection_ptr->cp);
67 o_ptr = &player_ptr->current_floor_ptr->o_list[item_selection_ptr->k];
68 if (!item_tester.okay(o_ptr) && ((item_selection_ptr->mode & USE_FULL) == 0)) {
77 * @brief インベントリのアイテムにタグ付けがされているかの調査処理 (のはず)
78 * @param player_ptr プレイヤーへの参照ポインタ
79 * @param fis_ptr 床上アイテムへの参照ポインタ
80 * @param prev_tag 前回選択したアイテムのタグ (のはず)
81 * @return プレイヤーによりアイテムが選択されたならTRUEを返す
83 static bool check_item_tag_inventory(PlayerType *player_ptr, item_selection_type *item_selection_ptr, char *prev_tag, const ItemTester &item_tester)
85 if ((!item_selection_ptr->inven || (*item_selection_ptr->cp < 0) || (*item_selection_ptr->cp >= INVEN_PACK)) && (!item_selection_ptr->equip || (*item_selection_ptr->cp < INVEN_MAIN_HAND) || (*item_selection_ptr->cp >= INVEN_TOTAL))) {
89 if (*prev_tag && command_cmd) {
92 item_use_flag use_flag = (*item_selection_ptr->cp >= INVEN_MAIN_HAND) ? USE_EQUIP : USE_INVEN;
94 flag |= !get_tag(player_ptr, &item_selection_ptr->k, *prev_tag, use_flag, item_tester);
95 flag |= !get_item_okay(player_ptr, item_selection_ptr->k, item_tester);
97 if (item_selection_ptr->k < INVEN_MAIN_HAND) {
98 flag |= !item_selection_ptr->inven;
100 flag |= !item_selection_ptr->equip;
108 *item_selection_ptr->cp = item_selection_ptr->k;
113 if (!get_item_okay(player_ptr, *item_selection_ptr->cp, item_tester)) {
122 * @brief アイテムにタグ付けがされているかの調査処理 (のはず)
123 * @param player_ptr プレイヤーへの参照ポインタ
124 * @param item_selection_ptr アイテムへの参照ポインタ
125 * @param prev_tag 前回選択したアイテムのタグ (のはず)
126 * @return プレイヤーによりアイテムが選択されたならTRUEを返す
128 static bool check_item_tag(PlayerType *player_ptr, item_selection_type *item_selection_ptr, char *prev_tag, const ItemTester &item_tester)
130 if (!repeat_pull(item_selection_ptr->cp)) {
134 if (item_selection_ptr->mode & USE_FORCE && (*item_selection_ptr->cp == INVEN_FORCE)) {
139 if (check_item_tag_aux(player_ptr, item_selection_ptr, item_tester)) {
143 return check_item_tag_inventory(player_ptr, item_selection_ptr, prev_tag, item_tester);
147 * @brief インベントリ内のアイテムが妥当かを判定する
148 * @param player_ptr プレイヤーへの参照ポインタ
149 * @param fis_ptr アイテム選択への参照ポインタ
151 static void test_inventory(PlayerType *player_ptr, item_selection_type *item_selection_ptr, const ItemTester &item_tester)
153 if (!item_selection_ptr->inven) {
154 item_selection_ptr->i2 = -1;
162 for (int j = 0; j < INVEN_PACK; j++) {
163 if (item_tester.okay(&player_ptr->inventory_list[j]) || (item_selection_ptr->mode & USE_FULL)) {
164 item_selection_ptr->max_inven++;
170 * @brief 装備品が妥当かを判定する
171 * @param player_ptr プレイヤーへの参照ポインタ
172 * @param fis_ptr アイテム選択への参照ポインタ
174 static void test_equipment(PlayerType *player_ptr, item_selection_type *item_selection_ptr, const ItemTester &item_tester)
176 if (!item_selection_ptr->equip) {
177 item_selection_ptr->e2 = -1;
185 for (int j = INVEN_MAIN_HAND; j < INVEN_TOTAL; j++) {
186 if (player_ptr->select_ring_slot ? is_ring_slot(j)
187 : item_tester.okay(&player_ptr->inventory_list[j]) || (item_selection_ptr->mode & USE_FULL)) {
188 item_selection_ptr->max_equip++;
192 if (has_two_handed_weapons(player_ptr) && !(item_selection_ptr->mode & IGNORE_BOTHHAND_SLOT)) {
193 item_selection_ptr->max_equip++;
198 * @brief オブジェクト選択の汎用関数 / General function for the selection of item
199 * Let the user select an item, save its "index"
200 * @param player_ptr プレイヤーへの参照ポインタ
201 * @param cp 選択したオブジェクトのID
202 * @param pmt 選択目的のメッセージ
203 * @param str 選択できるオブジェクトがない場合のキャンセルメッセージ
204 * @param mode オプションフラグ
205 * @return プレイヤーによりアイテムが選択されたならTRUEを返す
206 * Return TRUE only if an acceptable item was chosen by the user
208 bool get_item(PlayerType *player_ptr, OBJECT_IDX *cp, concptr pmt, concptr str, BIT_FLAGS mode, const ItemTester &item_tester)
210 static char prev_tag = '\0';
211 if (easy_floor || use_menu) {
212 return get_item_floor(player_ptr, cp, pmt, str, mode, item_tester);
215 item_selection_type tmp_selection;
216 item_selection_type *item_selection_ptr = initialize_item_selection_type(&tmp_selection, cp, mode);
217 check_item_selection_mode(item_selection_ptr);
218 if (check_item_tag(player_ptr, item_selection_ptr, &prev_tag, item_tester)) {
223 item_selection_ptr->done = false;
224 item_selection_ptr->item = false;
225 item_selection_ptr->i1 = 0;
226 item_selection_ptr->i2 = INVEN_PACK - 1;
227 test_inventory(player_ptr, item_selection_ptr, item_tester);
228 while ((item_selection_ptr->i1 <= item_selection_ptr->i2) && (!get_item_okay(player_ptr, item_selection_ptr->i1, item_tester))) {
229 item_selection_ptr->i1++;
232 while ((item_selection_ptr->i1 <= item_selection_ptr->i2) && (!get_item_okay(player_ptr, item_selection_ptr->i2, item_tester))) {
233 item_selection_ptr->i2--;
236 item_selection_ptr->e1 = INVEN_MAIN_HAND;
237 item_selection_ptr->e2 = INVEN_TOTAL - 1;
238 test_equipment(player_ptr, item_selection_ptr, item_tester);
239 while ((item_selection_ptr->e1 <= item_selection_ptr->e2) && (!get_item_okay(player_ptr, item_selection_ptr->e1, item_tester))) {
240 item_selection_ptr->e1++;
243 while ((item_selection_ptr->e1 <= item_selection_ptr->e2) && (!get_item_okay(player_ptr, item_selection_ptr->e2, item_tester))) {
244 item_selection_ptr->e2--;
247 if (item_selection_ptr->equip && has_two_handed_weapons(player_ptr) && !(item_selection_ptr->mode & IGNORE_BOTHHAND_SLOT)) {
248 if (can_attack_with_main_hand(player_ptr)) {
249 if (item_selection_ptr->e2 < INVEN_SUB_HAND) {
250 item_selection_ptr->e2 = INVEN_SUB_HAND;
252 } else if (can_attack_with_sub_hand(player_ptr)) {
253 item_selection_ptr->e1 = INVEN_MAIN_HAND;
257 if (item_selection_ptr->floor) {
258 for (const auto this_o_idx : player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].o_idx_list) {
260 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
261 if ((item_tester.okay(o_ptr) || (item_selection_ptr->mode & USE_FULL)) && o_ptr->marked.has(OmType::FOUND)) {
262 item_selection_ptr->allow_floor = true;
267 if (!item_selection_ptr->allow_floor && (item_selection_ptr->i1 > item_selection_ptr->i2) && (item_selection_ptr->e1 > item_selection_ptr->e2)) {
269 item_selection_ptr->oops = true;
270 item_selection_ptr->done = true;
272 if (item_selection_ptr->mode & USE_FORCE) {
273 *item_selection_ptr->cp = INVEN_FORCE;
274 item_selection_ptr->item = true;
277 if (command_see && command_wrk && item_selection_ptr->equip) {
279 } else if (item_selection_ptr->inven) {
281 } else if (item_selection_ptr->equip) {
288 /* 追加オプション(always_show_list)が設定されている場合は常に一覧を表示する */
289 if (always_show_list || use_menu) {
297 while (!item_selection_ptr->done) {
298 COMMAND_CODE get_item_label = 0;
301 for (auto i = 0U; i < angband_terms.size(); ++i) {
302 if (!angband_terms[i]) {
306 if (window_flag[i] & (PW_INVEN)) {
310 if (window_flag[i] & (PW_EQUIP)) {
315 if ((command_wrk && ni && !ne) || (!command_wrk && !ni && ne)) {
316 toggle_inventory_equipment(player_ptr);
317 item_selection_ptr->toggle = !item_selection_ptr->toggle;
320 player_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
321 handle_stuff(player_ptr);
325 get_item_label = show_inventory(player_ptr, item_selection_ptr->menu_line, item_selection_ptr->mode, item_tester);
329 get_item_label = show_equipment(player_ptr, item_selection_ptr->menu_line, item_selection_ptr->mode, item_tester);
334 angband_strcpy(item_selection_ptr->out_val, _("持ち物:", "Inven:"), sizeof(item_selection_ptr->out_val));
335 if ((item_selection_ptr->i1 <= item_selection_ptr->i2) && !use_menu) {
337 strnfmt(tmp_val, sizeof(tmp_val), _("%c-%c,'(',')',", " %c-%c,'(',')',"), index_to_label(item_selection_ptr->i1), index_to_label(item_selection_ptr->i2));
338 angband_strcat(item_selection_ptr->out_val, tmp_val, sizeof(item_selection_ptr->out_val));
341 if (!command_see && !use_menu) {
342 angband_strcat(item_selection_ptr->out_val, _(" '*'一覧,", " * to see,"), sizeof(item_selection_ptr->out_val));
345 if (item_selection_ptr->equip) {
347 strnfmt(tmp_val, sizeof(tmp_val), _(" %s 装備品,", " %s for Equip,"), use_menu ? _("'4'or'6'", "4 or 6") : _("'/'", "/"));
348 angband_strcat(item_selection_ptr->out_val, tmp_val, sizeof(item_selection_ptr->out_val));
351 angband_strcpy(item_selection_ptr->out_val, _("装備品:", "Equip:"), sizeof(item_selection_ptr->out_val));
352 if ((item_selection_ptr->e1 <= item_selection_ptr->e2) && !use_menu) {
354 strnfmt(tmp_val, sizeof(tmp_val), _("%c-%c,'(',')',", " %c-%c,'(',')',"), index_to_label(item_selection_ptr->e1), index_to_label(item_selection_ptr->e2));
355 angband_strcat(item_selection_ptr->out_val, tmp_val, sizeof(item_selection_ptr->out_val));
358 if (!command_see && !use_menu) {
359 angband_strcat(item_selection_ptr->out_val, _(" '*'一覧,", " * to see,"), sizeof(item_selection_ptr->out_val));
362 if (item_selection_ptr->inven) {
364 strnfmt(tmp_val, sizeof(tmp_val), _(" %s 持ち物,", " %s for Inven,"), use_menu ? _("'4'or'6'", "4 or 6") : _("'/'", "'/'"));
365 angband_strcat(item_selection_ptr->out_val, tmp_val, sizeof(item_selection_ptr->out_val));
369 if (item_selection_ptr->allow_floor) {
370 angband_strcat(item_selection_ptr->out_val, _(" '-'床上,", " - for floor,"), sizeof(item_selection_ptr->out_val));
373 if (item_selection_ptr->mode & USE_FORCE) {
374 angband_strcat(item_selection_ptr->out_val, _(" 'w'練気術,", " w for the Force,"), sizeof(item_selection_ptr->out_val));
377 angband_strcat(item_selection_ptr->out_val, " ESC", sizeof(item_selection_ptr->out_val));
378 strnfmt(item_selection_ptr->tmp_val, sizeof(item_selection_ptr->tmp_val), "(%s) %s", item_selection_ptr->out_val, pmt);
379 prt(item_selection_ptr->tmp_val, 0, 0);
380 item_selection_ptr->which = inkey();
382 int max_line = (command_wrk ? item_selection_ptr->max_equip : item_selection_ptr->max_inven);
383 switch (item_selection_ptr->which) {
388 item_selection_ptr->done = true;
395 item_selection_ptr->menu_line += (max_line - 1);
402 item_selection_ptr->menu_line++;
412 if (!item_selection_ptr->inven || !item_selection_ptr->equip) {
422 command_wrk = !command_wrk;
423 max_line = (command_wrk ? item_selection_ptr->max_equip : item_selection_ptr->max_inven);
424 if (item_selection_ptr->menu_line > max_line) {
425 item_selection_ptr->menu_line = max_line;
435 if (command_wrk == USE_FLOOR) {
436 *item_selection_ptr->cp = -get_item_label;
438 if (!get_item_okay(player_ptr, get_item_label, item_tester)) {
443 if (!get_item_allow(player_ptr, get_item_label)) {
444 item_selection_ptr->done = true;
448 *item_selection_ptr->cp = get_item_label;
451 item_selection_ptr->item = true;
452 item_selection_ptr->done = true;
456 if (item_selection_ptr->mode & USE_FORCE) {
457 *item_selection_ptr->cp = INVEN_FORCE;
458 item_selection_ptr->item = true;
459 item_selection_ptr->done = true;
465 if (item_selection_ptr->menu_line > max_line) {
466 item_selection_ptr->menu_line -= max_line;
472 switch (item_selection_ptr->which) {
474 item_selection_ptr->done = true;
491 if (!item_selection_ptr->inven || !item_selection_ptr->equip) {
501 command_wrk = !command_wrk;
505 if (item_selection_ptr->allow_floor) {
506 for (const auto this_o_idx : player_ptr->current_floor_ptr->grid_array[player_ptr->y][player_ptr->x].o_idx_list) {
508 o_ptr = &player_ptr->current_floor_ptr->o_list[this_o_idx];
509 if (!item_tester.okay(o_ptr) && !(item_selection_ptr->mode & USE_FULL)) {
513 item_selection_ptr->k = 0 - this_o_idx;
514 if ((other_query_flag && !verify(player_ptr, _("本当に", "Try"), item_selection_ptr->k)) || !get_item_allow(player_ptr, item_selection_ptr->k)) {
518 *item_selection_ptr->cp = item_selection_ptr->k;
519 item_selection_ptr->item = true;
520 item_selection_ptr->done = true;
524 if (item_selection_ptr->done) {
542 if (!get_tag(player_ptr, &item_selection_ptr->k, item_selection_ptr->which, command_wrk ? USE_EQUIP : USE_INVEN, item_tester)) {
547 if ((item_selection_ptr->k < INVEN_MAIN_HAND) ? !item_selection_ptr->inven : !item_selection_ptr->equip) {
552 if (!get_item_okay(player_ptr, item_selection_ptr->k, item_tester)) {
557 if (!get_item_allow(player_ptr, item_selection_ptr->k)) {
558 item_selection_ptr->done = true;
562 *item_selection_ptr->cp = item_selection_ptr->k;
563 item_selection_ptr->item = true;
564 item_selection_ptr->done = true;
565 item_selection_ptr->cur_tag = item_selection_ptr->which;
569 if (item_selection_ptr->mode & USE_FORCE) {
570 *item_selection_ptr->cp = INVEN_FORCE;
571 item_selection_ptr->item = true;
572 item_selection_ptr->done = true;
578 bool tag_not_found = false;
580 if (!get_tag(player_ptr, &item_selection_ptr->k, item_selection_ptr->which, command_wrk ? USE_EQUIP : USE_INVEN, item_tester)) {
581 tag_not_found = true;
582 } else if ((item_selection_ptr->k < INVEN_MAIN_HAND) ? !item_selection_ptr->inven : !item_selection_ptr->equip) {
583 tag_not_found = true;
586 if (!tag_not_found) {
587 item_selection_ptr->cur_tag = item_selection_ptr->which;
589 auto which = (char)tolower(item_selection_ptr->which);
593 item_selection_ptr->k = item_selection_ptr->i1;
594 } else if (which == ')') {
595 item_selection_ptr->k = item_selection_ptr->i2;
597 item_selection_ptr->k = label_to_inventory(player_ptr, which);
601 item_selection_ptr->k = item_selection_ptr->e1;
602 } else if (which == ')') {
603 item_selection_ptr->k = item_selection_ptr->e2;
605 item_selection_ptr->k = label_to_equipment(player_ptr, which);
610 if (!get_item_okay(player_ptr, item_selection_ptr->k, item_tester)) {
615 auto ver = tag_not_found && isupper(item_selection_ptr->which);
616 if (ver && !verify(player_ptr, _("本当に", "Try"), item_selection_ptr->k)) {
617 item_selection_ptr->done = true;
621 if (!get_item_allow(player_ptr, item_selection_ptr->k)) {
622 item_selection_ptr->done = true;
626 *item_selection_ptr->cp = item_selection_ptr->k;
627 item_selection_ptr->item = true;
628 item_selection_ptr->done = true;
639 if (item_selection_ptr->toggle) {
640 toggle_inventory_equipment(player_ptr);
643 player_ptr->window_flags |= (PW_INVEN | PW_EQUIP);
644 handle_stuff(player_ptr);
646 if (item_selection_ptr->oops && str) {
650 if (item_selection_ptr->item) {
651 repeat_push(*item_selection_ptr->cp);
653 prev_tag = item_selection_ptr->cur_tag;
658 return item_selection_ptr->item;