Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * ------------------------------------------------------------------------
 * 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);
	}
}
Beispiel #4
0
/**
 * ------------------------------------------------------------------------
 * 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;
}
Beispiel #5
0
/**
 * 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);
	}

}
Beispiel #6
0
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;
}
Beispiel #7
0
/**
 * ------------------------------------------------------------------------
 * 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;
}
Beispiel #8
0
/**
 * 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);
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
/**
 * ------------------------------------------------------------------------
 * 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;
}
Beispiel #16
0
/**
 * 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);
}
Beispiel #17
0
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;
}
Beispiel #18
0
/**
 * ------------------------------------------------------------------------
 * 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;
}
Beispiel #19
0
/**
 * 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;
}
Beispiel #20
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;
}
Beispiel #21
0
/**
 * 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);
}
Beispiel #23
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)
{
	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);
	}
}
Beispiel #24
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;
}
Beispiel #25
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);
	}
}
Beispiel #26
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;
}