/** * Let the user select an object, save its address * * Return true only if an acceptable item was chosen by the user. * * The user is allowed to choose acceptable items from the equipment, * inventory, quiver, or floor, respectively, if the proper flag was given, * and there are any acceptable items in that location. * * The equipment, inventory or quiver are displayed (even if no acceptable * items are in that location) if the proper flag was given. * * If there are no acceptable items available anywhere, and "str" is * not NULL, then it will be used as the text of a warning message * before the function returns. * * If a legal item is selected , we save it in "choice" and return true. * * If no item is available, we do nothing to "choice", and we display a * warning message, using "str" if available, and return false. * * If no item is selected, we do nothing to "choice", and return false. * * Global "player->upkeep->command_wrk" is used to choose between * equip/inven/quiver/floor listings. It is equal to USE_INVEN or USE_EQUIP or * USE_QUIVER or USE_FLOOR, except when this function is first called, when it * is equal to zero, which will cause it to be set to USE_INVEN. * * We always erase the prompt when we are done, leaving a blank line, * or a warning message, if appropriate, if no items are available. * * Note that only "acceptable" floor objects get indexes, so between two * commands, the indexes of floor objects may change. XXX XXX XXX */ bool textui_get_item(struct object **choice, const char *pmt, const char *str, cmd_code cmd, item_tester tester, int mode) { bool use_inven = ((mode & USE_INVEN) ? true : false); bool use_equip = ((mode & USE_EQUIP) ? true : false); bool use_quiver = ((mode & USE_QUIVER) ? true : false); bool use_floor = ((mode & USE_FLOOR) ? true : false); bool quiver_tags = ((mode & QUIVER_TAGS) ? true : false); bool allow_inven = false; bool allow_equip = false; bool allow_quiver = false; bool allow_floor = false; bool toggle = false; int floor_max = z_info->floor_size; int floor_num; floor_list = mem_zalloc(floor_max * sizeof(*floor_list)); olist_mode = 0; item_mode = mode; item_cmd = cmd; tester_m = tester; prompt = pmt; allow_all = str ? false : true; /* Object list display modes */ if (mode & SHOW_FAIL) olist_mode |= OLIST_FAIL; else olist_mode |= OLIST_WEIGHT; if (mode & SHOW_PRICES) olist_mode |= OLIST_PRICE; if (mode & SHOW_EMPTY) olist_mode |= OLIST_SEMPTY; if (mode & SHOW_QUIVER) olist_mode |= OLIST_QUIVER; if (mode & SHOW_RECHARGE) olist_mode |= OLIST_RECHARGE; /* Paranoia XXX XXX XXX */ event_signal(EVENT_MESSAGE_FLUSH); /* Full inventory */ i1 = 0; i2 = z_info->pack_size - 1; /* Forbid inventory */ if (!use_inven) i2 = -1; /* Restrict inventory indexes */ while ((i1 <= i2) && (!object_test(tester, player->upkeep->inven[i1]))) i1++; while ((i1 <= i2) && (!object_test(tester, player->upkeep->inven[i2]))) i2--; /* Accept inventory */ if ((i1 <= i2) || allow_all) allow_inven = true; else if (item_mode & USE_INVEN) item_mode -= USE_INVEN; /* Full equipment */ e1 = 0; e2 = player->body.count - 1; /* Forbid equipment */ if (!use_equip) e2 = -1; /* Restrict equipment indexes unless starting with no command */ if ((cmd != CMD_NULL) || (tester != NULL)) { while ((e1 <= e2) && (!object_test(tester, slot_object(player, e1)))) e1++; while ((e1 <= e2) && (!object_test(tester, slot_object(player, e2)))) e2--; } /* Accept equipment */ if ((e1 <= e2) || allow_all) allow_equip = true; else if (item_mode & USE_EQUIP) item_mode -= USE_EQUIP; /* Restrict quiver indexes */ q1 = 0; q2 = z_info->quiver_size - 1; /* Forbid quiver */ if (!use_quiver) q2 = -1; /* Restrict quiver indexes */ while ((q1 <= q2) && (!object_test(tester, player->upkeep->quiver[q1]))) q1++; while ((q1 <= q2) && (!object_test(tester, player->upkeep->quiver[q2]))) q2--; /* Accept quiver */ if ((q1 <= q2) || allow_all) allow_quiver = true; else if (item_mode & USE_QUIVER) item_mode -= USE_QUIVER; /* Scan all non-gold objects in the grid */ floor_num = scan_floor(floor_list, floor_max, OFLOOR_TEST | OFLOOR_SENSE | OFLOOR_VISIBLE, tester); /* Full floor */ f1 = 0; f2 = floor_num - 1; /* Forbid floor */ if (!use_floor) f2 = -1; /* Restrict floor indexes */ while ((f1 <= f2) && (!object_test(tester, floor_list[f1]))) f1++; while ((f1 <= f2) && (!object_test(tester, floor_list[f2]))) f2--; /* Accept floor */ if ((f1 <= f2) || allow_all) allow_floor = true; else if (item_mode & USE_FLOOR) item_mode -= USE_FLOOR; /* Require at least one legal choice */ if (allow_inven || allow_equip || allow_quiver || allow_floor) { /* Start where requested if possible */ if ((player->upkeep->command_wrk == USE_EQUIP) && allow_equip) player->upkeep->command_wrk = USE_EQUIP; else if ((player->upkeep->command_wrk == USE_INVEN) && allow_inven) player->upkeep->command_wrk = USE_INVEN; else if ((player->upkeep->command_wrk == USE_QUIVER) && allow_quiver) player->upkeep->command_wrk = USE_QUIVER; else if ((player->upkeep->command_wrk == USE_FLOOR) && allow_floor) player->upkeep->command_wrk = USE_FLOOR; /* If we are obviously using the quiver then start on quiver */ else if (quiver_tags && allow_quiver) player->upkeep->command_wrk = USE_QUIVER; /* Otherwise choose whatever is allowed */ else if (use_inven && allow_inven) player->upkeep->command_wrk = USE_INVEN; else if (use_equip && allow_equip) player->upkeep->command_wrk = USE_EQUIP; else if (use_quiver && allow_quiver) player->upkeep->command_wrk = USE_QUIVER; else if (use_floor && allow_floor) player->upkeep->command_wrk = USE_FLOOR; /* If nothing to choose, use (empty) inventory */ else player->upkeep->command_wrk = USE_INVEN; while (true) { int j; int ni = 0; int ne = 0; /* If inven or equip is on the main screen, and only one of them * is slated for a subwindow, we should show the opposite there */ for (j = 0; j < ANGBAND_TERM_MAX; j++) { /* Unused */ if (!angband_term[j]) continue; /* Count windows displaying inven */ if (window_flag[j] & (PW_INVEN)) ni++; /* Count windows displaying equip */ if (window_flag[j] & (PW_EQUIP)) ne++; } /* Are we in the situation where toggling makes sense? */ if ((ni && !ne) || (!ni && ne)) { if (player->upkeep->command_wrk == USE_EQUIP) { if ((ne && !toggle) || (ni && toggle)) { /* Main screen is equipment, so is subwindow */ toggle_inven_equip(); toggle = !toggle; } } else if (player->upkeep->command_wrk == USE_INVEN) { if ((ni && !toggle) || (ne && toggle)) { /* Main screen is inventory, so is subwindow */ toggle_inven_equip(); toggle = !toggle; } } else { /* Quiver or floor, go back to the original */ if (toggle) { toggle_inven_equip(); toggle = !toggle; } } } /* Redraw */ player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); /* Redraw windows */ redraw_stuff(player); /* Save screen */ screen_save(); /* Build object list */ wipe_obj_list(); if (player->upkeep->command_wrk == USE_INVEN) build_obj_list(i2, player->upkeep->inven, tester_m, olist_mode); else if (player->upkeep->command_wrk == USE_EQUIP) build_obj_list(e2, NULL, tester_m, olist_mode); else if (player->upkeep->command_wrk == USE_QUIVER) build_obj_list(q2, player->upkeep->quiver, tester_m,olist_mode); else if (player->upkeep->command_wrk == USE_FLOOR) build_obj_list(f2, floor_list, tester_m, olist_mode); /* Show the prompt */ menu_header(); if (pmt) { prt(pmt, 0, 0); prt(header, 0, strlen(pmt) + 1); } /* No menu change request */ newmenu = false; /* Get an item choice */ *choice = item_menu(cmd, MAX(pmt ? strlen(pmt) : 0, 15), mode); /* Fix the screen */ screen_load(); /* Update */ player->upkeep->redraw |= (PR_INVEN | PR_EQUIP); redraw_stuff(player); /* Clear the prompt line */ prt("", 0, 0); /* We have a selection, or are backing out */ if (*choice || !newmenu) { if (toggle) toggle_inven_equip(); break; } } } else { /* Warning if needed */ if (str) msg("%s", str); *choice = NULL; } /* Clean up */ player->upkeep->command_wrk = 0; mem_free(floor_list); /* Result */ return (*choice != NULL) ? true : false; }
/** * Let the user select an item, save its "index" * * Return TRUE only if an acceptable item was chosen by the user. * * The selected item must satisfy the "item_tester_hook()" function, * if that hook is set, and the "item_tester_tval", if that value is set. * * All "item_tester" restrictions are cleared before this function returns. * * The user is allowed to choose acceptable items from the equipment, * inventory, or floor, respectively, if the proper flag was given, * and there are any acceptable items in that location. * * The equipment or inventory are displayed (even if no acceptable * items are in that location) if the proper flag was given. * * If there are no acceptable items available anywhere, and "str" is * not NULL, then it will be used as the text of a warning message * before the function returns. * * Note that the user must press "-" to specify the item on the floor, * and there is no way to "examine" the item on the floor, while the * use of "capital" letters will "examine" an inventory/equipment item, * and prompt for its use. * * If a legal item is selected from the inventory, we save it in "cp" * directly (0 to 35), and return TRUE. * * If a legal item is selected from the floor, we save it in "cp" as * a negative (-1 to -511), and return TRUE. * * If no item is available, we do nothing to "cp", and we display a * warning message, using "str" if available, and return FALSE. * * If no item is selected, we do nothing to "cp", and return FALSE. * * Global "p_ptr->command_wrk" is used to choose between equip/inven/floor * listings. It is equal to USE_INVEN or USE_EQUIP or USE_FLOOR, except * when this function is first called, when it is equal to zero, which will * cause it to be set to USE_INVEN. * * We always erase the prompt when we are done, leaving a blank line, * or a warning message, if appropriate, if no items are available. * * Note that only "acceptable" floor objects get indexes, so between two * commands, the indexes of floor objects may change. XXX XXX XXX */ bool get_item(int *cp, const char *pmt, const char *str, cmd_code cmd, int mode) { s16b py = p_ptr->py; s16b px = p_ptr->px; unsigned char cmdkey = cmd_lookup_key(cmd, KEYMAP_MODE_ORIG); bool done, item; int j, k; bool oops = FALSE; bool toggle = FALSE; bool use_inven = ((mode & USE_INVEN) ? TRUE : FALSE); bool use_equip = ((mode & USE_EQUIP) ? TRUE : FALSE); bool use_floor = ((mode & (USE_FLOOR | USE_TARGET)) ? TRUE : FALSE); bool use_quiver = ((mode & QUIVER_TAGS) ? TRUE : FALSE); bool can_squelch = ((mode & CAN_SQUELCH) ? TRUE : FALSE); bool is_harmless = ((mode & IS_HARMLESS) ? TRUE : FALSE); bool quiver_tags = ((mode & QUIVER_TAGS) ? TRUE : FALSE); bool allow_inven = FALSE; bool allow_equip = FALSE; bool allow_floor = FALSE; int floor_num; ui_event which; prompt = pmt; olist_mode = 0; item_mode = mode; item_cmd = cmd; /* Not done */ done = FALSE; /* No item selected */ item = FALSE; *cp = 0; /* Object list display modes */ if (mode & SHOW_FAIL) olist_mode |= (OLIST_FAIL); else olist_mode |= (OLIST_WEIGHT); if (mode & SHOW_PRICES) olist_mode |= (OLIST_PRICE); show_list = OPT(show_lists) ? TRUE : FALSE; /* Set target for telekinesis */ if (mode & (USE_TARGET)) { target_get(&px, &py); if (!(px && py)) return FALSE; } /* Full inventory */ i1 = 0; i2 = INVEN_PACK - 1; /* Forbid inventory */ if (!use_inven) i2 = -1; /* Restrict inventory indexes */ while ((i1 <= i2) && (!get_item_okay(i1))) i1++; while ((i1 <= i2) && (!get_item_okay(i2))) i2--; /* Accept inventory */ if (i1 <= i2) allow_inven = TRUE; /* Full equipment */ e1 = INVEN_WIELD; e2 = ALL_INVEN_TOTAL - 1; /* Forbid equipment */ if (!use_equip) e2 = -1; /* Restrict equipment indexes */ while ((e1 <= e2) && (!get_item_okay(e1))) e1++; while ((e1 <= e2) && (!get_item_okay(e2))) e2--; /* Accept equipment */ if (e1 <= e2) allow_equip = TRUE; /* Reject quiver */ if (e2 < QUIVER_START) use_quiver = FALSE; /* Scan all non-gold objects in the grid */ floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), py, px, 0x03); /* Full floor */ f1 = 0; f2 = floor_num - 1; /* Forbid floor */ if (!use_floor) f2 = -1; /* Restrict floor indexes */ while ((f1 <= f2) && (!get_item_okay(0 - floor_list[f1]))) f1++; while ((f1 <= f2) && (!get_item_okay(0 - floor_list[f2]))) f2--; /* Accept floor */ if (f1 <= f2) allow_floor = TRUE; /* Require at least one legal choice */ if (!allow_inven && !allow_equip && !allow_floor) { /* Oops */ oops = TRUE; done = TRUE; } /* Analyze choices, prepare for initial menu */ else { /* Hack -- Start on equipment if requested */ if ((p_ptr->command_wrk == USE_EQUIP) && use_equip){ p_ptr->command_wrk = USE_EQUIP; build_obj_list(INVEN_WIELD, e2, NULL, olist_mode); } /* If we are using the quiver then start on equipment */ else if (use_quiver){ p_ptr->command_wrk = USE_EQUIP; build_obj_list(INVEN_WIELD, e2, NULL, olist_mode); } /* Use inventory if allowed */ else if (use_inven){ p_ptr->command_wrk = USE_INVEN; build_obj_list(0, i2, NULL, olist_mode); } /* Use equipment if allowed */ else if (use_equip){ p_ptr->command_wrk = USE_EQUIP; build_obj_list(INVEN_WIELD, e2, NULL, olist_mode); } /* Use floor if allowed */ else if (use_floor){ p_ptr->command_wrk = USE_FLOOR; build_obj_list(0, f2, floor_list, olist_mode); } /* Hack -- Use (empty) inventory */ else { p_ptr->command_wrk = USE_INVEN; build_obj_list(0, i2, NULL, olist_mode); } } /* Clear all current messages */ msg_flag = FALSE; /* Start out in "display" mode */ if (show_list) { /* Save screen */ screen_save(); } /* Repeat until done */ while (!done) { static bool refresh; int ni = 0; int ne = 0; /* Scan windows */ for (j = 0; j < ANGBAND_TERM_MAX; j++) { /* Unused */ if (!angband_term[j]) continue; /* Count windows displaying inven */ if (op_ptr->window_flag[j] & (PW_INVEN)) ni++; /* Count windows displaying equip */ if (op_ptr->window_flag[j] & (PW_EQUIP)) ne++; } /* Toggle if needed */ if (((p_ptr->command_wrk == USE_EQUIP) && ni && !ne) || ((p_ptr->command_wrk == USE_INVEN) && !ni && ne)) { /* Toggle */ toggle_inven_equip(); /* Track toggles */ toggle = !toggle; } /* Redraw */ p_ptr->redraw |= (PR_INVEN | PR_EQUIP); /* Redraw windows */ redraw_stuff(p_ptr); /* Change the list if needed */ if (refresh) { /* Rebuild object list */ if (p_ptr->command_wrk == USE_INVEN) build_obj_list(0, i2, NULL, olist_mode); else if (p_ptr->command_wrk == USE_EQUIP) build_obj_list(INVEN_WIELD, e2, NULL, olist_mode); else build_obj_list(0, f2, floor_list, mode); refresh = FALSE; } /* Show the prompt */ item_prompt(mode); redraw_stuff(p_ptr); /* Menu if requested */ if (show_list) { which = item_menu(cmd, mode); if (which.type == EVT_ESCAPE) which.key.code = ESCAPE; } /* Get a key */ else which = inkey_ex(); /* Parse it */ switch (which.key.code) { case ESCAPE: { done = TRUE; break; } case '*': case '?': case ' ': { if (!OPT(show_lists)) { /* Save screen */ screen_save(); /* Flip flag */ show_list = TRUE; } refresh = TRUE; break; } case '/': { /* Toggle to inventory */ if (use_inven && (p_ptr->command_wrk != USE_INVEN)) { p_ptr->command_wrk = USE_INVEN; refresh = TRUE; } /* Toggle to equipment */ else if (use_equip && (p_ptr->command_wrk != USE_EQUIP)) { p_ptr->command_wrk = USE_EQUIP; refresh = TRUE; } /* No toggle allowed */ else { bell("Cannot switch item selector!"); break; } /* Need to redraw */ break; } case '-': { /* Paranoia */ if (!allow_floor) { bell("Cannot select floor!"); break; } /* There is only one item */ if (OPT(pickup_single) && (floor_num == 1)) { /* Fall through */ } else { p_ptr->command_wrk = (USE_FLOOR); refresh = TRUE; break; } } case '.': { /* * If we are allow to use the floor, select * the top item. -BR- */ if (allow_floor) { int k; /* Special index */ k = 0 - floor_list[0]; /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; } break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { /* Look up the tag */ if (!get_tag(&k, which.key.code, cmd, quiver_tags)) { bell("Illegal object choice (tag)!"); break; } /* Hack -- Validate the item */ if ((k < INVEN_WIELD) ? !allow_inven : !allow_equip) { bell("Illegal object choice (tag)!"); break; } /* Validate the item */ if (!get_item_okay(k)) { bell("Illegal object choice (tag)!"); break; } /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } case KC_ENTER: { /* Choose "default" inventory item */ if (p_ptr->command_wrk == USE_INVEN) { if (i1 != i2) { bell("Illegal object choice (default)!"); break; } k = i1; } /* Choose the "default" slot (0) of the quiver */ else if (quiver_tags) k = e1; /* Choose "default" equipment item */ else if (p_ptr->command_wrk == USE_EQUIP) { if (e1 != e2) { bell("Illegal object choice (default)!"); break; } k = e1; } /* Choose "default" floor item */ else { if (f1 != f2) { bell("Illegal object choice (default)!"); break; } k = 0 - floor_list[f1]; } /* Validate the item */ if (!get_item_okay(k)) { bell("Illegal object choice (default)!"); break; } /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } case '!': { /* Try squelched items */ if (can_squelch) { (*cp) = ALL_SQUELCHED; item = TRUE; done = TRUE; break; } /* Just fall through */ } default: { bool verify; /* Note verify */ verify = (isupper((unsigned char) which.key.code) ? TRUE : FALSE); /* Lowercase */ which.key.code = tolower((unsigned char) which.key.code); /* Convert letter to inventory index */ if (p_ptr->command_wrk == USE_INVEN) { k = label_to_inven(which.key.code); if (k < 0) { bell("Illegal object choice (inven)!"); break; } } /* Convert letter to equipment index */ else if (p_ptr->command_wrk == USE_EQUIP) { k = label_to_equip(which.key.code); if (k < 0) { bell("Illegal object choice (equip)!"); break; } } /* Convert letter to floor index */ else { k = (islower((unsigned char) which.key.code) ? A2I((unsigned char)which.key.code) : -1); if (k < 0 || k >= floor_num) { bell("Illegal object choice (floor)!"); break; } /* Special index */ k = 0 - floor_list[k]; } /* Validate the item */ if (!get_item_okay(k)) { bell("Illegal object choice (normal)!"); break; } /* Verify the item */ if (verify && !verify_item("Try", k)) { done = TRUE; break; } /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } } } /* Fix the screen if necessary */ if (show_list) { /* Load screen */ screen_load(); /* Hack -- Cancel "display" */ show_list = FALSE; } /* Kill buttons */ button_kill('*'); button_kill('/'); button_kill('-'); button_kill('!'); /* Forget the item_tester_tval restriction */ item_tester_tval = 0; /* Forget the item_tester_hook restriction */ item_tester_hook = NULL; /* Toggle again if needed */ if (toggle) toggle_inven_equip(); /* Update */ p_ptr->redraw |= (PR_INVEN | PR_EQUIP); redraw_stuff(p_ptr); /* Clear the prompt line */ prt("", 0, 0); /* Warning if needed */ if (oops && str) msg(str); /* Result */ return (item); }