/** * 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); } }
/** * 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_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; }
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; }
/** * 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; }
/** * 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_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_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; }
/** * ------------------------------------------------------------------------ * 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; }
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; }
/** * 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); } }
/** * 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); } }
/** * 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; }