/* ------------------------------------------------------------------------ * Quickstart? screen. * ------------------------------------------------------------------------ */ static enum birth_stage get_quickstart_command(void) { const char *prompt = "['Y' to use this character, 'N' to start afresh, 'C' to change name]"; enum birth_stage next = BIRTH_QUICKSTART; /* Prompt for it */ prt("New character based on previous one:", 0, 0); prt(prompt, Term->hgt - 1, Term->wid / 2 - strlen(prompt) / 2); /* Buttons */ button_kill_all(); button_add("[Y]", 'y'); button_add("[N]", 'n'); button_add("[C]", 'c'); redraw_stuff(p_ptr); do { /* Get a key */ struct keypress ke = inkey(); if (ke.code == 'N' || ke.code == 'n') { cmd_insert(CMD_BIRTH_RESET); next = BIRTH_SEX_CHOICE; } else if (ke.code == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } else if (ke.code == 'C' || ke.code == 'c') { next = BIRTH_NAME_CHOICE; } else if (ke.code == 'Y' || ke.code == 'y') { cmd_insert(CMD_ACCEPT_CHARACTER); next = BIRTH_COMPLETE; } } while (next == BIRTH_QUICKSTART); /* Buttons */ button_kill_all(); redraw_stuff(p_ptr); /* Clear prompt */ clear_from(23); return next; }
/* * Ask the user to respond with a character. Options is a constant string, * e.g. "yns"; len is the length of the constant string, and fallback should * be the default answer if the user hits escape or an invalid key. * * Example: get_char("Study? ", "yns", 3, 'n') * This prompts "Study? [yns]" and defaults to 'n'. * */ char get_char(const char *prompt, const char *options, size_t len, char fallback) { size_t i; struct keypress key; char button[4], buf[80]; bool repeat = FALSE; /* Paranoia XXX XXX XXX */ message_flush(); /* Hack -- Build a "useful" prompt */ strnfmt(buf, 78, "%.70s[%s] ", prompt, options); /* Hack - kill the repeat button */ if (button_kill('n')) repeat = TRUE; /* Make some buttons */ for (i = 0; i < len; i++) { strnfmt(button, 4, "[%c]", options[i]); button_add(button, options[i]); } redraw_stuff(p_ptr); /* Prompt for it */ prt(buf, 0, 0); /* Get an acceptable answer */ key = inkey(); /* Lowercase answer if necessary */ if (key.code >= 'A' && key.code <= 'Z') key.code += 32; /* See if key is in our options string */ if (!strchr(options, (char)key.code)) key.code = fallback; /* Kill the buttons */ for (i = 0; i < len; i++) button_kill(options[i]); /* Hack - restore the repeat button */ if (repeat) button_add("[Rpt]", 'n'); redraw_stuff(p_ptr); /* Erase the prompt */ prt("", 0, 0); /* Success */ return key.code; }
/* ------------------------------------------------------------------------ * Final confirmation of character. * ------------------------------------------------------------------------ */ static enum birth_stage get_confirm_command(void) { const char *prompt = "['ESC' to step back, 'S' to start over, or any other key to continue]"; struct keypress ke; enum birth_stage next; /* Prompt for it */ prt(prompt, Term->hgt - 1, Term->wid / 2 - strlen(prompt) / 2); /* Buttons */ button_kill_all(); button_add("[Continue]", 'q'); button_add("[ESC]", ESCAPE); button_add("[S]", 'S'); redraw_stuff(p_ptr); /* Get a key */ ke = inkey(); /* Start over */ if (ke.code == 'S' || ke.code == 's') { next = BIRTH_RESET; } else if (ke.code == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } else if (ke.code == ESCAPE) { next = BIRTH_BACK; } else { cmd_insert(CMD_ACCEPT_CHARACTER); next = BIRTH_COMPLETE; } /* Buttons */ button_kill_all(); redraw_stuff(p_ptr); /* Clear prompt */ clear_from(23); return next; }
/** * Modify the current panel to the given coordinates, adjusting only to * ensure the coordinates are legal, and return TRUE if anything done. * * The town should never be scrolled around. * * Note that monsters are no longer affected in any way by panel changes. * * As a total hack, whenever the current panel changes, we assume that * the "overhead view" window should be updated. */ bool modify_panel(term *t, int wy, int wx) { int dungeon_hgt = cave->height; int dungeon_wid = cave->width; /* Verify wy, adjust if needed */ if (wy > dungeon_hgt - SCREEN_HGT) wy = dungeon_hgt - SCREEN_HGT; if (wy < 0) wy = 0; /* Verify wx, adjust if needed */ if (wx > dungeon_wid - SCREEN_WID) wx = dungeon_wid - SCREEN_WID; if (wx < 0) wx = 0; /* React to changes */ if (panel_should_modify(t, wy, wx)) { /* Save wy, wx */ t->offset_y = wy; t->offset_x = wx; /* Redraw map */ player->upkeep->redraw |= (PR_MAP); /* Redraw for big graphics */ if ((tile_width > 1) || (tile_height > 1)) redraw_stuff(player); /* Changed */ return (TRUE); } /* No change */ return (FALSE); }
/* * Modify the current panel to the given coordinates, adjusting only to * ensure the coordinates are legal, and return TRUE if anything done. * * The town should never be scrolled around. * * Note that monsters are no longer affected in any way by panel changes. * * As a total hack, whenever the current panel changes, we assume that * the "overhead view" window should be updated. */ bool modify_panel(term *t, int wy, int wx) { int dungeon_hgt = (p_ptr->depth == 0) ? TOWN_HGT : DUNGEON_HGT; int dungeon_wid = (p_ptr->depth == 0) ? TOWN_WID : DUNGEON_WID; /* Verify wy, adjust if needed */ if (wy > dungeon_hgt - SCREEN_HGT) wy = dungeon_hgt - SCREEN_HGT; if (wy < 0) wy = 0; /* Verify wx, adjust if needed */ if (wx > dungeon_wid - SCREEN_WID) wx = dungeon_wid - SCREEN_WID; if (wx < 0) wx = 0; /* React to changes */ if ((t->offset_y != wy) || (t->offset_x != wx)) { /* Save wy, wx */ t->offset_y = wy; t->offset_x = wx; /* Redraw map */ p_ptr->redraw |= (PR_MAP); /* Redraw for big graphics */ if ((tile_width > 1) || (tile_height > 1)) redraw_stuff(p_ptr); /* Changed */ return (TRUE); } /* No change */ return (FALSE); }
/* * Verify something with the user * * The "prompt" should take the form "Query? " * * Note that "[y/n]" is appended to the prompt. */ bool get_check(const char *prompt) { //struct keypress ke; ui_event ke; char buf[80]; bool repeat = FALSE; /* Paranoia XXX XXX XXX */ message_flush(); /* Hack -- Build a "useful" prompt */ strnfmt(buf, 78, "%.70s[y/n] ", prompt); /* Hack - kill the repeat button */ if (button_kill('n')) repeat = TRUE; /* Make some buttons */ button_add("[y]", 'y'); button_add("[n]", 'n'); redraw_stuff(p_ptr); /* Prompt for it */ prt(buf, 0, 0); ke = inkey_m(); /* Kill the buttons */ button_kill('y'); button_kill('n'); /* Hack - restore the repeat button */ if (repeat) button_add("[Rpt]", 'n'); redraw_stuff(p_ptr); /* Erase the prompt */ prt("", 0, 0); /* Normal negation */ if (ke.type == EVT_MOUSE) { if ((ke.mouse.button != 1) && (ke.mouse.y != 0)) return (FALSE); } else if ((ke.key.code != 'Y') && (ke.key.code != 'y')) return (FALSE); /* Success */ return (TRUE); }
/** * Save the screen, and increase the "icky" depth. */ void screen_save(void) { player->upkeep->redraw |= PR_MAP; redraw_stuff(player); event_signal(EVENT_MESSAGE_FLUSH); Term_save(); screen_save_depth++; }
/* * Handle "p_ptr->update" and "p_ptr->redraw" */ void handle_stuff(void) { /* Update stuff */ if (p_ptr->update) update_stuff(); /* Redraw stuff */ if (p_ptr->redraw) redraw_stuff(); }
/** * Housekeeping on leaving a level */ static void on_leave_level(void) { /* Any pending processing */ notice_stuff(player); update_stuff(player); redraw_stuff(player); /* Flush messages */ event_signal(EVENT_MESSAGE_FLUSH); }
/* ------------------------------------------------------------------------ * Quickstart? screen. * ------------------------------------------------------------------------ */ static enum birth_stage get_quickstart_command(void) { const char *prompt = "['Y' to use this character, 'N' to start afresh, 'C' to change name]"; ui_event_data ke; enum birth_stage next = BIRTH_QUICKSTART; /* Prompt for it */ prt("New character based on previous one:", 0, 0); prt(prompt, Term->hgt - (mouse_buttons ? 2 : 1), Term->wid / 2 - strlen(prompt) / 2); /* Buttons */ button_kill_all(); button_add("[YES]", 'y'); button_add("[START_OVER]", 'n'); button_add("[CHANGE_NAME]", 'c'); redraw_stuff(); event_signal(EVENT_MOUSEBUTTONS); do { /* Get a key */ ke = inkey_ex(); if (ke.key == 'N' || ke.key == 'n') { cmd_insert(CMD_BIRTH_RESET, TRUE); next = BIRTH_SEX_CHOICE; } else if (ke.key == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } else if (ke.key == 'C' || ke.key == 'c') { next = BIRTH_NAME_CHOICE; } else if (ke.key == 'Y' || ke.key == 'y') { cmd_insert(CMD_ACCEPT_CHARACTER); next = BIRTH_COMPLETE; } } while (next == BIRTH_QUICKSTART); /* Buttons */ button_kill_all(); handle_stuff(); event_signal(EVENT_MOUSEBUTTONS); /* Clear prompt */ clear_from(23); return next; }
/* * Handle "p_ptr->update" and "p_ptr->redraw" and "p_ptr->window" */ void handle_stuff(void) { /* Update stuff */ if (p_ptr->update) update_stuff(); /* Redraw stuff */ if (flag_used(&p_ptr->redraw)) redraw_stuff(); /* Window stuff */ if (flag_used(&p_ptr->window)) window_stuff(); }
/* * Look command */ void do_cmd_look(void) { if (!character_dungeon) return; /* Look around */ if (target_set_interactive(TARGET_LOOK, -1, -1)) { message("Target Selected."); p_ptr->redraw |= (PR_SIDEBAR_MON); redraw_stuff(); } }
/** * Housekeeping after the processing of a player command */ static void process_player_cleanup(void) { int i; /* Significant */ if (player->upkeep->energy_use) { /* Use some energy */ player->energy -= player->upkeep->energy_use; /* Increment the total energy counter */ player->total_energy += player->upkeep->energy_use; /* Do nothing else if player has auto-dropped stuff */ if (!player->upkeep->dropping) { /* Hack -- constant hallucination */ if (player->timed[TMD_IMAGE]) player->upkeep->redraw |= (PR_MAP); /* Shimmer multi-hued monsters */ for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); if (!mon->race) continue; if (!rf_has(mon->race->flags, RF_ATTR_MULTI)) continue; square_light_spot(cave, mon->fy, mon->fx); } /* Clear NICE flag, and show marked monsters */ for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); mflag_off(mon->mflag, MFLAG_NICE); if (mflag_has(mon->mflag, MFLAG_MARK)) { if (!mflag_has(mon->mflag, MFLAG_SHOW)) { mflag_off(mon->mflag, MFLAG_MARK); update_mon(mon, cave, false); } } } } } /* Clear SHOW flag and player drop status */ for (i = 1; i < cave_monster_max(cave); i++) { struct monster *mon = cave_monster(cave, i); mflag_off(mon->mflag, MFLAG_SHOW); } player->upkeep->dropping = false; /* Hack - update needed first because inventory may have changed */ update_stuff(player); redraw_stuff(player); }
/** * Overflow an item from the pack, if it is overfull. */ void pack_overflow(struct object *obj) { int i; char o_name[80]; bool artifact = false; if (!pack_is_overfull()) return; /* Disturbing */ disturb(player, 0); /* Warning */ msg("Your pack overflows!"); /* Get the last proper item */ for (i = 1; i <= z_info->pack_size; i++) if (!player->upkeep->inven[i]) break; /* Drop the last inventory item unless requested otherwise */ if (!obj) { obj = player->upkeep->inven[i - 1]; } /* Rule out weirdness (like pack full, but inventory empty) */ assert(obj != NULL); /* Describe */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); if (obj->artifact) { artifact = true; } /* Message */ msg("You drop %s.", o_name); /* Excise the object and drop it (carefully) near the player */ gear_excise_object(obj); drop_near(cave, &obj, 0, player->py, player->px, false); /* Describe */ if (artifact) msg("You no longer have the %s.", o_name); else msg("You no longer have %s.", o_name); /* Notice, update, redraw */ if (player->upkeep->notice) notice_stuff(player); if (player->upkeep->update) update_stuff(player); if (player->upkeep->redraw) redraw_stuff(player); }
/** * Overflow an item from the pack, if it is overfull. */ void pack_overflow(void) { int i; struct object *obj = NULL; char o_name[80]; if (!pack_is_overfull()) return; /* Disturbing */ disturb(player, 0); /* Warning */ msg("Your pack overflows!"); /* Find the last inventory item */ for (i = 1; i <= z_info->pack_size; i++) if (!player->upkeep->inven[i]) break; /* Last object was the previous index */ obj = player->upkeep->inven[i - 1]; /* Rule out weirdness (like pack full, but inventory empty) */ assert(obj != NULL); /* Describe */ object_desc(o_name, sizeof(o_name), obj, ODESC_PREFIX | ODESC_FULL); /* Message */ msg("You drop %s (%c).", o_name, I2A(i - 1)); /* Excise the object and drop it (carefully) near the player */ gear_excise_object(obj); drop_near(cave, obj, 0, player->py, player->px, FALSE); /* Describe */ if (obj->artifact) msg("You no longer have the %s (%c).", o_name, I2A(i - 1)); else msg("You no longer have %s (%c).", o_name, I2A(i - 1)); /* Notice stuff (if needed) */ if (player->upkeep->notice) notice_stuff(player->upkeep); /* Update stuff (if needed) */ if (player->upkeep->update) update_stuff(player->upkeep); /* Redraw stuff (if needed) */ if (player->upkeep->redraw) redraw_stuff(player->upkeep); }
/** * Housekeeping on arriving on a new level */ void on_new_level(void) { /* Play ambient sound on change of level. */ play_ambient_sound(); /* Cancel the target */ target_set_monster(0); /* Cancel the health bar */ health_track(player->upkeep, NULL); /* Disturb */ disturb(player, 1); /* Track maximum player level */ if (player->max_lev < player->lev) player->max_lev = player->lev; /* Track maximum dungeon level */ if (player->max_depth < player->depth) player->max_depth = player->depth; /* Flush messages */ event_signal(EVENT_MESSAGE_FLUSH); /* Update display */ event_signal(EVENT_NEW_LEVEL_DISPLAY); /* Update player */ update_player_object_knowledge(player); player->upkeep->update |= (PU_BONUS | PU_HP | PU_SPELLS | PU_INVEN); player->upkeep->notice |= (PN_COMBINE | PN_SEARCH); notice_stuff(player); update_stuff(player); redraw_stuff(player); /* Refresh */ event_signal(EVENT_REFRESH); /* Announce (or repeat) the feeling */ if (player->depth) display_feeling(false); /* Give player minimum energy to start a new level, but do not reduce * higher value from savefile for level in progress */ if (player->energy < z_info->move_energy) player->energy = z_info->move_energy; }
/* * Flush the screen, make a noise */ void bell(const char *reason) { /* Mega-Hack -- Flush the output */ Term_fresh(); /* Hack -- memorize the reason if possible */ if (character_generated && reason) { message_add(reason, MSG_BELL); /* Window stuff */ p_ptr->redraw |= (PR_MESSAGE); redraw_stuff(p_ptr); } /* Flush the input (later!) */ flush(); }
/* * Remove a button */ int button_kill_text(keycode_t keypress) { int i, j, length; /* Find the button */ for (i = 0; i < button_num; i++) if (button_mse[i].key == keypress) break; /* No such button */ if (i == button_num) { return 0; } /* Find the length */ length = button_mse[i].right - button_mse[i].left + 1; button_length -= length; /* Move each button up one */ for (j = i; j < button_num - 1; j++) { button_mse[j] = button_mse[j + 1]; /* Adjust length */ button_mse[j].left -= length; button_mse[j].right -= length; } /* Wipe the data */ button_mse[button_num].label[0] = '\0'; button_mse[button_num].left = 0; button_mse[button_num].right = 0; button_mse[button_num--].key = 0; /* Redraw */ p_ptr->redraw |= (PR_BUTTONS); redraw_stuff(p_ptr); /* Return the size of the button */ return (length); }
/* * Modify the current panel to the given coordinates, adjusting only to * ensure the coordinates are legal, and return TRUE if anything done. * * The town should never be scrolled around. * * Note that monsters are no longer affected in any way by panel changes. * * As a total hack, whenever the current panel changes, we assume that * the "overhead view" window should be updated. */ bool modify_panel(term *t, int wy, int wx) { int dungeon_hgt = DUNGEON_HGT; int dungeon_wid = DUNGEON_WID; /* Adjust for town */ if (p_ptr->depth == 0) town_adjust(&dungeon_hgt, &dungeon_wid); /* Verify wy, adjust if needed */ if (wy > dungeon_hgt - SCREEN_HGT) wy = dungeon_hgt - SCREEN_HGT; if (wy < 0) wy = 0; /* Verify wx, adjust if needed */ if (wx > dungeon_wid - SCREEN_WID) wx = dungeon_wid - SCREEN_WID; if (wx < 0) wx = 0; /* React to changes */ if ((t->offset_y != wy) || (t->offset_x != wx)) { /* Save wy, wx */ t->offset_y = wy; t->offset_x = wx; /* Redraw map */ p_ptr->redraw |= (PR_MAP); /* Redraw for big graphics */ if ((tile_width > 1) || (tile_height > 1)) redraw_stuff(); /* Hack -- optional disturb on "panel change" */ if (OPT(disturb_panel) && !OPT(center_player)) disturb(0, 0); /* Changed */ return (TRUE); } /* No change */ return (FALSE); }
/** * Hack -- change name */ void do_cmd_change_name(void) { ui_event ke; int col = 0; int last_line = 0; int top_line = 0; const char *p; /* Prompt */ p = "['c' change name, 'f' to file, scroll, or ESC]"; /* Save screen */ screen_save(); /* Adjust the buttons */ button_backup_all(); button_kill_all(); button_add("ESC", ESCAPE); button_add("Spc", ' '); button_add("-", '-'); button_add("c", 'c'); button_add("f", 'f'); button_add("->", ARROW_RIGHT); button_add("<-", ARROW_LEFT); p_ptr->redraw |= PR_BUTTONS; /* Make the array of lines */ C_WIPE(dumpline, DUMP_MAX_LINES, char_attr_line); last_line = make_dump(dumpline, 2); /* Forever */ while (1) { /* Display the player */ display_dump(dumpline, top_line, top_line + Term->hgt - 1, col); redraw_stuff(p_ptr); /* Clear the bottom line */ prt("", Term->hgt - 1, 0); /* Prompt */ Term_putstr(0, Term->hgt - 1, -1, TERM_WHITE, p); /* Query */ ke = inkey_ex(); /* Exit */ if (ke.key.code == ESCAPE) break; /* Change name */ if (ke.key.code == 'c') { char namebuf[32] = ""; if (get_name(namebuf, sizeof namebuf)) { /* Set player name */ my_strcpy(op_ptr->full_name, namebuf, sizeof(op_ptr->full_name)); /* Don't change savefile name. */ process_player_name(FALSE); } //(void) get_name(namebuf, sizeof namebuf); (void) make_dump(dumpline, 2); } /* File dump */ else if (ke.key.code == 'f') { char ftmp[80]; strnfmt(ftmp, sizeof ftmp, "%s.txt", op_ptr->base_name); if (get_string("File name: ", ftmp, 80)) { if (ftmp[0] && (ftmp[0] != ' ')) { if (file_character(ftmp, dumpline, last_line)) msg("Character dump failed!"); else msg("Character dump successful."); } } } /* Scroll down */ else if (ke.key.code == ARROW_DOWN) { if (top_line + Term->hgt - 2 < last_line) top_line++; } /* Page down */ else if (ke.key.code == ' ') { top_line = MIN(last_line - Term->hgt + 2, top_line + (Term->hgt - 2)); } /* Scroll up */ else if (ke.key.code == ARROW_UP) { if (top_line) top_line--; } /* Page up */ else if (ke.key.code == '-') { top_line -= (Term->hgt - 2) / 2; if (top_line < 0) top_line = 0; } /* Scroll left */ else if (ke.key.code == ARROW_LEFT) { if (col) col--; } /* Scroll right */ else if (ke.key.code == ARROW_RIGHT) { if (col < 32) col++; } /* Oops */ else { bell(NULL); } /* Flush messages */ message_flush(); } /* Adjust the buttons */ button_restore(); /* Load screen */ screen_load(); }
/** * 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); }
/** * Deal with events on the get_item menu */ bool get_item_action(menu_type *menu, const ui_event *event, int oid) { bool refresh = FALSE; struct object_menu_data *choice = menu_priv(menu); char key = event->key.code; int i, k; char *selections = (char *) menu->selections; if (event->type == EVT_SELECT) { selection = choice[oid].key; return FALSE; } if (event->type == EVT_KBRD) { if (key == '/') { /* Toggle to inventory */ if ((item_mode & USE_INVEN) && (p_ptr->command_wrk != USE_INVEN)) { p_ptr->command_wrk = USE_INVEN; build_obj_list(0, i2, NULL, olist_mode); refresh = TRUE; } /* Toggle to equipment */ else if ((item_mode & USE_EQUIP) && (p_ptr->command_wrk != USE_EQUIP)) { p_ptr->command_wrk = USE_EQUIP; build_obj_list(INVEN_WIELD, e2, NULL, olist_mode); refresh = TRUE; } /* No toggle allowed */ else { bell("Cannot switch item selector!"); } } else if (key == '-') { /* No toggle allowed */ if (f1 > f2) { bell("Cannot select floor!"); } /* Toggle to floor */ else { p_ptr->command_wrk = (USE_FLOOR); build_obj_list(0, f2, floor_list, olist_mode); refresh = TRUE; } } else if ((key >= '0') && (key <= '9')) { /* Look up the tag */ if (!get_tag(&k, key, item_cmd, item_mode & QUIVER_TAGS)) { bell("Illegal object choice (tag)!"); return TRUE; } /* Match the item */ for (i = 0; i < menu->count; i++) { if (choice[i].object == &p_ptr->inventory[k]) { Term_keypress(choice[i].key, 0); return TRUE; } } } if (refresh) { /* Load screen */ screen_load(); Term_fresh(); /* Save screen */ screen_save(); /* Show the prompt */ item_prompt(item_mode); menu_setpriv(menu, num_obj, items); for (i = 0; i < num_obj; i++) selections[i] = items[i].key; area.page_rows = menu->count + 1; menu_layout(menu, &area); menu_refresh(menu, TRUE); redraw_stuff(p_ptr); } return FALSE; } return TRUE; }
/* * Throw an object from the pack or floor. * * Note: "unseen" monsters are very hard to hit. * * Should throwing a weapon do full damage? Should it allow the magic * to hit bonus of the weapon to have an effect? Should it ever cause * the item to be destroyed? Should it do any damage at all? */ void do_cmd_throw(cmd_code code, cmd_arg args[]) { int dir, item; int i, j, y, x; s16b ty, tx; int chance, tdam, tdis; int weight; object_type *o_ptr; object_type *i_ptr; object_type object_type_body; bool hit_body = FALSE; byte missile_attr; char missile_char; char o_name[80]; u32b msg_type = 0; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor * op_ptr->delay_factor; /* Get item to throw and direction in which to throw it. */ item = args[0].item; dir = args[1].direction; /* Make sure the player isn't throwing wielded items */ if (item >= INVEN_WIELD && item < QUIVER_START) { msg_print("You have cannot throw wielded items."); return; } /* Check the item being thrown is usable by the player. */ if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR))) { msg_format("That item is not within your reach."); return; } /* Get the object */ o_ptr = object_from_item_idx(item); object_notice_on_firing(o_ptr); /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Distribute the charges of rods/wands/staves between the stacks */ distribute_charges(o_ptr, i_ptr, 1); /* Single object */ i_ptr->number = 1; /* Reduce and describe inventory */ if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Reduce and describe floor item */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Description */ object_desc(o_name, sizeof(o_name), i_ptr, ODESC_FULL); /* Find the color and symbol for the object for throwing */ missile_attr = object_attr(i_ptr); missile_char = object_char(i_ptr); /* Enforce a minimum "weight" of one pound */ weight = ((i_ptr->weight > 10) ? i_ptr->weight : 10); /* Hack -- Distance -- Reward strength, penalize weight */ tdis = (adj_str_blow[p_ptr->state.stat_ind[A_STR]] + 20) * 10 / weight; /* Max distance of 10 */ if (tdis > 10) tdis = 10; /* Hack -- Base damage from thrown object */ tdam = damroll(i_ptr->dd, i_ptr->ds); if (!tdam) tdam = 1; tdam += i_ptr->to_d; /* Chance of hitting */ chance = (p_ptr->state.skills[SKILL_TO_HIT_THROW] + (p_ptr->state.to_h * BTH_PLUS_ADJ)); /* Take a turn */ p_ptr->energy_use = 100; /* Start at the player */ y = p_ptr->py; x = p_ptr->px; /* Predict the "target" location */ ty = p_ptr->py + 99 * ddy[dir]; tx = p_ptr->px + 99 * ddx[dir]; /* Check for "target request" */ if ((dir == 5) && target_okay()) { target_get(&tx, &ty); } /* Calculate the path */ path_n = project_path(path_g, tdis, p_ptr->py, p_ptr->px, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(); /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { /* Visual effects */ print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); Term_xtra(TERM_XTRA_DELAY, msec); light_spot(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); } /* Delay anyway for consistency */ else { /* Pause anyway, for consistancy */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x); int visible = m_ptr->ml; /* Note the collision */ hit_body = TRUE; /* Did we hit it (penalize range) */ if (test_hit(chance2, r_ptr->ac, m_ptr->ml)) { const char *hit_verb = "hits"; bool fear = FALSE; const slay_t *best_s_ptr = NULL; /* Assume a default death */ cptr note_dies = " dies."; /* Some monsters get "destroyed" */ if (monster_is_unusual(r_ptr)) { /* Special note at death */ note_dies = " is destroyed."; } /* Apply special damage - brought forward to fill in hit_verb XXX XXX XXX */ improve_attack_modifier(i_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) { tdam *= best_s_ptr->mult; hit_verb = best_s_ptr->range_verb; } /* Apply special damage XXX XXX XXX */ tdam = critical_shot(i_ptr->weight, i_ptr->to_h, tdam, &msg_type); /* No negative damage; change verb if no damage done */ if (tdam <= 0) { tdam = 0; hit_verb = "fail to harm"; } /* Handle unseen monster */ if (!visible) { /* Invisible monster */ msg_format("The %s finds a mark.", o_name); } /* Handle visible monster */ else { char m_name[80]; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Tell the player what happened */ if (msg_type == MSG_SHOOT_HIT) message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name); else { if (msg_type == MSG_HIT_GOOD) { message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } } /* Hack -- Track this monster race */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Hack -- Track this monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); } /* Learn the bonuses */ /* XXX Eddie This is messed up, better done for firing, */ /* should use that method [split last] instead */ /* check if inven_optimize removed what o_ptr referenced */ if (object_similar(i_ptr, o_ptr, OSTACK_PACK)) object_notice_attack_plusses(o_ptr); object_notice_attack_plusses(i_ptr); /* Complex message */ if (p_ptr->wizard) msg_format("You do %d (out of %d) damage.", tdam, m_ptr->hp); /* Hit the monster, check for death */ if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies)) { /* Dead monster */ } /* No death */ else { /* Message */ message_pain(cave_m_idx[y][x], tdam); /* Take note */ if (fear && m_ptr->ml) { char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } } } /* Stop looking */ break; } } /* Chance of breakage (during attacks) */ j = (hit_body ? breakage_chance(i_ptr) : 0); /* Drop (or break) near that location */ drop_near(i_ptr, j, y, x, TRUE); }
/* * Fire an object from the pack or floor. * * You may only fire items that "match" your missile launcher. * * See "calc_bonuses()" for more calculations and such. * * Note that "firing" a missile is MUCH better than "throwing" it. * * Note: "unseen" monsters are very hard to hit. * * Objects are more likely to break if they "attempt" to hit a monster. * * Rangers (with Bows) and Anyone (with "Extra Shots") get extra shots. * The "extra shot" code works by decreasing the amount of energy * required to make each shot, spreading the shots out over time. * * Note that when firing missiles, the launcher multiplier is applied * after all the bonuses are added in, making multipliers very useful. * * Note that Bows of "Extra Might" get extra range and an extra bonus * for the damage multiplier. */ void do_cmd_fire(cmd_code code, cmd_arg args[]) { int dir, item; int i, j, y, x; s16b ty, tx; int tdam, tdis, thits; int bonus, chance; object_type *o_ptr; object_type *j_ptr; object_type *i_ptr; object_type object_type_body; bool hit_body = FALSE; byte missile_attr; char missile_char; char o_name[80]; u32b msg_type = 0; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor * op_ptr->delay_factor; /* Get the "bow" */ j_ptr = &p_ptr->inventory[INVEN_BOW]; /* Require a usable launcher */ if (!j_ptr->tval || !p_ptr->state.ammo_tval) { msg_print("You have nothing to fire with."); return; } /* Get item to fire and direction to fire in. */ item = args[0].item; dir = args[1].direction; /* Check the item being fired is usable by the player. */ if (!item_is_available(item, NULL, (USE_EQUIP | USE_INVEN | USE_FLOOR))) { msg_format("That item is not within your reach."); return; } /* Get the object for the ammo */ o_ptr = object_from_item_idx(item); /* Check the ammo can be used with the launcher */ if (o_ptr->tval != p_ptr->state.ammo_tval) { msg_format("That ammo cannot be fired by your current weapon."); return; } /* Base range XXX XXX */ tdis = 6 + 2 * p_ptr->state.ammo_mult; /* Start at the player */ x = p_ptr->px; y = p_ptr->py; /* Predict the "target" location */ ty = y + 99 * ddy[dir]; tx = x + 99 * ddx[dir]; /* Check for target validity */ if ((dir == 5) && target_okay()) { target_get(&tx, &ty); if (distance(y, x, ty, tx) > tdis) { if (!get_check("Target out of range. Fire anyway? ")) return; } } /* Sound */ sound(MSG_SHOOT); object_notice_on_firing(o_ptr); /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR); /* Find the color and symbol for the object for throwing */ missile_attr = object_attr(o_ptr); missile_char = object_char(o_ptr); /* Use the proper number of shots */ thits = p_ptr->state.num_fire; /* Actually "fire" the object */ bonus = (p_ptr->state.to_h + o_ptr->to_h + j_ptr->to_h); chance = p_ptr->state.skills[SKILL_TO_HIT_BOW] + (bonus * BTH_PLUS_ADJ); /* Take a (partial) turn */ p_ptr->energy_use = (100 / thits); /* Calculate the path */ path_n = project_path(path_g, tdis, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(); /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { /* Visual effects */ print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); Term_xtra(TERM_XTRA_DELAY, msec); light_spot(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(); } /* Delay anyway for consistency */ else { /* Pause anyway, for consistancy */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave_m_idx[y][x] > 0) { monster_type *m_ptr = &mon_list[cave_m_idx[y][x]]; monster_race *r_ptr = &r_info[m_ptr->r_idx]; int chance2 = chance - distance(p_ptr->py, p_ptr->px, y, x); int visible = m_ptr->ml; int multiplier = 1; const char *hit_verb = "hits"; const slay_t *best_s_ptr = NULL; /* Note the collision */ hit_body = TRUE; /* Did we hit it (penalize distance travelled) */ if (test_hit(chance2, r_ptr->ac, m_ptr->ml)) { bool fear = FALSE; /* Assume a default death */ cptr note_dies = " dies."; improve_attack_modifier(o_ptr, m_ptr, &best_s_ptr); improve_attack_modifier(j_ptr, m_ptr, &best_s_ptr); if (best_s_ptr != NULL) hit_verb = best_s_ptr->range_verb; /* Some monsters get "destroyed" */ if (monster_is_unusual(r_ptr)) { /* Special note at death */ note_dies = " is destroyed."; } /* Calculate multiplier */ multiplier = p_ptr->state.ammo_mult; if (best_s_ptr != NULL) multiplier += best_s_ptr->mult; /* Apply damage: multiplier, slays, criticals, bonuses */ tdam = damroll(o_ptr->dd, o_ptr->ds); tdam += o_ptr->to_d + j_ptr->to_d; tdam *= multiplier; tdam = critical_shot(o_ptr->weight, o_ptr->to_h, tdam, &msg_type); object_notice_attack_plusses(o_ptr); object_notice_attack_plusses(&p_ptr->inventory[INVEN_BOW]); /* No negative damage; change verb if no damage done */ if (tdam <= 0) { tdam = 0; hit_verb = "fail to harm"; } /* Handle unseen monster */ if (!visible) { /* Invisible monster */ message_format(MSG_SHOOT_HIT, 0, "The %s finds a mark.", o_name); } /* Handle visible monster */ else { char m_name[80]; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Tell the player what happened */ if (msg_type == MSG_SHOOT_HIT) message_format(MSG_SHOOT_HIT, 0, "The %s %s %s.", o_name, hit_verb, m_name); else { if (msg_type == MSG_HIT_GOOD) { message_format(MSG_HIT_GOOD, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { message_format(MSG_HIT_GREAT, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { message_format(MSG_HIT_SUPERB, 0, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } } /* Hack -- Track this monster race */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); /* Hack -- Track this monster */ if (m_ptr->ml) health_track(cave_m_idx[y][x]); } /* Complex message */ if (p_ptr->wizard) { msg_format("You do %d (out of %d) damage.", tdam, m_ptr->hp); } /* Hit the monster, check for death */ if (mon_take_hit(cave_m_idx[y][x], tdam, &fear, note_dies)) { /* Dead monster */ } /* No death */ else { /* Message */ message_pain(cave_m_idx[y][x], tdam); /* Take note */ if (fear && m_ptr->ml) { char m_name[80]; /* Get the monster name (or "it") */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); /* Message */ message_format(MSG_FLEE, m_ptr->r_idx, "%^s flees in terror!", m_name); } } } /* Stop looking */ break; } } /* Get local object */ i_ptr = &object_type_body; /* Obtain a local object */ object_copy(i_ptr, o_ptr); /* Single object */ i_ptr->number = 1; if (item >= 0) { inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } /* Reduce and describe floor item */ else { floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } /* Chance of breakage (during attacks) */ j = (hit_body ? breakage_chance(i_ptr) : 0); /* Drop (or break) near that location */ drop_near(i_ptr, j, y, x, TRUE); }
/** * 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; }
/** * This is a helper function used by do_cmd_throw and do_cmd_fire. * * It abstracts out the projectile path, display code, identify and clean up * logic, while using the 'attack' parameter to do work particular to each * kind of attack. */ static void ranged_helper(int item, int dir, int range, int shots, ranged_attack attack) { /* Get the ammo */ object_type *o_ptr = object_from_item_idx(item); int i, j; byte missile_attr = object_attr(o_ptr); char missile_char = object_char(o_ptr); object_type object_type_body; object_type *i_ptr = &object_type_body; char o_name[80]; int path_n; u16b path_g[256]; int msec = op_ptr->delay_factor; /* Start at the player */ int x = p_ptr->px; int y = p_ptr->py; /* Predict the "target" location */ s16b ty = y + 99 * ddy[dir]; s16b tx = x + 99 * ddx[dir]; bool hit_target = FALSE; /* Check for target validity */ if ((dir == 5) && target_okay()) { int taim; char msg[80]; target_get(&tx, &ty); taim = distance(y, x, ty, tx); if (taim > range) { sprintf (msg, "Target out of range by %d squares. Fire anyway? ", taim - range); if (!get_check(msg)) return; } } /* Sound */ sound(MSG_SHOOT); object_notice_on_firing(o_ptr); /* Describe the object */ object_desc(o_name, sizeof(o_name), o_ptr, ODESC_FULL | ODESC_SINGULAR); /* Actually "fire" the object -- Take a partial turn */ p_ptr->energy_use = (100 / shots); /* Calculate the path */ path_n = project_path(path_g, range, y, x, ty, tx, 0); /* Hack -- Handle stuff */ handle_stuff(p_ptr); /* Start at the player */ x = p_ptr->px; y = p_ptr->py; /* Project along the path */ for (i = 0; i < path_n; ++i) { int ny = GRID_Y(path_g[i]); int nx = GRID_X(path_g[i]); /* Hack -- Stop before hitting walls */ if (!cave_floor_bold(ny, nx)) break; /* Advance */ x = nx; y = ny; /* Only do visuals if the player can "see" the missile */ if (player_can_see_bold(y, x)) { print_rel(missile_char, missile_attr, y, x); move_cursor_relative(y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); Term_xtra(TERM_XTRA_DELAY, msec); cave_light_spot(cave, y, x); Term_fresh(); if (p_ptr->redraw) redraw_stuff(p_ptr); } else { /* Delay anyway for consistency */ Term_xtra(TERM_XTRA_DELAY, msec); } /* Handle monster */ if (cave->m_idx[y][x] > 0) break; } /* Try the attack on the monster at (x, y) if any */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); monster_race *r_ptr = &r_info[m_ptr->r_idx]; int visible = m_ptr->ml; bool fear = FALSE; char m_name[80]; const char *note_dies = monster_is_unusual(r_ptr) ? " is destroyed." : " dies."; struct attack_result result = attack(o_ptr, y, x); int dmg = result.dmg; u32b msg_type = result.msg_type; const char *hit_verb = result.hit_verb; if (result.success) { hit_target = TRUE; /* Get "the monster" or "it" */ monster_desc(m_name, sizeof(m_name), m_ptr, 0); object_notice_attack_plusses(o_ptr); /* No negative damage; change verb if no damage done */ if (dmg <= 0) { dmg = 0; hit_verb = "fail to harm"; } if (!visible) { /* Invisible monster */ msgt(MSG_SHOOT_HIT, "The %s finds a mark.", o_name); } else { /* Visible monster */ if (msg_type == MSG_SHOOT_HIT) msgt(MSG_SHOOT_HIT, "The %s %s %s.", o_name, hit_verb, m_name); else if (msg_type == MSG_HIT_GOOD) { msgt(MSG_HIT_GOOD, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a good hit!"); } else if (msg_type == MSG_HIT_GREAT) { msgt(MSG_HIT_GREAT, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a great hit!"); } else if (msg_type == MSG_HIT_SUPERB) { msgt(MSG_HIT_SUPERB, "The %s %s %s. %s", o_name, hit_verb, m_name, "It was a superb hit!"); } /* Track this monster */ if (m_ptr->ml) monster_race_track(m_ptr->r_idx); if (m_ptr->ml) health_track(p_ptr, cave->m_idx[y][x]); } /* Complex message */ if (p_ptr->wizard) msg("You do %d (out of %d) damage.", dmg, m_ptr->hp); /* Hit the monster, check for death */ if (!mon_take_hit(cave->m_idx[y][x], dmg, &fear, note_dies)) { message_pain(cave->m_idx[y][x], dmg); if (fear && m_ptr->ml) add_monster_message(m_name, cave->m_idx[y][x], MON_MSG_FLEE_IN_TERROR, TRUE); } } } /* Obtain a local object */ object_copy(i_ptr, o_ptr); object_split(i_ptr, o_ptr, 1); /* See if the ammunition broke or not */ j = breakage_chance(i_ptr, hit_target); /* Drop (or break) near that location */ drop_near(cave, i_ptr, j, y, x, TRUE); if (item >= 0) { /* The ammo is from the inventory */ inven_item_increase(item, -1); inven_item_describe(item); inven_item_optimize(item); } else { /* The ammo is from the floor */ floor_item_increase(0 - item, -1); floor_item_optimize(0 - item); } }
/* * 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) { int py = p_ptr->py; int px = p_ptr->px; unsigned char cmdkey = cmd_lookup_key(cmd, OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG); //struct keypress which; ui_event press; int j, k; int i1, i2; int e1, e2; int f1, f2; bool done, item; bool oops = FALSE; bool use_inven = ((mode & USE_INVEN) ? TRUE : FALSE); bool use_equip = ((mode & USE_EQUIP) ? TRUE : FALSE); bool use_floor = ((mode & USE_FLOOR) ? TRUE : FALSE); bool is_harmless = ((mode & IS_HARMLESS) ? TRUE : FALSE); bool quiver_tags = ((mode & QUIVER_TAGS) ? TRUE : FALSE); int olist_mode = 0; bool allow_inven = FALSE; bool allow_equip = FALSE; bool allow_floor = FALSE; bool toggle = FALSE; char tmp_val[160]; char out_val[160]; int floor_list[MAX_FLOOR_STACK]; int floor_num; bool show_list = TRUE; /* Hack - Only shift the command key if it actually needs to be shifted. */ if (cmdkey < 0x20) cmdkey = UN_KTRL(cmdkey); /* 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; /* Paranoia XXX XXX XXX */ message_flush(); /* Not done */ done = FALSE; /* No item selected */ item = 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; /* Scan all non-gold objects in the grid */ floor_num = scan_floor(floor_list, N_ELEMENTS(floor_list), py, px, 0x0B); /* 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 */ else { /* Hack -- Start on equipment if requested */ if ((p_ptr->command_wrk == USE_EQUIP) && allow_equip) p_ptr->command_wrk = USE_EQUIP; else if ((p_ptr->command_wrk == USE_INVEN) && allow_inven) p_ptr->command_wrk = USE_INVEN; else if ((p_ptr->command_wrk == USE_FLOOR) && allow_floor) p_ptr->command_wrk = USE_FLOOR; /* If we are using the quiver then start on equipment */ else if (quiver_tags && allow_equip) p_ptr->command_wrk = USE_EQUIP; /* Use inventory if allowed */ else if (use_inven && allow_inven) p_ptr->command_wrk = USE_INVEN; /* Use equipment if allowed */ else if (use_equip && allow_equip) p_ptr->command_wrk = USE_EQUIP; /* Use floor if allowed */ else if (use_floor && allow_floor) p_ptr->command_wrk = USE_FLOOR; /* Hack -- Use (empty) inventory */ else p_ptr->command_wrk = USE_INVEN; } /* Start out in "display" mode */ if (show_list) { /* Save screen */ screen_save(); } /* Repeat until done */ while (!done) { 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); /* Viewing inventory */ if (p_ptr->command_wrk == USE_INVEN) { int nmode = olist_mode; /* Show the quiver counts in certain cases, like the 'i' command */ if (mode & SHOW_QUIVER) nmode |= OLIST_QUIVER; /* Redraw if needed */ if (show_list) show_inven(nmode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Inven:"); /* List choices */ if (i1 <= i2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", index_to_label(i1), index_to_label(i2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Indicate legality of "toggle" */ if (use_equip) { my_strcat(out_val, " / for Equip,", sizeof(out_val)); button_add("[/]", '/'); } /* Indicate legality of the "floor" */ if (allow_floor) { my_strcat(out_val, " - for floor,", sizeof(out_val)); button_add("[-]", '-'); } } /* Viewing equipment */ else if (p_ptr->command_wrk == USE_EQUIP) { /* Redraw if needed */ if (show_list) show_equip(olist_mode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Equip:"); /* List choices */ if (e1 <= e2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", index_to_label(e1), index_to_label(e2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Indicate legality of "toggle" */ if (use_inven) { my_strcat(out_val, " / for Inven,", sizeof(out_val)); button_add("[/]", '/'); } /* Indicate legality of the "floor" */ if (allow_floor) { my_strcat(out_val, " - for floor,", sizeof(out_val)); button_add("[!]", '!'); } } /* Viewing floor */ else { /* Redraw if needed */ if (show_list) show_floor(floor_list, floor_num, olist_mode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Floor:"); /* List choices */ if (f1 <= f2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", I2A(f1), I2A(f2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Append */ if (use_inven) { my_strcat(out_val, " / for Inven,", sizeof(out_val)); button_add("[/]", '/'); } /* Append */ else if (use_equip) { my_strcat(out_val, " / for Equip,", sizeof(out_val)); button_add("[/]", '/'); } } redraw_stuff(p_ptr); /* Finish the prompt */ my_strcat(out_val, " ESC", sizeof(out_val)); /* if we have a prompt header, show the part that we just built */ if (pmt) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), "(%s) %s", out_val, pmt); /* Show the prompt */ prt(tmp_val, 0, 0); } /* Get a key */ //which = inkey(); press = inkey_m(); /* Parse it */ if (press.type == EVT_MOUSE) { if (press.mouse.button == 2) { done = TRUE; } else if (press.mouse.button == 1) { k = -1; if (p_ptr->command_wrk == USE_INVEN) { if (press.mouse.y == 0) { if (use_equip) { p_ptr->command_wrk = USE_EQUIP; } else if (allow_floor) { p_ptr->command_wrk = USE_FLOOR; } } else if ((press.mouse.y <= i2-i1+1) ){ //&& (press.mouse.x > Term->wid - 1 - max_len - ex_width)) { //k = label_to_inven(index_to_label(i1+press.mouse.y-1)); /* get the item index, allowing for skipped indices */ for (j = i1; j <= i2; j++) { if (get_item_okay(j)) { if (press.mouse.y == 1) { k = j; break; } press.mouse.y--; } } } } else if (p_ptr->command_wrk == USE_EQUIP) { if (press.mouse.y == 0) { if (allow_floor) { p_ptr->command_wrk = USE_FLOOR; } else if (use_inven) { p_ptr->command_wrk = USE_INVEN; } } else if (press.mouse.y <= e2-e1+1) { if (olist_mode & OLIST_SEMPTY) { /* If we are showing empties, just set the object (empty objects will just keep the loop going) */ k = label_to_equip(index_to_label(e1+press.mouse.y-1)); } else { /* get the item index, allowing for skipped indices */ for (j = e1; j <= e2; j++) { /* skip the quiver slot which is a blank line in the list */ if (j == 36) { press.mouse.y--; } else if (get_item_okay(j)) { if (press.mouse.y == 1) { k = j; break; } press.mouse.y--; } } } } } else if (p_ptr->command_wrk == USE_FLOOR) { if (press.mouse.y == 0) { if (use_inven) { p_ptr->command_wrk = USE_INVEN; } else if (use_equip) { p_ptr->command_wrk = USE_EQUIP; } } else if ((press.mouse.y <= floor_num) && (press.mouse.y >= 1)) { /* Special index */ k = 0 - floor_list[press.mouse.y-1]; /* get the item index, allowing for skipped indices */ for (j = f1; j <= f2; j++) { if (get_item_okay(0 - floor_list[j])) { if (press.mouse.y == 1) { k = 0 - floor_list[j]; break; } press.mouse.y--; } } /* check the bounds the item number */ if (k < 0) { /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, cmd, is_harmless)) { done = TRUE; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; } else { /* set k to a value that will be invalid below */ k = -1; } } } if (k >= 0) { /* Validate the item */ if (!get_item_okay(k)) { bell("Illegal object choice (normal)!"); } /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, cmd, is_harmless)) { done = TRUE; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; } else if (press.mouse.y == 0) { /* Hack -- Fix screen */ if (show_list) { /* Load screen */ screen_load(); /* Save screen */ screen_save(); } } } } else //switch (which.code) switch (press.key.code) { case ESCAPE: case ' ': { done = TRUE; break; } case '/': { /* Toggle to inventory */ if (use_inven && (p_ptr->command_wrk != USE_INVEN)) { p_ptr->command_wrk = USE_INVEN; } /* Toggle to equipment */ else if (use_equip && (p_ptr->command_wrk != USE_EQUIP)) { p_ptr->command_wrk = USE_EQUIP; } /* No toggle allowed */ else { bell("Cannot switch item selector!"); break; } /* Hack -- Fix screen */ if (show_list) { /* Load screen */ screen_load(); /* Save screen */ screen_save(); } /* Need to redraw */ break; } case '-': { /* Paranoia */ if (!allow_floor) { bell("Cannot select floor!"); break; } /* There is only one item */ if (floor_num == 1) { /* Auto-select */ if (p_ptr->command_wrk == (USE_FLOOR)) { /* Special index */ k = 0 - floor_list[0]; /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, cmd, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } } /* Hack -- Fix screen */ if (show_list) { /* Load screen */ screen_load(); /* Save screen */ screen_save(); } p_ptr->command_wrk = (USE_FLOOR); #if 0 /* Check each legal object */ for (i = 0; i < floor_num; ++i) { /* Special index */ k = 0 - floor_list[i]; /* Skip non-okay objects */ if (!get_item_okay(k)) continue; /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, cmd, is_harmless)) continue; /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } #endif 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.code, cmd, quiver_tags)) if (!get_tag(&k, press.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, cmd, 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, cmd, is_harmless)) { done = TRUE; break; } /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } default: { bool verify; /* Note verify */ //verify = (isupper((unsigned char)which.code) ? TRUE : FALSE); verify = (isupper((unsigned char)press.key.code) ? TRUE : FALSE); /* Lowercase */ //which.code = tolower((unsigned char)which.code); press.key.code = tolower((unsigned char)press.key.code); /* Convert letter to inventory index */ if (p_ptr->command_wrk == USE_INVEN) { //k = label_to_inven(which.code); k = label_to_inven(press.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.code); k = label_to_equip(press.key.code); if (k < 0) { bell("Illegal object choice (equip)!"); break; } } /* Convert letter to floor index */ else { //k = (islower((unsigned char)which.code) ? A2I((unsigned char)which.code) : -1); k = (islower((unsigned char)press.key.code) ? A2I((unsigned char)press.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, cmd, 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('!'); redraw_stuff(p_ptr); /* 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("%s", str); /* Result */ return (item); }
/* * 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, cptr pmt, cptr str, cmd_code cmd, int mode) { int py = p_ptr->py; int px = p_ptr->px; unsigned char cmdkey = cmd_lookup_key(cmd); ui_event_data which; int j, k; int i1, i2; int e1, e2; int f1, f2; bool done, item; bool oops = FALSE; bool use_inven = ((mode & USE_INVEN) ? TRUE : FALSE); bool use_equip = ((mode & USE_EQUIP) ? TRUE : FALSE); bool use_floor = ((mode & USE_FLOOR) ? TRUE : FALSE); bool use_quiver = ((mode & QUIVER_TAGS) ? TRUE : FALSE); bool is_harmless = ((mode & IS_HARMLESS) ? TRUE : FALSE); bool quiver_tags = ((mode & QUIVER_TAGS) ? TRUE : FALSE); olist_detail_t olist_mode = 0; bool allow_inven = FALSE; bool allow_equip = FALSE; bool allow_floor = FALSE; bool toggle = FALSE; char tmp_val[160]; char out_val[160]; int floor_list[MAX_FLOOR_STACK]; int floor_num; bool show_list = 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); /* Paranoia XXX XXX XXX */ message_flush(); /* Not done */ done = FALSE; /* No item selected */ item = 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; /* 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 */ else { /* Hack -- Start on equipment if requested */ if ((p_ptr->command_wrk == USE_EQUIP) && use_equip) p_ptr->command_wrk = USE_EQUIP; /* If we are using the quiver then start on equipment */ else if (use_quiver) p_ptr->command_wrk = USE_EQUIP; /* Use inventory if allowed */ else if (use_inven) p_ptr->command_wrk = USE_INVEN; /* Use equipment if allowed */ else if (use_equip) p_ptr->command_wrk = USE_EQUIP; /* Use floor if allowed */ else if (use_floor) p_ptr->command_wrk = USE_FLOOR; /* Hack -- Use (empty) inventory */ else p_ptr->command_wrk = USE_INVEN; } /* Start out in "display" mode */ if (show_list) { /* Save screen */ screen_save(); } /* Repeat until done */ while (!done) { int ni = 0; int ne = 0; /* Scan windows */ for (j = 0; j < REPOSBAND_TERM_MAX; j++) { /* Unused */ if (!reposband_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(); /* Viewing inventory */ if (p_ptr->command_wrk == USE_INVEN) { /* Redraw if needed */ if (show_list) show_inven(olist_mode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Inven:"); /* List choices */ if (i1 <= i2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", index_to_label(i1), index_to_label(i2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Indicate legality of "toggle" */ if (use_equip) { my_strcat(out_val, " / for Equip,", sizeof(out_val)); button_add("[/]", '/'); } /* Indicate legality of the "floor" */ if (allow_floor) { my_strcat(out_val, " - for floor,", sizeof(out_val)); button_add("[-]", '-'); } } /* Viewing equipment */ else if (p_ptr->command_wrk == USE_EQUIP) { /* Redraw if needed */ if (show_list) show_equip(olist_mode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Equip:"); /* List choices */ if (e1 <= e2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", index_to_label(e1), index_to_label(e2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Indicate legality of "toggle" */ if (use_inven) { my_strcat(out_val, " / for Inven,", sizeof(out_val)); button_add("[/]", '/'); } /* Indicate legality of the "floor" */ if (allow_floor) { my_strcat(out_val, " - for floor,", sizeof(out_val)); button_add("[!]", '!'); } } /* Viewing floor */ else { /* Redraw if needed */ if (show_list) show_floor(floor_list, floor_num, olist_mode); /* Begin the prompt */ strnfmt(out_val, sizeof(out_val), "Floor:"); /* List choices */ if (f1 <= f2) { /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), " %c-%c,", I2A(f1), I2A(f2)); /* Append */ my_strcat(out_val, tmp_val, sizeof(out_val)); } /* Indicate ability to "view" */ if (!show_list) { my_strcat(out_val, " * to see,", sizeof(out_val)); button_add("[*]", '*'); } /* Append */ if (use_inven) { my_strcat(out_val, " / for Inven,", sizeof(out_val)); button_add("[/]", '/'); } /* Append */ else if (use_equip) { my_strcat(out_val, " / for Equip,", sizeof(out_val)); button_add("[/]", '/'); } } redraw_stuff(); /* Finish the prompt */ my_strcat(out_val, " ESC", sizeof(out_val)); /* Build the prompt */ strnfmt(tmp_val, sizeof(tmp_val), "(%s) %s", out_val, pmt); /* Show the prompt */ prt(tmp_val, 0, 0); /* Get a key */ which = inkey_ex(); /* Parse it */ switch (which.key) { case ESCAPE: { done = TRUE; break; } case '/': { /* Toggle to inventory */ if (use_inven && (p_ptr->command_wrk != USE_INVEN)) { p_ptr->command_wrk = USE_INVEN; } /* Toggle to equipment */ else if (use_equip && (p_ptr->command_wrk != USE_EQUIP)) { p_ptr->command_wrk = USE_EQUIP; } /* No toggle allowed */ else { bell("Cannot switch item selector!"); break; } /* Hack -- Fix screen */ if (show_list) { /* Load screen */ screen_load(); /* Save screen */ screen_save(); } /* Need to redraw */ break; } case '-': { /* Paranoia */ if (!allow_floor) { bell("Cannot select floor!"); break; } /* There is only one item */ if (floor_num == 1) { /* Auto-select */ if (p_ptr->command_wrk == (USE_FLOOR)) { /* 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; } } /* Hack -- Fix screen */ if (show_list) { /* Load screen */ screen_load(); /* Save screen */ screen_save(); } p_ptr->command_wrk = (USE_FLOOR); #if 0 /* Check each legal object */ for (i = 0; i < floor_num; ++i) { /* Special index */ k = 0 - floor_list[i]; /* Skip non-okay objects */ if (!get_item_okay(k)) continue; /* Allow player to "refuse" certain actions */ if (!get_item_allow(k, cmdkey, is_harmless)) continue; /* Accept that choice */ (*cp) = k; item = TRUE; done = TRUE; break; } #endif 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, 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 '\n': case '\r': { /* 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; } default: { bool verify; /* Note verify */ verify = (isupper((unsigned char)which.key) ? TRUE : FALSE); /* Lowercase */ which.key = tolower((unsigned char)which.key); /* Convert letter to inventory index */ if (p_ptr->command_wrk == USE_INVEN) { k = label_to_inven(which.key); 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); if (k < 0) { bell("Illegal object choice (equip)!"); break; } } /* Convert letter to floor index */ else { k = (islower((unsigned char)which.key) ? A2I(which.key) : -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('!'); redraw_stuff(); /* 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(); /* Clear the prompt line */ prt("", 0, 0); /* Warning if needed */ if (oops && str) msg_print(str); /* Result */ return (item); }
static enum birth_stage roller_command(bool first_call) { char prompt[80] = ""; size_t promptlen = 0; struct keypress ch; enum birth_stage next = BIRTH_ROLLER; /* Used to keep track of whether we've rolled a character before or not. */ static bool prev_roll = FALSE; /* Display the player - a bit cheaty, but never mind. */ display_player(0); if (first_call) prev_roll = FALSE; /* Add buttons */ button_add("[ESC]", ESCAPE); button_add("[Enter]", '\r'); button_add("[r]", 'r'); if (prev_roll) button_add("[p]", 'p'); clear_from(Term->hgt - 2); redraw_stuff(p_ptr); /* Prepare a prompt (must squeeze everything in) */ strnfcat(prompt, sizeof (prompt), &promptlen, "['r' to reroll"); if (prev_roll) strnfcat(prompt, sizeof(prompt), &promptlen, ", 'p' for prev"); strnfcat(prompt, sizeof (prompt), &promptlen, " or 'Enter' to accept]"); /* Prompt for it */ prt(prompt, Term->hgt - 1, Term->wid / 2 - promptlen / 2); /* Prompt and get a command */ ch = inkey(); if (ch.code == ESCAPE) { button_kill('r'); button_kill('p'); next = BIRTH_BACK; } /* 'Enter' accepts the roll */ if ((ch.code == '\r') || (ch.code == '\n')) { next = BIRTH_NAME_CHOICE; } /* Reroll this character */ else if ((ch.code == ' ') || (ch.code == 'r')) { cmd_insert(CMD_ROLL_STATS); prev_roll = TRUE; } /* Previous character */ else if (prev_roll && (ch.code == 'p')) { cmd_insert(CMD_PREV_STATS); } /* Quit */ else if (ch.code == KTRL('X')) { cmd_insert(CMD_QUIT); next = BIRTH_COMPLETE; } /* Help XXX */ else if (ch.code == '?') { do_cmd_help(); } /* Nothing handled directly here */ else { bell("Illegal roller command!"); } /* Kill buttons */ button_kill(ESCAPE); button_kill('\r'); button_kill('r'); button_kill('p'); redraw_stuff(p_ptr); return next; }
/** * Show previous messages to the user * * The screen format uses line 0 and 23 for headers and prompts, * skips line 1 and 22, and uses line 2 thru 21 for old messages. * * This command shows you which commands you are viewing, and allows * you to "search" for strings in the recall. * * Note that messages may be longer than 80 characters, but they are * displayed using "infinite" length, with a special sub-command to * "slide" the virtual display to the left or right. * * Attempt to only hilight the matching portions of the string. */ void do_cmd_messages(void) { ui_event ke; int i, j, n, q; int wid, hgt; char shower[80]; char finder[80]; char p[80]; /* Wipe finder */ my_strcpy(finder, "", sizeof(shower)); /* Wipe shower */ my_strcpy(shower, "", sizeof(finder)); /* Total messages */ n = messages_num(); /* Start on first message */ i = 0; /* Start at leftmost edge */ q = 0; /* Get size */ Term_get_size(&wid, &hgt); /* Prompt */ strncpy(p, "[Press 'p' for older, 'n' for newer, ..., or ESCAPE]", 80); /* Save screen */ screen_save(); /* Adjust the buttons */ button_backup_all(); button_kill_all(); button_add("ESC", ESCAPE); button_add("-", '-'); button_add("=", '='); button_add("/", '/'); button_add("p", 'p'); button_add("n", 'n'); button_add("+", '+'); button_add("->", '6'); button_add("<-", '4'); p_ptr->redraw |= (PR_BUTTONS); /* Process requests until done */ while (1) { /* Clear screen */ Term_clear(); /* Dump messages */ for (j = 0; (j < hgt - 4) && (i + j < n); j++) { const char *msg = message_str((s16b)(i+j)); byte attr = message_color((s16b)(i+j)); /* Apply horizontal scroll */ msg = ((int)strlen(msg) >= q) ? (msg + q) : ""; /* Dump the messages, bottom to top */ Term_putstr(0, hgt - 3 - j, -1, attr, msg); /* Hilight "shower" */ if (shower[0]) { const char *str = msg; /* Display matches */ while ((str = strstr(str, shower)) != NULL) { int len = strlen(shower); /* Display the match */ Term_putstr(str-msg, hgt - 3 - j, len, TERM_YELLOW, shower); /* Advance */ str += len; } } } /* Display header XXX XXX XXX */ prt(format("Message Recall (%d-%d of %d), Offset %d", i, i + j - 1, n, q), 0, 0); /* Display prompt (not very informative) */ prt(p, hgt - 1, 0); redraw_stuff(p_ptr); /* Get a command */ ke = inkey_ex(); /* Exit on Escape */ if (ke.key.code == ESCAPE) break; /* Hack -- Save the old index */ j = i; /* Horizontal scroll */ if (ke.key.code == '4') { /* Scroll left */ q = (q >= wid / 2) ? (q - wid / 2) : 0; /* Success */ continue; } /* Horizontal scroll */ if (ke.key.code == '6') { /* Scroll right */ q = q + wid / 2; /* Success */ continue; } /* Hack -- handle show */ if (ke.key.code == '=') { /* Prompt */ prt("Show: ", hgt - 1, 0); /* Get a "shower" string, or continue */ if (!askfor_aux(shower, sizeof shower, NULL)) continue; /* Okay */ continue; } /* Hack -- handle find */ if (ke.key.code == '/') { s16b z; /* Prompt */ prt("Find: ", hgt - 1, 0); /* Get a "finder" string, or continue */ if (!askfor_aux(finder, sizeof finder, NULL)) continue; /* Show it */ my_strcpy(shower, finder, sizeof(shower)); /* Scan messages */ for (z = i + 1; z < n; z++) { const char *msg = message_str(z); /* Search for it */ if (strstr(msg, finder)) { /* New location */ i = z; /* Done */ break; } } } /* Recall 20 older messages */ if ((ke.key.code == 'p') || (ke.key.code == KTRL('P')) || (ke.key.code == ' ')) { /* Go older if legal */ if (i + 20 < n) i += 20; } /* Recall 10 older messages */ if (ke.key.code == '+') { /* Go older if legal */ if (i + 10 < n) i += 10; } /* Recall 1 older message */ if ((ke.key.code == '8') || (ke.key.code == '\n') || (ke.key.code == '\r')) { /* Go older if legal */ if (i + 1 < n) i += 1; } /* Recall 20 newer messages */ if ((ke.key.code == 'n') || (ke.key.code == KTRL('N'))) { /* Go newer (if able) */ i = (i >= 20) ? (i - 20) : 0; } /* Recall 10 newer messages */ if (ke.key.code == '-') { /* Go newer (if able) */ i = (i >= 10) ? (i - 10) : 0; } /* Recall 1 newer messages */ if (ke.key.code == '2') { /* Go newer (if able) */ i = (i >= 1) ? (i - 1) : 0; } /* Scroll forwards or backwards using mouse clicks */ if (ke.mouse.button) { if (ke.mouse.y <= hgt / 2) { /* Go older if legal */ if (i + 20 < n) i += 20; } else { /* Go newer (if able) */ i = (i >= 20) ? (i - 20) : 0; } } /* Hack -- Error of some kind */ if (i == j) bell(NULL); } /* Adjust the buttons */ button_restore(); /* Load screen */ screen_load(); }