int test_drop_eat(void *state) { int num = 0; /* Load the saved game */ eq(savefile_load("Test1", FALSE), TRUE); num = player->upkeep->inven[0]->number; cmdq_push(CMD_WALK); cmd_set_arg_direction(cmdq_peek(), "direction", 4); run_game_loop(); cmdq_push(CMD_DROP); cmd_set_arg_item(cmdq_peek(), "item", player->upkeep->inven[0]); cmd_set_arg_number(cmdq_peek(), "quantity", player->upkeep->inven[0]->number); run_game_loop(); eq(square_object(cave, player->py, player->px)->number, num); cmdq_push(CMD_EAT); cmd_set_arg_item(cmdq_peek(), "item", square_object(cave, player->py, player->px)); run_game_loop(); if (num > 1) { eq(square_object(cave, player->py, player->px)->number, num - 1); } else { eq(square_object(cave, player->py, player->px), NULL); } ok; }
/** * ------------------------------------------------------------------------ * Quickstart? screen. * ------------------------------------------------------------------------ */ static enum birth_stage textui_birth_quickstart(void) { const char *prompt = "['Y' to use this character, 'N' to start afresh, 'C' to change name or history]"; 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); do { /* Get a key */ struct keypress ke = inkey(); if (ke.code == 'N' || ke.code == 'n') { cmdq_push(CMD_BIRTH_RESET); next = BIRTH_RACE_CHOICE; } else if (ke.code == KTRL('X')) { quit(NULL); } else if (ke.code == 'C' || ke.code == 'c') { next = BIRTH_NAME_CHOICE; } else if (ke.code == 'Y' || ke.code == 'y') { cmdq_push(CMD_ACCEPT_CHARACTER); next = BIRTH_COMPLETE; } } while (next == BIRTH_QUICKSTART); /* Clear prompt */ clear_from(23); return next; }
/** * Get input for the rest command */ void textui_cmd_rest(void) { const char *p = "Rest (0-9999, '!' for HP or SP, '*' for HP and SP, '&' as needed): "; char out_val[5] = "& "; /* Ask for duration */ if (!get_string(p, out_val, sizeof(out_val))) return; /* Rest... */ if (out_val[0] == '&') { /* ...until done */ cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", REST_COMPLETE); } else if (out_val[0] == '*') { /* ...a lot */ cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", REST_ALL_POINTS); } else if (out_val[0] == '!') { /* ...until HP or SP filled */ cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", REST_SOME_POINTS); } else { /* ...some */ int turns = atoi(out_val); if (turns <= 0) return; if (turns > 9999) turns = 9999; cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", turns); } }
/** * ------------------------------------------------------------------------ * The rolling bit of the roller. * ------------------------------------------------------------------------ */ 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; /* 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 previous roll"); 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(); /* Analyse the command */ if (ch.code == ESCAPE) { /* Back out */ next = BIRTH_BACK; } else if (ch.code == KC_ENTER) { /* 'Enter' accepts the roll */ next = BIRTH_NAME_CHOICE; } else if ((ch.code == ' ') || (ch.code == 'r')) { /* Reroll this character */ cmdq_push(CMD_ROLL_STATS); prev_roll = TRUE; } else if (prev_roll && (ch.code == 'p')) { /* Previous character */ cmdq_push(CMD_PREV_STATS); } else if (ch.code == KTRL('X')) { /* Quit */ quit(NULL); } else if (ch.code == '?') { /* Help XXX */ do_cmd_help(); } else { /* Nothing handled directly here */ bell("Illegal roller command!"); } return next; }
/** * Rest (restores hit points and mana and such) */ void do_cmd_rest(struct command *cmd) { int n; /* XXX-AS need to insert UI here */ if (cmd_get_arg_choice(cmd, "choice", &n) != CMD_OK) return; /* * A little sanity checking on the input - only the specified negative * values are valid. */ if (n < 0 && !player_resting_is_special(n)) return; /* Do some upkeep on the first turn of rest */ if (!player_is_resting(player)) { player->searching = false; player->upkeep->update |= (PU_BONUS); /* If a number of turns was entered, remember it */ if (n > 1) player_set_resting_repeat_count(player, n); else if (n == 1) /* If we're repeating the command, use the same count */ n = player_get_resting_repeat_count(player); } /* Set the counter, and stop if told to */ player_resting_set_count(player, n); if (!player_is_resting(player)) return; /* Take a turn */ player_resting_step_turn(player); /* Redraw the state if requested */ handle_stuff(player); /* Prepare to continue, or cancel and clean up */ if (player_resting_count(player) > 0) { cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", n - 1); } else if (player_resting_is_special(n)) { cmdq_push(CMD_REST); cmd_set_arg_choice(cmdq_peek(), "choice", n); player_set_resting_repeat_count(player, 0); } else { player_resting_cancel(player, false); } }
static enum birth_stage point_based_command(void) { static int stat = 0; struct keypress ch; enum birth_stage next = BIRTH_POINTBASED; /* Place cursor just after cost of current stat */ Term_gotoxy(COSTS_COL + 4, COSTS_ROW + stat); /* Get key */ ch = inkey(); if (ch.code == KTRL('X')) { quit(NULL); } else if (ch.code == ESCAPE) { /* Go back a step, or back to the start of this step */ next = BIRTH_BACK; } else if (ch.code == 'r' || ch.code == 'R') { cmdq_push(CMD_RESET_STATS); cmd_set_arg_choice(cmdq_peek(), "choice", FALSE); } else if (ch.code == KC_ENTER) { /* Done */ next = BIRTH_NAME_CHOICE; } else { int dir = target_dir(ch); /* Prev stat, looping round to the bottom when going off the top */ if (dir == 8) stat = (stat + STAT_MAX - 1) % STAT_MAX; /* Next stat, looping round to the top when going off the bottom */ if (dir == 2) stat = (stat + 1) % STAT_MAX; /* Decrease stat (if possible) */ if (dir == 4) { cmdq_push(CMD_SELL_STAT); cmd_set_arg_choice(cmdq_peek(), "choice", stat); } /* Increase stat (if possible) */ if (dir == 6) { cmdq_push(CMD_BUY_STAT); cmd_set_arg_choice(cmdq_peek(), "choice", stat); } } return next; }
/** * ------------------------------------------------------------------------ * 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 = BIRTH_RESET; /* Prompt for it */ prt(prompt, Term->hgt - 1, Term->wid / 2 - strlen(prompt) / 2); /* Get a key */ ke = inkey(); /* Start over */ if (ke.code == 'S' || ke.code == 's') { next = BIRTH_RESET; } else if (ke.code == KTRL('X')) { quit(NULL); } else if (ke.code == ESCAPE) { next = BIRTH_BACK; } else { cmdq_push(CMD_ACCEPT_CHARACTER); next = BIRTH_COMPLETE; } /* Clear prompt */ clear_from(23); return next; }
/** * Front-end command which fires at the nearest target with default ammo. */ void do_cmd_fire_at_nearest(void) { int i, dir = DIR_TARGET; struct object *ammo = NULL; struct object *bow = equipped_item_by_slot_name(player, "shooting"); /* Require a usable launcher */ if (!bow || !player->state.ammo_tval) { msg("You have nothing to fire with."); return; } /* Find first eligible ammo in the quiver */ for (i = 0; i < z_info->quiver_size; i++) { if (!player->upkeep->quiver[i]) continue; if (player->upkeep->quiver[i]->tval != player->state.ammo_tval) continue; ammo = player->upkeep->quiver[i]; break; } /* Require usable ammo */ if (!ammo) { msg("You have no ammunition in the quiver to fire."); return; } /* Require foe */ if (!target_set_closest(TARGET_KILL | TARGET_QUIET)) return; /* Fire! */ cmdq_push(CMD_FIRE); cmd_set_arg_item(cmdq_peek(), "item", ammo); cmd_set_arg_target(cmdq_peek(), "target", dir); }
int test_prefs(void *state) { bool error = FALSE; graphics_mode *mode; /* This is a bit of a hack to ensure we have a player struct set up */ /* Otherwise race/class dependent graphics will crash */ cmdq_push(CMD_BIRTH_RESET); cmdq_execute(CMD_BIRTH); event_add_handler(EVENT_MESSAGE, getmsg, &error); for (mode = graphics_modes; mode; mode = mode->pNext) { /* Skip 'normal' */ if (mode->grafID == 0) continue; printf("Testing mode '%s'.\n", mode->menuname); /* Load pref file */ use_graphics = mode->grafID; reset_visuals(TRUE); } eq(error, FALSE); ok; }
/** * Verify the suicide command */ void textui_cmd_suicide(void) { /* Flush input */ event_signal(EVENT_INPUT_FLUSH); /* Verify */ if (player->total_winner) { if (!get_check("Do you want to retire? ")) return; } else { struct keypress ch; if (!get_check("Do you really want to commit suicide? ")) return; /* Special Verification for suicide */ prt("Please verify SUICIDE by typing the '@' sign: ", 0, 0); event_signal(EVENT_INPUT_FLUSH); ch = inkey(); prt("", 0, 0); if (ch.code != '@') return; } cmdq_push(CMD_SUICIDE); }
int test_stairs2(void *state) { /* Load the saved game */ eq(savefile_load("Test1", FALSE), TRUE); cmdq_push(CMD_WALK); cmd_set_arg_direction(cmdq_peek(), "direction", 4); run_game_loop(); cmdq_push(CMD_WALK); cmd_set_arg_direction(cmdq_peek(), "direction", 6); run_game_loop(); cmdq_push(CMD_GO_DOWN); run_game_loop(); eq(player->depth, 1); ok; }
int test_newgame(void *state) { /* Try making a new game */ cmdq_push(CMD_BIRTH_INIT); cmdq_push(CMD_BIRTH_RESET); cmdq_push(CMD_CHOOSE_RACE); cmd_set_arg_choice(cmdq_peek(), "choice", 0); cmdq_push(CMD_CHOOSE_CLASS); cmd_set_arg_choice(cmdq_peek(), "choice", 0); cmdq_push(CMD_ROLL_STATS); cmdq_push(CMD_NAME_CHOICE); cmd_set_arg_string(cmdq_peek(), "name", "Tester"); cmdq_push(CMD_ACCEPT_CHARACTER); cmdq_execute(CMD_BIRTH); eq(player->is_dead, FALSE); cave_generate(&cave, player); on_new_level(); noteq(cave, NULL); eq(player->chp, player->mhp); eq(player->food, PY_FOOD_FULL - 1); /* Should be all set up to save properly now */ eq(savefile_save("Test1"), TRUE); /* Make sure it saved properly */ eq(file_exists("Test1"), TRUE); ok; }
int test_stairs1(void *state) { /* Load the saved game */ eq(savefile_load("Test1", FALSE), TRUE); cmdq_push(CMD_GO_DOWN); run_game_loop(); eq(player->depth, 1); ok; }
int test_drop_pickup(void *state) { /* Load the saved game */ eq(savefile_load("Test1", FALSE), TRUE); cmdq_push(CMD_WALK); cmd_set_arg_direction(cmdq_peek(), "direction", 4); run_game_loop(); if (player->upkeep->inven[0]->number > 1) { cmdq_push(CMD_DROP); cmd_set_arg_item(cmdq_peek(), "item", player->upkeep->inven[0]); cmd_set_arg_number(cmdq_peek(), "quantity", 1); run_game_loop(); eq(square_object(cave, player->py, player->px)->number, 1); cmdq_push(CMD_AUTOPICKUP); run_game_loop(); } eq(square_object(cave, player->py, player->px), NULL); ok; }
/** * ------------------------------------------------------------------------ * Asking for the player's chosen name. * ------------------------------------------------------------------------ */ static enum birth_stage get_name_command(void) { enum birth_stage next; char name[32]; if (get_character_name(name, sizeof(name))) { cmdq_push(CMD_NAME_CHOICE); cmd_set_arg_string(cmdq_peek(), "name", name); next = BIRTH_HISTORY_CHOICE; } else { next = BIRTH_BACK; } return next; }
/** * Drop all {ignore}able items. */ void ignore_drop(void) { struct object *obj; /* Scan through the slots backwards */ for (obj = gear_last_item(); obj; obj = obj->prev) { /* Skip non-objects and unignoreable objects */ assert(obj->kind); if (!ignore_item_ok(obj)) continue; /* Check for !d (no drop) inscription */ if (!check_for_inscrip(obj, "!d") && !check_for_inscrip(obj, "!*")) { /* Confirm the drop if the item is equipped. */ if (object_is_equipped(player->body, obj)) { if (!verify_object("Really take off and drop", obj)) { /* Hack - inscribe the item with !d to prevent repeated * confirmations. */ const char *inscription = quark_str(obj->note); if (inscription == NULL) { obj->note = quark_add("!d"); } else { char buffer[1024]; my_strcpy(buffer, inscription, sizeof(buffer)); my_strcat(buffer, "!d", sizeof(buffer)); obj->note = quark_add(buffer); } continue; } } /* We're allowed to drop it. */ if (!square_isshop(cave, player->py, player->px)) { player->upkeep->dropping = true; cmdq_push(CMD_DROP); cmd_set_arg_item(cmdq_peek(), "item", obj); cmd_set_arg_number(cmdq_peek(), "quantity", obj->number); } } } /* Update the gear */ player->upkeep->update |= (PU_INVEN); /* Combine/reorder the pack */ player->upkeep->notice |= (PN_COMBINE); }
int test_magic_missile(void *state) { /* Try making a new game */ cmdq_push(CMD_BIRTH_INIT); cmdq_push(CMD_BIRTH_RESET); cmdq_push(CMD_CHOOSE_RACE); cmd_set_arg_choice(cmdq_peek(), "choice", 4); cmdq_push(CMD_CHOOSE_CLASS); cmd_set_arg_choice(cmdq_peek(), "choice", 1); cmdq_push(CMD_ROLL_STATS); cmdq_push(CMD_NAME_CHOICE); cmd_set_arg_string(cmdq_peek(), "name", "Tyrion"); cmdq_push(CMD_ACCEPT_CHARACTER); cmdq_execute(CMD_BIRTH); eq(player->is_dead, FALSE); cave_generate(&cave, player); on_new_level(); notnull(cave); eq(player->chp, player->mhp); eq(player->food, PY_FOOD_FULL - 1); cmdq_push(CMD_STUDY); cmd_set_arg_choice(cmdq_peek(), "spell", 0); run_game_loop(); cmdq_push(CMD_CAST); cmd_set_arg_choice(cmdq_peek(), "spell", 0); cmd_set_arg_target(cmdq_peek(), "target", 2); run_game_loop(); noteq(player->csp, player->msp); ok; }
/** * ------------------------------------------------------------------------ * Allowing the player to choose their history. * ------------------------------------------------------------------------ */ static enum birth_stage get_history_command(void) { enum birth_stage next = 0; struct keypress ke; char old_history[240]; /* Save the original history */ my_strcpy(old_history, player->history, sizeof(old_history)); /* Ask for some history */ prt("Accept character history? [y/n]", 0, 0); ke = inkey(); /* Quit, go back, change history, or accept */ if (ke.code == KTRL('X')) { quit(NULL); } else if (ke.code == ESCAPE) { next = BIRTH_BACK; } else if (ke.code == 'N' || ke.code == 'n') { char history[240]; my_strcpy(history, player->history, sizeof(history)); switch (edit_text(history, sizeof(history))) { case -1: next = BIRTH_BACK; case 0: cmdq_push(CMD_HISTORY_CHOICE); cmd_set_arg_string(cmdq_peek(), "history", history); next = BIRTH_HISTORY_CHOICE; } } else { next = BIRTH_FINAL_CONFIRM; } return next; }
/** * This is called when we receive a request for a command in the birth * process. * The birth process continues until we send a final character confirmation * command (or quit), so this is effectively called in a loop by the main * game. * * We're imposing a step-based system onto the main game here, so we need * to keep track of where we're up to, where each step moves on to, etc. */ int textui_do_birth(void) { enum birth_stage current_stage = BIRTH_RESET; enum birth_stage prev; enum birth_stage roller = BIRTH_RESET; enum birth_stage next = current_stage; bool done = FALSE; cmdq_push(CMD_BIRTH_INIT); cmdq_execute(CMD_BIRTH); while (!done) { switch (current_stage) { case BIRTH_RESET: { cmdq_push(CMD_BIRTH_RESET); roller = BIRTH_RESET; if (quickstart_allowed) next = BIRTH_QUICKSTART; else next = BIRTH_RACE_CHOICE; break; } case BIRTH_QUICKSTART: { display_player(0); next = textui_birth_quickstart(); if (next == BIRTH_COMPLETE) done = TRUE; break; } case BIRTH_CLASS_CHOICE: case BIRTH_RACE_CHOICE: case BIRTH_ROLLER_CHOICE: { struct menu *menu = &race_menu; cmd_code command = CMD_CHOOSE_RACE; Term_clear(); print_menu_instructions(); if (current_stage > BIRTH_RACE_CHOICE) { menu_refresh(&race_menu, FALSE); menu = &class_menu; command = CMD_CHOOSE_CLASS; } if (current_stage > BIRTH_CLASS_CHOICE) { menu_refresh(&class_menu, FALSE); menu = &roller_menu; } next = menu_question(current_stage, menu, command); if (next == BIRTH_BACK) next = current_stage - 1; /* Make sure the character gets reset before quickstarting */ if (next == BIRTH_QUICKSTART) next = BIRTH_RESET; break; } case BIRTH_POINTBASED: { roller = BIRTH_POINTBASED; if (prev > BIRTH_POINTBASED) point_based_start(); next = point_based_command(); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; if (next != BIRTH_POINTBASED) point_based_stop(); break; } case BIRTH_ROLLER: { roller = BIRTH_ROLLER; next = roller_command(prev < BIRTH_ROLLER); if (next == BIRTH_BACK) next = BIRTH_ROLLER_CHOICE; break; } case BIRTH_NAME_CHOICE: { if (prev < BIRTH_NAME_CHOICE) display_player(0); next = get_name_command(); if (next == BIRTH_BACK) next = roller; break; } case BIRTH_HISTORY_CHOICE: { if (prev < BIRTH_HISTORY_CHOICE) display_player(0); next = get_history_command(); if (next == BIRTH_BACK) next = BIRTH_NAME_CHOICE; break; } case BIRTH_FINAL_CONFIRM: { if (prev < BIRTH_FINAL_CONFIRM) display_player(0); next = get_confirm_command(); if (next == BIRTH_BACK) next = BIRTH_HISTORY_CHOICE; if (next == BIRTH_COMPLETE) done = TRUE; break; } default: { /* Remove dodgy compiler warning, */ } } prev = current_stage; current_stage = next; /* Execute whatever commands have been sent */ cmdq_execute(CMD_BIRTH); } return 0; }
/** * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int y = player->py + ddy[dir]; int x = player->px + ddx[dir]; int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); bool alterable = (square_isknowntrap(cave, y, x) || square_iscloseddoor(cave, y, x)); /* Attack monsters, alter traps/doors on movement, hit obstacles or move */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(mon)) { become_aware(mon); /* Mimic wakes up */ mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { py_attack(y, x); } } else if (disarm && square_isknown(cave, y, x) && alterable) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } else if (player->upkeep->running && square_isknowntrap(cave, y, x)) { /* Stop running before known traps */ disturb(player, 0); } else if (!square_ispassable(cave, y, x)) { disturb(player, 0); /* Notice unknown obstacles, mention known obstacles */ if (!square_isknown(cave, y, x)) { if (square_isrubble(cave, y, x)) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else if (square_iscloseddoor(cave, y, x)) { msgt(MSG_HITWALL, "You feel a door blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } } else { if (square_isrubble(cave, y, x)) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (square_iscloseddoor(cave, y, x)) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } else { /* Move player */ monster_swap(player->py, player->px, y, x); /* Handle store doors, or notice objects */ if (square_isshop(cave, y, x)) { disturb(player, 0); event_signal(EVENT_ENTER_STORE); event_remove_handler_type(EVENT_ENTER_STORE); event_signal(EVENT_USE_STORE); event_remove_handler_type(EVENT_USE_STORE); event_signal(EVENT_LEAVE_STORE); event_remove_handler_type(EVENT_LEAVE_STORE); } else { square_know_pile(cave, y, x); cmdq_push(CMD_AUTOPICKUP); } /* Discover invisible traps, set off visible ones */ if (square_issecrettrap(cave, y, x)) { disturb(player, 0); hit_trap(y, x); } else if (square_isknowntrap(cave, y, x)) { disturb(player, 0); hit_trap(y, x); } /* Update view and search */ update_view(cave, player); search(); } player->upkeep->running_firststep = false; }
/** * Process player commands from the command queue, finishing when there is a * command using energy (any regular game command), or we run out of commands * and need another from the user, or the character changes level or dies, or * the game is stopped. * * Notice the annoying code to handle "pack overflow", which * must come first just in case somebody manages to corrupt * the savefiles by clever use of menu commands or something. (Can go? NRM) * * Notice the annoying code to handle "monster memory" changes, * which allows us to avoid having to update the window flags * every time we change any internal monster memory field, and * also reduces the number of times that the recall window must * be redrawn. */ void process_player(void) { /* Check for interrupts */ player_resting_complete_special(player); event_signal(EVENT_CHECK_INTERRUPT); /* Repeat until energy is reduced */ do { /* Refresh */ notice_stuff(player); handle_stuff(player); event_signal(EVENT_REFRESH); /* Hack -- Pack Overflow */ pack_overflow(NULL); /* Assume free turn */ player->upkeep->energy_use = 0; /* Dwarves detect treasure */ if (player_has(player, PF_SEE_ORE)) { /* Only if they are in good shape */ if (!player->timed[TMD_IMAGE] && !player->timed[TMD_CONFUSED] && !player->timed[TMD_AMNESIA] && !player->timed[TMD_STUN] && !player->timed[TMD_PARALYZED] && !player->timed[TMD_TERROR] && !player->timed[TMD_AFRAID]) effect_simple(EF_DETECT_GOLD, "3d3", 1, 0, 0, NULL); } /* Paralyzed or Knocked Out player gets no turn */ if ((player->timed[TMD_PARALYZED]) || (player->timed[TMD_STUN] >= 100)) cmdq_push(CMD_SLEEP); /* Prepare for the next command */ if (cmd_get_nrepeats() > 0) event_signal(EVENT_COMMAND_REPEAT); else { /* Check monster recall */ if (player->upkeep->monster_race) player->upkeep->redraw |= (PR_MONSTER); /* Place cursor on player/target */ event_signal(EVENT_REFRESH); } /* Get a command from the queue if there is one */ if (!cmdq_pop(CMD_GAME)) break; if (!player->upkeep->playing) break; process_player_cleanup(); } while (!player->upkeep->energy_use && !player->is_dead && !player->upkeep->generate_level); /* Notice stuff (if needed) */ notice_stuff(player); }
/** * Handle "target" and "look". * * Note that this code can be called from "get_aim_dir()". * * Currently, when "flag" is true, that is, when * "interesting" grids are being used, and a directional key is used, we * only scroll by a single panel, in the direction requested, and check * for any interesting grids on that panel. The "correct" solution would * actually involve scanning a larger set of grids, including ones in * panels which are adjacent to the one currently scanned, but this is * overkill for this function. XXX XXX * * Hack -- targetting/observing an "outer border grid" may induce * problems, so this is not currently allowed. * * The player can use the direction keys to move among "interesting" * grids in a heuristic manner, or the "space", "+", and "-" keys to * move through the "interesting" grids in a sequential manner, or * can enter "location" mode, and use the direction keys to move one * grid at a time in any direction. The "t" (set target) command will * only target a monster (as opposed to a location) if the monster is * target_able and the "interesting" mode is being used. * * The current grid is described using the "look" method above, and * a new command may be entered at any time, but note that if the * "TARGET_LOOK" bit flag is set (or if we are in "location" mode, * where "space" has no obvious meaning) then "space" will scan * through the description of the current grid until done, instead * of immediately jumping to the next "interesting" grid. This * allows the "target" command to retain its old semantics. * * The "*", "+", and "-" keys may always be used to jump immediately * to the next (or previous) interesting grid, in the proper mode. * * The "return" key may always be used to scan through a complete * grid description (forever). * * This command will cancel any old target, even if used from * inside the "look" command. * * * 'mode' is one of TARGET_LOOK or TARGET_KILL. * 'x' and 'y' are the initial position of the target to be highlighted, * or -1 if no location is specified. * Returns TRUE if a target has been successfully set, FALSE otherwise. */ bool target_set_interactive(int mode, int x, int y) { int py = player->py; int px = player->px; int path_n; struct loc path_g[256]; int i, d, m, t, bd; int wid, hgt, help_prompt_loc; bool done = FALSE; bool flag = TRUE; bool help = FALSE; ui_event press; /* These are used for displaying the path to the target */ wchar_t *path_char = mem_zalloc(z_info->max_range * sizeof(wchar_t)); int *path_attr = mem_zalloc(z_info->max_range * sizeof(int)); struct point_set *targets; /* If we haven't been given an initial location, start on the player, otherwise honour it by going into "free targetting" mode. */ if (x == -1 || y == -1) { x = player->px; y = player->py; } else { flag = FALSE; } /* Cancel target */ target_set_monster(0); /* Calculate the window location for the help prompt */ Term_get_size(&wid, &hgt); help_prompt_loc = hgt - 1; /* Display the help prompt */ prt("Press '?' for help.", help_prompt_loc, 0); /* Prepare the target set */ targets = target_get_monsters(mode); /* Start near the player */ m = 0; /* Interact */ while (!done) { bool path_drawn = FALSE; /* Interesting grids if chosen and there are any, otherwise arbitrary */ if (flag && point_set_size(targets)) { y = targets->pts[m].y; x = targets->pts[m].x; /* Adjust panel if needed */ if (adjust_panel_help(y, x, help)) handle_stuff(player); /* Update help */ if (help) { bool good_target = target_able(square_monster(cave, y, x)); target_display_help(good_target, !(flag && point_set_size(targets))); } /* Find the path. */ path_n = project_path(path_g, z_info->max_range, py, px, y, x, PROJECT_THRU); /* Draw the path in "target" mode. If there is one */ if (mode & (TARGET_KILL)) path_drawn = draw_path(path_n, path_g, path_char, path_attr, py, px); /* Describe and Prompt */ press = target_set_interactive_aux(y, x, mode); /* Remove the path */ if (path_drawn) load_path(path_n, path_g, path_char, path_attr); /* Assume no "direction" */ d = 0; /* Analyze */ if (press.type == EVT_MOUSE) { if (press.mouse.button == 3) { /* give the target selection command */ press.mouse.button = 2; press.mouse.mods = KC_MOD_CONTROL; } if (press.mouse.button == 2) { y = KEY_GRID_Y(press); x = KEY_GRID_X(press); if (press.mouse.mods & KC_MOD_CONTROL) { /* same as keyboard target selection command below */ struct monster *m = square_monster(cave, y, x); if (target_able(m)) { /* Set up target information */ monster_race_track(player->upkeep, m->race); health_track(player->upkeep, m); target_set_monster(m); done = TRUE; } else { bell("Illegal target!"); } } else if (press.mouse.mods & KC_MOD_ALT) { /* go to spot - same as 'g' command below */ cmdq_push(CMD_PATHFIND); cmd_set_arg_point(cmdq_peek(), "point", y, x); done = TRUE; } else { /* cancel look mode */ done = TRUE; } } else { y = KEY_GRID_Y(press); x = KEY_GRID_X(press); if (square_monster(cave, y, x) || square_object(cave, y, x)) { /* reset the flag, to make sure we stay in this * mode if something is actually there */ flag = FALSE; /* scan the interesting list and see if there is * anything here */ for (i = 0; i < point_set_size(targets); i++) { if ((y == targets->pts[i].y) && (x == targets->pts[i].x)) { m = i; flag = TRUE; break; } } } else { flag = FALSE; } } } else switch (press.key.code) { case ESCAPE: case 'q': { done = TRUE; break; } case ' ': case '*': case '+': { if (++m == point_set_size(targets)) m = 0; break; } case '-': { if (m-- == 0) m = point_set_size(targets) - 1; break; } case 'p': { /* Recenter around player */ verify_panel(); /* Handle stuff */ handle_stuff(player); y = player->py; x = player->px; } case 'o': { flag = FALSE; break; } case 'm': { break; } case 't': case '5': case '0': case '.': { struct monster *m = square_monster(cave, y, x); if (target_able(m)) { health_track(player->upkeep, m); target_set_monster(m); done = TRUE; } else { bell("Illegal target!"); } break; } case 'g': { cmdq_push(CMD_PATHFIND); cmd_set_arg_point(cmdq_peek(), "point", y, x); done = TRUE; break; } case '?': { help = !help; /* Redraw main window */ player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP); Term_clear(); handle_stuff(player); if (!help) prt("Press '?' for help.", help_prompt_loc, 0); break; } default: { /* Extract direction */ d = target_dir(press.key); /* Oops */ if (!d) bell("Illegal command for target mode!"); break; } } /* Hack -- move around */ if (d) { int old_y = targets->pts[m].y; int old_x = targets->pts[m].x; /* Find a new monster */ i = target_pick(old_y, old_x, ddy[d], ddx[d], targets); /* Scroll to find interesting grid */ if (i < 0) { int old_wy = Term->offset_y; int old_wx = Term->offset_x; /* Change if legal */ if (change_panel(d)) { /* Recalculate interesting grids */ point_set_dispose(targets); targets = target_get_monsters(mode); /* Find a new monster */ i = target_pick(old_y, old_x, ddy[d], ddx[d], targets); /* Restore panel if needed */ if ((i < 0) && modify_panel(Term, old_wy, old_wx)) { /* Recalculate interesting grids */ point_set_dispose(targets); targets = target_get_monsters(mode); } /* Handle stuff */ handle_stuff(player); } } /* Use interesting grid if found */ if (i >= 0) m = i; } } else { /* Update help */ if (help) { bool good_target = target_able(square_monster(cave, y, x)); target_display_help(good_target, !(flag && point_set_size(targets))); } /* Find the path. */ path_n = project_path(path_g, z_info->max_range, py, px, y, x, PROJECT_THRU); /* Draw the path in "target" mode. If there is one */ if (mode & (TARGET_KILL)) path_drawn = draw_path (path_n, path_g, path_char, path_attr, py, px); /* Describe and Prompt (enable "TARGET_LOOK") */ press = target_set_interactive_aux(y, x, mode | TARGET_LOOK); /* Remove the path */ if (path_drawn) load_path(path_n, path_g, path_char, path_attr); /* Assume no direction */ d = 0; /* Analyze the keypress */ if (press.type == EVT_MOUSE) { if (press.mouse.button == 3) { /* give the target selection command */ press.mouse.button = 2; press.mouse.mods = KC_MOD_CONTROL; } if (press.mouse.button == 2) { if (mode & (TARGET_KILL)) { if ((y == KEY_GRID_Y(press)) && (x == KEY_GRID_X(press))) { d = -1; } } y = KEY_GRID_Y(press); x = KEY_GRID_X(press); if (press.mouse.mods & KC_MOD_CONTROL) { /* same as keyboard target selection command below */ target_set_location(y, x); done = TRUE; } else if (press.mouse.mods & KC_MOD_ALT) { /* go to spot - same as 'g' command below */ cmdq_push(CMD_PATHFIND); cmd_set_arg_point(cmdq_peek(), "point", y, x); done = TRUE; } else { /* cancel look mode */ done = TRUE; if (d == -1) { target_set_location(y, x); d = 0; } } } else { int dungeon_hgt = cave->height; int dungeon_wid = cave->width; y = KEY_GRID_Y(press); x = KEY_GRID_X(press); if (press.mouse.y <= 1) { /* move the screen north */ y--; } else if (press.mouse.y >= (Term->hgt - 2)) { /* move the screen south */ y++; } else if (press.mouse.x <= COL_MAP) { /* move the screen in west */ x--; } else if (press.mouse.x >= (Term->wid - 2)) { /* move the screen east */ x++; } if (y < 0) y = 0; if (x < 0) x = 0; if (y >= dungeon_hgt-1) y = dungeon_hgt-1; if (x >= dungeon_wid-1) x = dungeon_wid-1; /* Adjust panel if needed */ if (adjust_panel_help(y, x, help)) { /* Handle stuff */ handle_stuff(player); /* Recalculate interesting grids */ point_set_dispose(targets); targets = target_get_monsters(mode); } if (square_monster(cave, y, x) || square_object(cave, y, x)) { /* scan the interesting list and see if there in * anything here */ for (i = 0; i < point_set_size(targets); i++) { if ((y == targets->pts[i].y) && (x == targets->pts[i].x)) { m = i; flag = TRUE; break; } } } else { flag = FALSE; } } } else switch (press.key.code) { case ESCAPE: case 'q': { done = TRUE; break; } case ' ': case '*': case '+': case '-': { break; } case 'p': { /* Recenter around player */ verify_panel(); /* Handle stuff */ handle_stuff(player); y = player->py; x = player->px; } case 'o': { break; } case 'm': { flag = TRUE; m = 0; bd = 999; /* Pick a nearby monster */ for (i = 0; i < point_set_size(targets); i++) { t = distance(y, x, targets->pts[i].y, targets->pts[i].x); /* Pick closest */ if (t < bd) { m = i; bd = t; } } /* Nothing interesting */ if (bd == 999) flag = FALSE; break; } case 't': case '5': case '0': case '.': { target_set_location(y, x); done = TRUE; break; } case 'g': { cmdq_push(CMD_PATHFIND); cmd_set_arg_point(cmdq_peek(), "point", y, x); done = TRUE; break; } case '?': { help = !help; /* Redraw main window */ player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP); Term_clear(); handle_stuff(player); if (!help) prt("Press '?' for help.", help_prompt_loc, 0); break; } default: { /* Extract a direction */ d = target_dir(press.key); /* Oops */ if (!d) bell("Illegal command for target mode!"); break; } } /* Handle "direction" */ if (d) { int dungeon_hgt = cave->height; int dungeon_wid = cave->width; /* Move */ x += ddx[d]; y += ddy[d]; /* Slide into legality */ if (x >= dungeon_wid - 1) x--; else if (x <= 0) x++; /* Slide into legality */ if (y >= dungeon_hgt - 1) y--; else if (y <= 0) y++; /* Adjust panel if needed */ if (adjust_panel_help(y, x, help)) { /* Handle stuff */ handle_stuff(player); /* Recalculate interesting grids */ point_set_dispose(targets); targets = target_get_monsters(mode); } } } } /* Forget */ point_set_dispose(targets); /* Redraw as necessary */ if (help) { player->upkeep->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP | PR_EQUIP); Term_clear(); } else { prt("", 0, 0); prt("", help_prompt_loc, 0); player->upkeep->redraw |= (PR_DEPTH | PR_STATUS); } /* Recenter around player */ verify_panel(); /* Handle stuff */ handle_stuff(player); mem_free(path_attr); mem_free(path_char); /* Failure to set target */ if (!target_is_set()) return (FALSE); /* Success */ return (TRUE); }
/** * Take one step along the current "run" path * * Called with a real direction to begin a new run, and with zero * to continue a run in progress. */ void run_step(int dir) { int x, y; /* Start or continue run */ if (dir) { /* Initialize */ run_init(dir); /* Hack -- Set the run counter */ player->upkeep->running = 1000; /* Calculate torch radius */ player->upkeep->update |= (PU_TORCH); } else { /* Continue running */ if (!player->upkeep->running_withpathfind) { /* Update regular running */ if (run_test()) { /* Disturb */ disturb(player, 0); return; } } else { /* Pathfinding */ if (pf_result_index < 0) { /* Abort if the path is finished */ disturb(player, 0); player->upkeep->running_withpathfind = FALSE; return; } else if (pf_result_index == 0) { /* Abort if we would hit a wall */ y = player->py + ddy[pf_result[pf_result_index] - '0']; x = player->px + ddx[pf_result[pf_result_index] - '0']; /* Known wall */ if (square_ismark(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = FALSE; return; } } else if (pf_result_index > 0) { /* If the player has computed a path that is going to end up * in a wall, we notice this and convert to a normal run. This * allows us to click on unknown areas to explore the map. * * We have to look ahead two, otherwise we don't know which is * the last direction moved and don't initialise the run * properly. */ y = player->py + ddy[pf_result[pf_result_index] - '0']; x = player->px + ddx[pf_result[pf_result_index] - '0']; /* Known wall */ if (square_ismark(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = FALSE; return; } /* Get step after */ y = y + ddy[pf_result[pf_result_index - 1] - '0']; x = x + ddx[pf_result[pf_result_index - 1] - '0']; /* Known wall, so run the direction we were going */ if (square_ismark(cave, y, x) && !square_ispassable(cave, y, x)) { player->upkeep->running_withpathfind = FALSE; run_init(pf_result[pf_result_index] - '0'); } } /* Now actually run the step if we're still going */ run_cur_dir = pf_result[pf_result_index--] - '0'; } } /* Decrease counter if it hasn't been cancelled */ if (player->upkeep->running) player->upkeep->running--; /* Take time */ player->upkeep->energy_use = z_info->move_energy; /* Move the player */ move_player(run_cur_dir, TRUE); /* Prepare the next step */ if (player->upkeep->running) { cmdq_push(CMD_RUN); cmd_set_arg_direction(cmdq_peek(), "direction", 0); } }
/** * Allow the user to select from the current menu, and return the * corresponding command to the game. Some actions are handled entirely * by the UI (displaying help text, for instance). */ static enum birth_stage menu_question(enum birth_stage current, struct menu *current_menu, cmd_code choice_command) { struct birthmenu_data *menu_data = menu_priv(current_menu); ui_event cx; enum birth_stage next = BIRTH_RESET; /* Print the question currently being asked. */ clear_question(); Term_putstr(QUESTION_COL, QUESTION_ROW, -1, COLOUR_YELLOW, menu_data->hint); current_menu->cmd_keys = "?=*\x18"; /* ?, =, *, <ctl-X> */ while (next == BIRTH_RESET) { /* Display the menu, wait for a selection of some sort to be made. */ cx = menu_select(current_menu, EVT_KBRD, FALSE); /* As all the menus are displayed in "hierarchical" style, we allow use of "back" (left arrow key or equivalent) to step back in the proces as well as "escape". */ if (cx.type == EVT_ESCAPE) { next = BIRTH_BACK; } else if (cx.type == EVT_SELECT) { if (current == BIRTH_ROLLER_CHOICE) { if (current_menu->cursor) { /* Do a first roll of the stats */ cmdq_push(CMD_ROLL_STATS); next = current + 2; } else { /* * Make sure we've got a point-based char to play with. * We call point_based_start here to make sure we get * an update on the points totals before trying to * display the screen. The call to CMD_RESET_STATS * forces a rebuying of the stats to give us up-to-date * totals. This is, it should go without saying, a hack. */ point_based_start(); cmdq_push(CMD_RESET_STATS); cmd_set_arg_choice(cmdq_peek(), "choice", TRUE); next = current + 1; } } else { cmdq_push(choice_command); cmd_set_arg_choice(cmdq_peek(), "choice", current_menu->cursor); next = current + 1; } } else if (cx.type == EVT_KBRD) { /* '*' chooses an option at random from those the game's provided */ if (cx.key.code == '*' && menu_data->allow_random) { current_menu->cursor = randint0(current_menu->count); cmdq_push(choice_command); cmd_set_arg_choice(cmdq_peek(), "choice", current_menu->cursor); menu_refresh(current_menu, FALSE); next = current + 1; } else if (cx.key.code == '=') { do_cmd_options_birth(); next = current; } else if (cx.key.code == KTRL('X')) { quit(NULL); } else if (cx.key.code == '?') { do_cmd_help(); } } } return next; }
/** * Take one step along the current "run" path * * Called with a real direction to begin a new run, and with zero * to continue a run in progress. */ void run_step(int dir) { /* Start or continue run */ if (dir) { /* Initialize */ run_init(dir); /* Hack -- Set the run counter */ player->upkeep->running = 1000; /* Calculate torch radius */ player->upkeep->update |= (PU_TORCH); } else { /* Continue running */ if (!player->upkeep->running_withpathfind) { /* Update regular running */ if (run_test()) { /* Disturb */ disturb(player, 0); return; } } else if (pf_result_index < 0) { /* Pathfinding, and the path is finished */ disturb(player, 0); player->upkeep->running_withpathfind = false; return; } else { int y = player->py + ddy[pf_result[pf_result_index] - '0']; int x = player->px + ddx[pf_result[pf_result_index] - '0']; if (pf_result_index == 0) { /* Known wall */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } } else if (pf_result_index > 0) { struct object *obj; /* If the player has computed a path that is going to end up * in a wall, we notice this and convert to a normal run. This * allows us to click on unknown areas to explore the map. * * We have to look ahead two, otherwise we don't know which is * the last direction moved and don't initialise the run * properly. */ y = player->py + ddy[pf_result[pf_result_index] - '0']; x = player->px + ddx[pf_result[pf_result_index] - '0']; /* Known wall */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } /* Visible monsters abort running */ if (cave->squares[y][x].mon > 0) { struct monster *mon = square_monster(cave, y, x); /* Visible monster */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } } /* Visible objects abort running */ for (obj = square_object(cave, y, x); obj; obj = obj->next) /* Visible object */ if (obj->known && !ignore_item_ok(obj)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } /* Get step after */ y = y + ddy[pf_result[pf_result_index - 1] - '0']; x = x + ddx[pf_result[pf_result_index - 1] - '0']; /* Known wall, so run the direction we were going */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { player->upkeep->running_withpathfind = false; run_init(pf_result[pf_result_index] - '0'); } } /* Now actually run the step if we're still going */ run_cur_dir = pf_result[pf_result_index--] - '0'; } } /* Decrease counter if it hasn't been cancelled */ if (player->upkeep->running) player->upkeep->running--; else if (!player->upkeep->running_withpathfind) return; /* Take time */ player->upkeep->energy_use = z_info->move_energy; /* Move the player; running straight into a trap == trying to disarm */ move_player(run_cur_dir, dir ? true : false); /* Prepare the next step */ if (player->upkeep->running) { cmdq_push(CMD_RUN); cmd_set_arg_direction(cmdq_peek(), "direction", 0); } }
/** * Move player in the given direction. * * This routine should only be called when energy has been expended. * * Note that this routine handles monsters in the destination grid, * and also handles attempting to move into walls/doors/rubble/etc. */ void move_player(int dir, bool disarm) { int py = player->py; int px = player->px; int y = py + ddy[dir]; int x = px + ddx[dir]; int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); bool alterable = (square_isknowntrap(cave, y, x) || square_iscloseddoor(cave, y, x)); /* Attack monsters, alter traps/doors on movement, hit obstacles or move */ if (m_idx > 0) { /* Mimics surprise the player */ if (is_mimicking(mon)) { become_aware(mon); /* Mimic wakes up */ mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false); } else { py_attack(y, x); } } else if (disarm && square_isknown(cave, y, x) && alterable) { /* Auto-repeat if not already repeating */ if (cmd_get_nrepeats() == 0) cmd_set_repeat(99); do_cmd_alter_aux(dir); } else if (player->upkeep->running && square_isknowntrap(cave, y, x)) { /* Stop running before known traps */ disturb(player, 0); } else if (!square_ispassable(cave, y, x)) { /* Disturb the player */ disturb(player, 0); /* Notice unknown obstacles, mention known obstacles */ if (!square_isknown(cave, y, x)) { if (square_isrubble(cave, y, x)) { msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else if (square_iscloseddoor(cave, y, x)) { msgt(MSG_HITWALL, "You feel a door blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } else { msgt(MSG_HITWALL, "You feel a wall blocking your way."); square_memorize(cave, y, x); square_light_spot(cave, y, x); } } else { if (square_isrubble(cave, y, x)) msgt(MSG_HITWALL, "There is a pile of rubble blocking your way."); else if (square_iscloseddoor(cave, y, x)) msgt(MSG_HITWALL, "There is a door blocking your way."); else msgt(MSG_HITWALL, "There is a wall blocking your way."); } } else { /* See if trap detection status will change */ bool old_dtrap = square_isdtrap(cave, py, px); bool new_dtrap = square_isdtrap(cave, y, x); /* Note the change in the detect status */ if (old_dtrap != new_dtrap) player->upkeep->redraw |= (PR_DTRAP); /* Disturb player if the player is about to leave the area */ if (player->upkeep->running && !player->upkeep->running_firststep && old_dtrap && !new_dtrap) { disturb(player, 0); return; } /* Move player */ monster_swap(py, px, y, x); /* New location */ y = py = player->py; x = px = player->px; /* Searching */ if (player->searching || (player->state.skills[SKILL_SEARCH_FREQUENCY] >= 50) || one_in_(50 - player->state.skills[SKILL_SEARCH_FREQUENCY])) search(false); /* Handle store doors, or notice objects */ if (square_isshop(cave, player->py, player->px)) { /* Disturb */ disturb(player, 0); event_signal(EVENT_ENTER_STORE); event_remove_handler_type(EVENT_ENTER_STORE); event_signal(EVENT_USE_STORE); event_remove_handler_type(EVENT_USE_STORE); event_signal(EVENT_LEAVE_STORE); event_remove_handler_type(EVENT_LEAVE_STORE); } else { /* Know objects, queue autopickup */ floor_pile_know(cave, player->py, player->px); cmdq_push(CMD_AUTOPICKUP); } /* Discover invisible traps, set off visible ones */ if (square_issecrettrap(cave, y, x)) { /* Disturb */ disturb(player, 0); /* Hit the trap. */ hit_trap(y, x); } else if (square_isknowntrap(cave, y, x)) { /* Disturb */ disturb(player, 0); /* Hit the trap */ hit_trap(y, x); } } player->upkeep->running_firststep = false; }