예제 #1
0
/**
 * Calls a monster from the level and moves it to the desired spot
 */
int call_monster(int y, int x)
{
	int i, mon_count, choice;
	int oy, ox;
	int *mon_indices;
	struct monster *mon;

	mon_count = 0;

	for (i = 1; i < cave_monster_max(cave); i++) {
		mon = cave_monster(cave, i);

		/* Figure out how many good monsters there are */
		if (can_call_monster(y, x, mon)) mon_count++;
	}

	/* There were no good monsters on the level */
	if (mon_count == 0) return (0);

	/* Make the array */
	mon_indices = mem_zalloc(mon_count * sizeof(int));

	/* Reset mon_count */
	mon_count = 0;

	/* Now go through a second time and store the indices */
	for (i = 1; i < cave_monster_max(cave); i++) {
		mon = cave_monster(cave, i);
		
		/* Save the values of the good monster */
		if (can_call_monster(y, x, mon)){
			mon_indices[mon_count] = i;
			mon_count++;
		}
	}

	/* Pick one */
	choice = randint0(mon_count - 1);

	/* Get the lucky monster */
	mon = cave_monster(cave, mon_indices[choice]);
	mem_free(mon_indices);

	/* Extract monster location */
	oy = mon->fy;
	ox = mon->fx;

	/* Swap the moster */
	monster_swap(oy, ox, y, x);

	/* Wake it up */
	mon_clear_timed(mon, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE, false);

	/* Set it's energy to 0 */
	mon->energy = 0;

	return (mon->race->level);
}
예제 #2
0
/**
 * Try to push past / kill another monster.  Returns true on success.
 */
static bool process_monster_try_push(struct chunk *c, struct monster *mon,
									 const char *m_name, int nx, int ny)
{
	struct monster *mon1 = square_monster(c, ny, nx);
	struct monster_lore *lore = get_lore(mon->race);

	/* Kill weaker monsters */
	int kill_ok = rf_has(mon->race->flags, RF_KILL_BODY);

	/* Move weaker monsters if they can swap places */
	/* (not in a wall) */
	int move_ok = (rf_has(mon->race->flags, RF_MOVE_BODY) &&
				   square_ispassable(c, mon->fy, mon->fx));

	if (compare_monsters(mon, mon1) > 0) {
		/* Learn about pushing and shoving */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE)) {
			rf_on(lore->flags, RF_KILL_BODY);
			rf_on(lore->flags, RF_MOVE_BODY);
		}

		if (kill_ok || move_ok) {
			/* Get the names of the monsters involved */
			char n_name[80];
			monster_desc(n_name, sizeof(n_name), mon1, MDESC_IND_HID);

			/* Reveal mimics */
			if (is_mimicking(mon1))
				become_aware(mon1);

			/* Note if visible */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
				mflag_has(mon->mflag, MFLAG_VIEW))
				msg("%s %s %s.", m_name,
					kill_ok ? "tramples over" : "pushes past", n_name);

			/* Monster ate another monster */
			if (kill_ok)
				delete_monster(ny, nx);

			monster_swap(mon->fy, mon->fx, ny, nx);
			return true;
		} 
	}

	return false;
}
예제 #3
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;
}
예제 #4
0
파일: cmd1.c 프로젝트: tonberrytoby/angband
/*
 * 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 = p_ptr->py;
	int px = p_ptr->px;

	int y = py + ddy[dir];
	int x = px + ddx[dir];
	
	int m_idx = cave->m_idx[y][x];

	/* Attack monsters */
	if (m_idx > 0) {
		/* Mimics surprise the player */
		if (is_mimicking(m_idx)) {
			become_aware(m_idx);

			/* Mimic wakes up */
			mon_clear_timed(m_idx, MON_TMD_SLEEP, MON_TMD_FLG_NOMESSAGE);

		} else {
			py_attack(y, x);
		}
	}

	/* Optionally alter traps/doors on movement */
	else if (disarm && (cave->info[y][x] & CAVE_MARK) &&
			(cave_isknowntrap(cave, y, x) ||
			cave_iscloseddoor(cave, y, x)))
	{
		/* Auto-repeat if not already repeating */
		if (cmd_get_nrepeats() == 0)
			cmd_set_repeat(99);

		do_cmd_alter_aux(dir);
	}

	/* Cannot walk through walls */
	else if (!cave_floor_bold(y, x))
	{
		/* Disturb the player */
		disturb(p_ptr, 0, 0);

		/* Notice unknown obstacles */
		if (!(cave->info[y][x] & CAVE_MARK))
		{
			/* Rubble */
			if (cave->feat[y][x] == FEAT_RUBBLE)
			{
				msgt(MSG_HITWALL, "You feel a pile of rubble blocking your way.");
				cave->info[y][x] |= (CAVE_MARK);
				cave_light_spot(cave, y, x);
			}

			/* Closed door */
			else if (cave->feat[y][x] < FEAT_SECRET)
			{
				msgt(MSG_HITWALL, "You feel a door blocking your way.");
				cave->info[y][x] |= (CAVE_MARK);
				cave_light_spot(cave, y, x);
			}

			/* Wall (or secret door) */
			else
			{
				msgt(MSG_HITWALL, "You feel a wall blocking your way.");
				cave->info[y][x] |= (CAVE_MARK);
				cave_light_spot(cave, y, x);
			}
		}

		/* Mention known obstacles */
		else
		{
			if (cave->feat[y][x] == FEAT_RUBBLE)
				msgt(MSG_HITWALL, "There is a pile of rubble blocking your way.");
			else if (cave->feat[y][x] < FEAT_SECRET)
				msgt(MSG_HITWALL, "There is a door blocking your way.");
			else
				msgt(MSG_HITWALL, "There is a wall blocking your way.");
		}
	}

	/* Normal movement */
	else
	{
		/* See if trap detection status will change */
		bool old_dtrap = ((cave->info2[py][px] & (CAVE2_DTRAP)) != 0);
		bool new_dtrap = ((cave->info2[y][x] & (CAVE2_DTRAP)) != 0);

		/* Note the change in the detect status */
		if (old_dtrap != new_dtrap)
			p_ptr->redraw |= (PR_DTRAP);

		/* Disturb player if the player is about to leave the area */
		if (OPT(disturb_detect) && p_ptr->running && 
			!p_ptr->running_firststep && old_dtrap && !new_dtrap)
		{
			disturb(p_ptr, 0, 0);
			return;
		}

		/* Move player */
		monster_swap(py, px, y, x);
  
		/* New location */
		y = py = p_ptr->py;
		x = px = p_ptr->px;

		/* Searching */
		if (p_ptr->searching ||
				(p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] >= 50) ||
				one_in_(50 - p_ptr->state.skills[SKILL_SEARCH_FREQUENCY]))
			search(FALSE);

		/* Handle "store doors" */
		if ((cave->feat[p_ptr->py][p_ptr->px] >= FEAT_SHOP_HEAD) &&
			(cave->feat[p_ptr->py][p_ptr->px] <= FEAT_SHOP_TAIL))
		{
			/* Disturb */
			disturb(p_ptr, 0, 0);
			cmd_insert(CMD_ENTER_STORE);
		}

		/* All other grids (including traps) */
		else
		{
			/* Handle objects (later) */
			p_ptr->notice |= (PN_PICKUP);
		}


		/* Discover invisible traps */
		if (cave->feat[y][x] == FEAT_INVIS)
		{
			/* Disturb */
			disturb(p_ptr, 0, 0);

			/* Message */
			msg("You found a trap!");

			/* Pick a trap */
			pick_trap(y, x);

			/* Hit the trap */
			hit_trap(y, x);
		}

		/* Set off an visible trap */
		else if (cave_isknowntrap(cave, y, x))
		{
			/* Disturb */
			disturb(p_ptr, 0, 0);

			/* Hit the trap */
			hit_trap(y, x);
		}
	}

	p_ptr->running_firststep = FALSE;
}
예제 #5
0
/**
 * Process a monster
 *
 * In several cases, we directly update the monster lore
 *
 * Note that a monster is only allowed to "reproduce" if there
 * are a limited number of "reproducing" monsters on the current
 * level.  This should prevent the level from being "swamped" by
 * reproducing monsters.  It also allows a large mass of mice to
 * prevent a louse from multiplying, but this is a small price to
 * pay for a simple multiplication method.
 *
 * XXX Monster fear is slightly odd, in particular, monsters will
 * fixate on opening a door even if they cannot open it.  Actually,
 * the same thing happens to normal monsters when they hit a door
 *
 * In addition, monsters which *cannot* open or bash down a door
 * will still stand there trying to open it...  XXX XXX XXX
 *
 * Technically, need to check for monster in the way combined
 * with that monster being in a wall (or door?) XXX
 */
static void process_monster(struct chunk *c, struct monster *mon)
{
	struct monster_lore *lore = get_lore(mon->race);

	bool did_something = false;

	int i;
	int dir = 0;
	bool stagger = false;
	char m_name[80];

	/* Get the monster name */
	monster_desc(m_name, sizeof(m_name), mon, MDESC_CAPITAL | MDESC_IND_HID);

	/* Try to multiply - this can use up a turn */
	if (process_monster_multiply(c, mon))
		return;

	/* Attempt to cast a spell */
	if (make_attack_spell(mon)) return;

	/* Work out what kind of movement to use - AI or staggered movement */
	if (!process_monster_should_stagger(mon)) {
		if (!get_moves(c, mon, &dir)) return;
	} else {
		stagger = true;
	}

	/* Process moves */
	for (i = 0; i < 5 && !did_something; i++) {
		int oy = mon->fy;
		int ox = mon->fx;

		/* Get the direction (or stagger) */
		int d = (stagger ? ddd[randint0(8)] : side_dirs[dir][i]);

		/* Get the destination */
		int ny = oy + ddy[d];
		int nx = ox + ddx[d];

		/* Check if we can move */
		if (!process_monster_can_move(c, mon, m_name, nx, ny, &did_something))
			continue;

		/* Try to break the glyph if there is one.  This can happen multiple
		 * times per turn because failure does not break the loop */
		if (square_iswarded(c, ny, nx) &&
			!process_monster_glyph(c, mon, nx, ny))
			continue;

		/* The player is in the way. */
		if (square_isplayer(c, ny, nx)) {
			/* Learn about if the monster attacks */
			if (mflag_has(mon->mflag, MFLAG_VISIBLE))
				rf_on(lore->flags, RF_NEVER_BLOW);

			/* Some monsters never attack */
			if (rf_has(mon->race->flags, RF_NEVER_BLOW))
				continue;

			/* Otherwise, attack the player */
			make_attack_normal(mon, player);

			did_something = true;
			break;
		} else {
			/* Some monsters never move */
			if (rf_has(mon->race->flags, RF_NEVER_MOVE)) {
				/* Learn about lack of movement */
				if (mflag_has(mon->mflag, MFLAG_VISIBLE))
					rf_on(lore->flags, RF_NEVER_MOVE);

				return;
			}
		}

		/* A monster is in the way, try to push past/kill */
		if (square_monster(c, ny, nx)) {
			did_something = process_monster_try_push(c, mon, m_name, nx, ny);
		} else {
			/* Otherwise we can just move */
			monster_swap(oy, ox, ny, nx);
			did_something = true;
		}

		/* Scan all objects in the grid, if we reached it */
		if (mon == square_monster(c, ny, nx)) {
			monster_desc(m_name, sizeof(m_name), mon,
						 MDESC_CAPITAL | MDESC_IND_HID);
			process_monster_grab_objects(c, mon, m_name, nx, ny);
		}
	}

	if (did_something) {
		/* Learn about no lack of movement */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE))
			rf_on(lore->flags, RF_NEVER_MOVE);

		/* Possible disturb */
		if (mflag_has(mon->mflag, MFLAG_VISIBLE) &&
			mflag_has(mon->mflag, MFLAG_VIEW) && OPT(player, disturb_near))
			disturb(player, 0);		
	}

	/* Hack -- get "bold" if out of options */
	if (!did_something && mon->m_timed[MON_TMD_FEAR])
		mon_clear_timed(mon, MON_TMD_FEAR, MON_TMD_FLG_NOTIFY, false);

	/* If we see an unaware monster do something, become aware of it */
	if (did_something && mflag_has(mon->mflag, MFLAG_UNAWARE))
		become_aware(mon);
}
예제 #6
0
/**
 * Move player in the given direction, with the given "pickup" flag.
 *
 * 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/etc.
 */
void move_player(int dir)
{
    int py = p_ptr->py;
    int px = p_ptr->px;

    byte str_escape, dex_escape;

    /* Permit the player to move? */
    bool can_move = FALSE;

    /* Player is jumping off a cliff */
    bool falling = FALSE;

    /* Player hits a trap (always unless flying) */
    bool trapped = TRUE;

    int temp;
    int y, x;

    /* Find the result of moving */
    y = py + ddy[dir];
    x = px + ddx[dir];


    /* Hack -- attack monsters */
    if (cave_m_idx[y][x] > 0) {
	/* Attack */
	if (py_attack(y, x, TRUE))
	    return;
    }

    /* It takes some dexterity, or failing that strength, to get out of pits */
    if (cave_feat[p_ptr->py][p_ptr->px] == (FEAT_TRAP_HEAD + 0x01)) {
	str_escape = adj_dex_dis[p_ptr->state.stat_ind[A_STR]];
	dex_escape = adj_dex_dis[p_ptr->state.stat_ind[A_DEX]];

	/* First attempt to leap out of the pit, */
	if ((dex_escape + 1) * 2 < randint1(16)) {
	    /* then attempt to climb out of the pit. */
	    if (str_escape + 3 < randint1(16)) {
		/* Failure costs a turn. */
		msg_print("You remain stuck in the pit.");
		return;
	    } else
		msg_print("You clamber out of the pit.");
	} else
	    msg_print("You leap out of the pit.");
    }


    /* Option to disarm a visible trap. -TNB- */
    /* Hack - Rogues can walk over their own trap - BR */
    if (OPT(easy_alter) && (cave_feat[y][x] >= FEAT_TRAP_HEAD)
	&& (cave_feat[y][x] <= FEAT_TRAP_TAIL)) 
    {
	bool more = FALSE;
	/* Auto-repeat if not already repeating */
	if (cmd_get_nrepeats() == 0)
	    cmd_set_repeat(99);
	
	more = do_cmd_disarm_aux(y, x);

	/* Cancel repeat unless we may continue */
	if (!more)
	    disturb(0, 0);
	return;
    }

    /* Some terrain is impassable for the player, such as stone walls. */
    else if (!cave_passable_bold(y, x)) {
	/* Disturb the player */
	disturb(0, 0);

	/* Notice unknown obstacles */
	if (!(cave_info[y][x] & (CAVE_MARK))) {
	    /* Closed door */
	    if (cave_feat[y][x] < FEAT_SECRET) {
		message(MSG_HITWALL, 0, "You feel a door blocking your way.");
		cave_info[y][x] |= (CAVE_MARK);
		light_spot(y, x);
	    }

	    /* Wall (or secret door) */
	    else {
		message(MSG_HITWALL, 0, "You feel a wall blocking your way.");
		cave_info[y][x] |= (CAVE_MARK);
		light_spot(y, x);
	    }
	}

	/* Mention known obstacles */
	else {
	    /* Closed door */
	    if (cave_feat[y][x] < FEAT_SECRET) {
		/* Option to automatically open doors. -TNB- */
		if (OPT(easy_alter)) {
		    bool more = FALSE;

		    /* Auto-repeat if not already repeating */
		    if (cmd_get_nrepeats() == 0)
			cmd_set_repeat(99);
		    
		    /* Open the door */
		    more = do_cmd_open_aux(y, x);
		    
		    /* Cancel repeat unless we may continue */
		    if (!more)
			disturb(0, 0);
		    return;
		}
		
		/* Otherwise, a message. */
		message(MSG_HITWALL, 0, "There is a door blocking your way.");
	    }

	    /* Wall (or secret door) */
	    else {
		message(MSG_HITWALL, 0, "There is a wall blocking your way.");
	    }
	}

	/* Sound */
	sound(MSG_HITWALL);
    }

    /* Normal movement */
    else 
    {
	/*** Handle traversable terrain.  ***/
	switch (cave_feat[y][x]) {
	case FEAT_RUBBLE:
	    {
		/* Dwarves move easily through rubble */
		if (player_has(PF_DWARVEN))
		    can_move = TRUE;

		/* Bats, dragons can fly */
		else if ((p_ptr->schange == SHAPE_BAT)
			 || (p_ptr->schange == SHAPE_WYRM))
		    can_move = TRUE;

		else if (player_is_crossing == dir)
		{
		    can_move = TRUE;
		    player_is_crossing = 0;
		}
		else 
		{
		    player_is_crossing = dir;
		    cmd_insert(CMD_WALK);
		}

		break;
	    }
	case FEAT_TREE:
	case FEAT_TREE2:
	    {
		/* Druids, rangers, elves and ents (SJGU) slip easily under
		 * trees */
		if (((player_has(PF_WOODSMAN)) || (player_has(PF_ELVEN)))
		    || (player_has(PF_WOODEN)))
		    can_move = TRUE;

		/* Bats, dragons can fly */
		else if ((p_ptr->schange == SHAPE_BAT)
			 || (p_ptr->schange == SHAPE_WYRM))
		    can_move = TRUE;

		/* Allow movement only if partway through already. */
		else if (player_is_crossing == dir)
		{
		    can_move = TRUE;
		    player_is_crossing = 0;
		}
		else 
		{
		    player_is_crossing = dir;
		    cmd_insert(CMD_WALK);
		}
		
		break;
	    }
	case FEAT_WATER:	/* Water now slows rather than stopping -NRM- */
	    {
		/* Stop any run. */
		disturb(0, 0);

		can_move = TRUE;

		/* Speed will need updating */
		p_ptr->update |= PU_BONUS;

		break;
	    }
	case FEAT_LAVA:
	    {
		/* Assume player will continue. */
		temp = TRUE;

		/* Smart enough to stop running. */
		if (p_ptr->running) {
		    if (!get_check("Lava blocks your path.  Step into it? ")) {
			temp = FALSE;
			p_ptr->running = 0;
		    }
		}

		/* Smart enough to sense trouble. */
		else if ((!p_resist_pos(P_RES_FIRE))
			 || (!p_resist_strong(P_RES_FIRE)
			     && (p_ptr->chp <= 100))
			 || (!p_immune(P_RES_FIRE) && (p_ptr->chp <= 30))) {
		    if (!get_check
			("The heat of the lava scalds you! Really enter? ")) {
			temp = FALSE;
		    }
		}

		/* Enter if OK or confirmed. */
		if (temp) {
		    /* Can always cross. */
		    can_move = TRUE;

		    /* Feather fall makes one lightfooted. */
		    if (p_ptr->state.ffall) {
			notice_obj(OF_FEATHER, 0);
			temp = 49 + randint1(51);
		    } else
			temp = 124 + randint1(126);

		    /* Will take serious fire damage. */
		    fire_dam(temp, "burnt to a cinder in molten lava");
		}
		break;
	    }
	case FEAT_VOID:
	    {
		/* Bats, dragons can fly */
		if ((p_ptr->schange == SHAPE_BAT)
		    || (p_ptr->schange == SHAPE_WYRM))
		    can_move = TRUE;
		else {
		    /* Assume player will continue. */
		    temp = TRUE;

		    /* Smart enough to stop running. */
		    if (p_ptr->running) {
			if (!get_check
			    ("You have come to a cliff.  Step off it? ")) {
			    temp = FALSE;
			    p_ptr->running = 0;
			}
		    }

		    /* Smart enough to sense trouble. */
		    else if (!p_ptr->timed[TMD_BLIND]) {
			if (!get_check("It's a cliff! Really step off it? ")) {
			    temp = FALSE;
			}
		    }

		    /* Step off if confirmed. */
		    if (temp) {
			/* Can always jump. */
			can_move = TRUE;

			/* Will take serious damage. */
			falling = TRUE;
		    }
		}
		break;
	    }
	default:
	    {
		/* All other terrain can be traversed normally. */
		can_move = TRUE;
	    }
	}

	/* If the player can move, handle various things. */
	if (can_move) {
	    /* Move player */
	    monster_swap(py, px, y, x);

	    /* Update speed if stepping out of water */
	    if (cave_feat[py][px] == FEAT_WATER)
		p_ptr->update |= PU_BONUS;

	    /* Update stealth for Unlight */
	    if (player_has(PF_UNLIGHT))
		p_ptr->update |= PU_BONUS;

	    /* Superstealth for ents in trees SJGU */
	    if ((player_has(PF_WOODEN))
		&&
		(tf_has
		 (f_info[cave_feat[p_ptr->py][p_ptr->px]].flags, TF_TREE))) {
		if (!(tf_has(f_info[cave_feat[py][px]].flags, TF_TREE))
		    || !(p_ptr->timed[TMD_SSTEALTH])) {
		    (void) inc_timed(TMD_SSTEALTH, 1, FALSE);
		    p_ptr->update |= (PU_BONUS);
		}
	    } else if ((player_has(PF_WOODEN))
		       && (tf_has(f_info[cave_feat[py][px]].flags, TF_TREE))) {
		if (p_ptr->timed[TMD_SSTEALTH]) {
		    (void) dec_timed(TMD_SSTEALTH, 1, FALSE);
		    p_ptr->update |= (PU_BONUS);
		}
	    }

	    /* New location */
	    y = py = p_ptr->py;
	    x = px = p_ptr->px;

	    /* No longer traversing. */
	    player_is_crossing = 0;

	    /* Fall off a cliff */
	    if (falling)
		fall_off_cliff();

	    /* Spontaneous Searching */
	    if (p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] > 49) {
		(void) search(FALSE);
	    } else if (0 == randint0(50 - p_ptr->state.skills[SKILL_SEARCH_FREQUENCY])) 
	    {
		(void) search(FALSE);
	    }

	    /* Continuous Searching */
	    if (p_ptr->searching) {
		(void) search(FALSE);
	    }

	    /* Handle "store doors" */
	    if ((cave_feat[y][x] >= FEAT_SHOP_HEAD)
		&& (cave_feat[y][x] <= FEAT_SHOP_TAIL)) {
		/* Disturb */
		disturb(0, 0);
		cmd_insert(CMD_ENTER_STORE);
	    }

	    /* All other grids (including traps) */
	    else
	    {
		/* Handle objects (later) */
		p_ptr->notice |= (PN_PICKUP);
	    }

	    /* Flying players have a chance to miss traps */
	    if ((p_ptr->schange == SHAPE_BAT) || (p_ptr->schange == SHAPE_WYRM)) {
		if (((cave_feat[y][x] == FEAT_INVIS)
		     || (cave_feat[y][x] == FEAT_GRASS_INVIS))
		    && (randint0(3) != 0))
		    trapped = FALSE;
		else if ((cave_feat[y][x] >= FEAT_TRAP_HEAD)
			 && (cave_feat[y][x] <= FEAT_TRAP_TAIL)
			 && (randint0(10) != 0))
		    trapped = FALSE;
	    }

	    /* Discover invisible traps */
	    else if (((cave_feat[y][x] == FEAT_INVIS)
		      || (cave_feat[y][x] == FEAT_GRASS_INVIS)
		      || (cave_feat[y][x] == FEAT_TREE_INVIS)
		      || (cave_feat[y][x] == FEAT_TREE2_INVIS)) && trapped) {
		/* Disturb */
		disturb(0, 0);

		/* Message */
		msg_print("You stumble upon a trap!");

		/* Pick a trap */
		pick_trap(y, x);

		/* Hit the floor trap. */
		hit_trap(y, x);
	    }

	    /* Set off a visible trap */
	    else if ((cave_feat[y][x] >= FEAT_TRAP_HEAD)
		     && (cave_feat[y][x] <= FEAT_TRAP_TAIL) && trapped) {
		/* Disturb */
		disturb(0, 0);

		/* Hit the floor trap. */
		hit_trap(y, x);
	    }

	    /* Walk on a monster trap */
	    else if ((cave_feat[y][x] >= FEAT_MTRAP_HEAD)
		     && (cave_feat[y][x] <= FEAT_MTRAP_TAIL)) {
		msg_print("You inspect your cunning trap.");
	    }
	}
    }
}
예제 #7
0
/**
 * Handle player hitting a real trap.  Rewritten in Oangband to allow a
 * greater variety of traps, with effects controlled by dungeon level.
 * To allow a trap to choose one of a variety of effects consistantly,
 * the quick RNG is often used, and xy coordinates input as a seed value.
 */
extern void hit_trap(int y, int x)
{
    int i, j, k, num;
    int dam = 0;

    int nastyness, selection;

    feature_type *f_ptr = &f_info[cave_feat[y][x]];

    cptr name = f_ptr->name;

    /* Use the "simple" RNG to insure that traps are consistant. */
    Rand_quick = TRUE;

    /* Use the coordinates of the trap to seed the RNG. */
    Rand_value = y * x;

    /* Disturb the player */
    disturb(0, 0);

    /* Analyze XXX XXX XXX */
    switch (cave_feat[y][x]) {
    /* trap door. */
    case FEAT_TRAP_HEAD + 0x00:
    {
        Rand_quick = FALSE;

        /* Paranoia -NRM- */
        if (((stage_map[p_ptr->stage][STAGE_TYPE] == CAVE)
                || (stage_map[p_ptr->stage][STAGE_TYPE] == VALLEY))
                && (!stage_map[p_ptr->stage][DOWN])) {
            cave_info[y][x] &= ~(CAVE_MARK);
            cave_set_feat(y, x, FEAT_FLOOR);
            msg_print("The trap fails!");
            break;
        }


        msg_print("You fall through a trap door!");
        if (p_ptr->state.ffall) {
            notice_obj(OF_FEATHER, 0);
            msg_print("You float gently down to the next level.");
        } else {
            dam = damroll(2, 8);
            take_hit(dam, name);
        }
        /* Remember where we came from */
        p_ptr->last_stage = p_ptr->stage;

        if (!stage_map[p_ptr->stage][DOWN]) {
            /* Set the ways forward and back */
            stage_map[255][UP] = p_ptr->stage;
            stage_map[p_ptr->stage][DOWN] = 255;
            stage_map[255][DEPTH] = p_ptr->depth + 1;
        }

        /* New stage */
        p_ptr->stage = stage_map[p_ptr->stage][DOWN];

        /* New depth */
        p_ptr->depth = stage_map[p_ptr->stage][DEPTH];

        /* Leaving */
        p_ptr->leaving = TRUE;

        Rand_quick = TRUE;

        break;
    }

    /* pits. */
    case FEAT_TRAP_HEAD + 0x01:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(20) == 1)
            nastyness += 20;
        else if (randint1(5) == 1)
            nastyness += 10;

        /* Player is now in pit. */
        monster_swap(p_ptr->py, p_ptr->px, y, x);

        /* Center on player. */
        y = p_ptr->py;
        x = p_ptr->px;

        /* pit of daggers. */
        if ((nastyness > 80) && (randint1(3) != 3)) {
            msg_print("You fall into a pit of daggers!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid setting off the daggers.");
            }

            else {
                /* a trap of morgul. */
                if (randint1(6) == 1) {
                    Rand_quick = FALSE;


                    msg_print
                    ("A single coldly gleaming dagger pierces you deeply!");
                    msg_print
                    ("You feel a deadly chill slowly withering your soul.");

                    /* activate the Black Breath. */
                    p_ptr->black_breath = TRUE;

                    /* lots of damage. */
                    dam = damroll(20, 15);

                    /* undead may be attracted. */
                    if (randint1(2) == 1) {
                        msg_print
                        ("Undead suddenly appear and call you to them!");

                        k = randint1(3) + 2;
                        for (i = 0; i < k; i++) {
                            summon_specific(y, x, FALSE, p_ptr->depth,
                                            SUMMON_UNDEAD);
                        }
                    }

                    /* morgul-traps are one-time only. */
                    cave_info[y][x] &= ~(CAVE_MARK);
                    cave_set_feat(y, x, FEAT_FLOOR);

                    Rand_quick = TRUE;
                }

                else {
                    Rand_quick = FALSE;

                    /* activate the ordinary daggers. */
                    msg_print("Daggers pierce you everywhere!");

                    k = randint1(10) + 5;
                    for (i = 0; i < k; i++) {
                        dam += damroll(3, 4);
                    }

                    Rand_quick = TRUE;
                }

                /* cut the player. */
                (void) inc_timed(TMD_CUT, randint1(dam), TRUE);

                /* Take the damage. */
                take_hit(dam, name);
            }
        }

        /* poisoned spiked pit. */
        else if ((nastyness > 55) && (randint1(3) != 3)) {
            msg_print("You fall into a spiked pit!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid touching the spikes.");
            }

            else {
                Rand_quick = FALSE;

                /* Base damage */
                dam = damroll(2, 6);

                /* Extra spike damage */
                if (randint0(100) < 85) {
                    bool was_poisoned;

                    msg_print("You are impaled on poisonous spikes!");

                    dam = dam * (randint1(6) + 3);
                    (void) inc_timed(TMD_CUT, randint1(dam), TRUE);

                    was_poisoned = pois_hit(dam);

                    if (!was_poisoned)
                        msg_print("The poison does not affect you!");
                }

                /* Take the damage */
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        /* spiked pit. */
        else if ((nastyness > 30) && (randint1(3) != 3)) {
            msg_print("You fall into a spiked pit!");

            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the floor of the pit.");
                msg_print("You carefully avoid touching the spikes.");
            }

            else {
                Rand_quick = FALSE;

                /* Base damage */
                dam = damroll(2, 6);

                /* Extra spike damage */
                if (randint0(100) < 85) {
                    msg_print("You are impaled!");

                    dam = dam * (2 + randint1(4));
                    (void) inc_timed(TMD_CUT, randint1(dam), TRUE);
                }

                /* Take the damage */
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        /* ordinary pit in all other cases. */
        else {
            msg_print("You fall into a pit!");
            if (p_ptr->state.ffall) {
                notice_obj(OF_FEATHER, 0);
                msg_print("You float gently to the bottom of the pit.");
            } else {
                Rand_quick = FALSE;

                dam = damroll(2, 6);
                take_hit(dam, name);

                Rand_quick = TRUE;
            }
        }

        break;
    }

    /* stat-reducing dart traps. */
    case FEAT_TRAP_HEAD + 0x02:
    {
        /* decide if the dart hits. */
        if (check_trap_hit(50 + p_ptr->depth)) {
            /* select a stat to drain. */
            selection = randint0(6);

            Rand_quick = FALSE;

            msg_print("A small dart hits you!");
            dam = damroll(1, 4);
            take_hit(dam, name);

            /* Determine how dangerous the trap is allowed to be. */
            nastyness = randint1(p_ptr->depth);

            /* decide how much to drain the stat by. */
            if ((nastyness > 50) && (randint1(3) == 1)) {
                num = randint1(4);
            } else
                num = 1;

            /* drain the stat. */
            for (i = 0; i < num; i++) {
                (void) do_dec_stat(selection);
            }

            Rand_quick = TRUE;
        } else {
            msg_print("A small dart barely misses you.");
        }
        break;
    }

    /* discolored spots. */
    case FEAT_TRAP_HEAD + 0x03:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(5) == 1)
            nastyness += 10;

        /* pick a elemental attack type. */
        selection = randint1(4);


        /* electicity trap. */
        if (selection == 1) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are struck by lightning!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You get zapped!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            elec_dam(dam, "an electricity trap");
            Rand_quick = TRUE;

        }

        /* frost trap. */
        if (selection == 2) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are lost within a blizzard!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are coated in frost!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            cold_dam(dam, "a frost trap");
            Rand_quick = TRUE;
        }

        /* fire trap. */
        if (selection == 3) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("You are enveloped in a column of fire!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are surrounded by flames!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            fire_dam(dam, "a fire trap");
            Rand_quick = TRUE;
        }

        /* acid trap. */
        if (selection == 4) {
            if ((nastyness >= 50) && (randint1(2) == 1)) {
                Rand_quick = FALSE;

                msg_print("A cauldron of acid is tipped over your head!");
                dam = damroll(6, 30);

                Rand_quick = TRUE;
            } else {
                Rand_quick = FALSE;

                msg_print("You are splashed with acid!");
                dam = damroll(4, 8);

                Rand_quick = TRUE;
            }
            Rand_quick = FALSE;
            acid_dam(dam, "an acid trap");
            Rand_quick = TRUE;
        }

        break;
    }

    /* gas traps. */
    case FEAT_TRAP_HEAD + 0x04:
    {
        selection = randint1(4);

        /* blinding trap. */
        if (selection == 1) {
            msg_print("You are surrounded by a black gas!");
            if (!p_ptr->state.no_blind) {
                Rand_quick = FALSE;

                (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE);

                Rand_quick = TRUE;
            }
        } else
            notice_obj(OF_SEEING, 0);

        /* confusing trap. */
        if (selection == 2) {
            msg_print
            ("You are surrounded by a gas of scintillating colors!");
            if (!p_resist_good(P_RES_CONFU)) {
                Rand_quick = FALSE;

                (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);

                Rand_quick = TRUE;
            } else
                notice_other(IF_RES_CONFU, 0);
        }

        /* poisoning trap. */
        if (selection == 3) {
            msg_print("You are surrounded by a pungent green gas!");

            Rand_quick = FALSE;

            pois_hit(25);

            Rand_quick = TRUE;
        }

        /* sleeping trap. */
        if (selection == 4) {
            msg_print("You are surrounded by a strange white mist!");
            if (!p_ptr->state.free_act) {
                (void) inc_timed(TMD_PARALYZED, randint0(10) + 5, TRUE);
            } else
                notice_obj(OF_FREE_ACT, 0);
        }

        break;
    }

    /* summoning traps. */
    case FEAT_TRAP_HEAD + 0x05:
    {
        sound(MSG_SUM_MONSTER);
        /* sometimes summon thieves. */
        if ((p_ptr->depth > 8) && (randint1(5) == 1)) {
            msg_print("You have aroused a den of thieves!");

            Rand_quick = FALSE;

            num = 2 + randint1(3);
            for (i = 0; i < num; i++) {
                (void) summon_specific(y, x, FALSE, p_ptr->depth,
                                       SUMMON_THIEF);
            }

            Rand_quick = TRUE;
        }

        /* sometimes summon a nasty unique. */
        else if (randint1(8) == 1) {
            msg_print("You are enveloped in a cloud of smoke!");

            Rand_quick = FALSE;

            (void) summon_specific(y, x, FALSE, p_ptr->depth + 5,
                                   SUMMON_UNIQUE);

            Rand_quick = TRUE;
        }

        /* otherwise, the ordinary summon monsters. */
        else {
            msg_print("You are enveloped in a cloud of smoke!");

            Rand_quick = FALSE;

            num = 2 + randint1(3);
            for (i = 0; i < num; i++) {
                (void) summon_specific(y, x, FALSE, p_ptr->depth, 0);
            }

            Rand_quick = TRUE;
        }

        /* these are all one-time traps. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        break;
    }

    /* dungeon alteration traps. */
    case FEAT_TRAP_HEAD + 0x06:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint1(p_ptr->depth);
        if (randint1(5) == 1)
            nastyness += 10;

        /* make room for alterations. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        /* Everything truely random from here on. */
        Rand_quick = FALSE;

        /* dungeon destruction trap. */
        if ((nastyness > 60) && (randint1(12) == 1)) {
            msg_print
            ("A ear-splitting howl shatters your mind as the dungeon is smashed by hammer blows!");

            (void) destroy_level(FALSE);

            /* the player is hard-hit. */
            (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);
            (void) inc_timed(TMD_BLIND, randint0(30) + 15, TRUE);
            (void) inc_timed(TMD_STUN, randint1(50) + 50, TRUE);
            dam = damroll(15, 15);
            take_hit(dam, name);
        }

        /* earthquake trap. */
        else if ((nastyness > 20) && (randint1(4) == 1)) {
            msg_print("A tremor shakes the earth around you");
            earthquake(y, x, 10, FALSE);
        }

        /* falling rock trap. */
        else if ((nastyness > 4) && (randint1(2) == 1)) {
            msg_print("A rock falls on your head.");
            dam = damroll(2, 10);
            take_hit(dam, name);

            (void) inc_timed(TMD_STUN, randint1(10) + 10, TRUE);
        }

        /* a few pebbles. */
        else {
            msg_print("A bunch of pebbles rain down on you.");
            dam = damroll(1, 8);
            take_hit(dam, name);
        }

        Rand_quick = TRUE;

        break;
    }

    /* various char and equipment-alteration traps, lumped together to
     * avoid any one effect being too common (some of them can be rather
     * nasty). */
    case FEAT_TRAP_HEAD + 0x07:
    {
        /* determine how dangerous the trap is allowed to be. */
        nastyness = randint0(100);

        /* these are all one-time traps. */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_FLOOR);

        /* Everything truely random from here on. */
        Rand_quick = FALSE;

        /* trap of drain wands. */
        if (nastyness < 15) {
            /* Hold the object information. */
            object_type *o_ptr;

            /* Find an item */
            for (i = 0; i < 20; i++) {
                /* Pick an item */
                i = randint0(INVEN_PACK - p_ptr->pack_size_reduce);

                /* Obtain the item */
                o_ptr = &p_ptr->inventory[i];

                /* use "num" to decide if a item can be uncharged.  By
                 * default, assume it can't. */
                num = 0;

                /* Skip non-objects */
                if (!o_ptr->k_idx)
                    continue;

                /* Drain charged wands/staffs/rods */
                if ((o_ptr->tval == TV_STAFF) || (o_ptr->tval == TV_WAND)
                        || (o_ptr->tval == TV_ROD)) {
                    /* case of charged wands/staffs. */
                    if (((o_ptr->tval == TV_STAFF)
                            || (o_ptr->tval == TV_WAND)) && (o_ptr->pval))
                        num = 1;

                    /* case of charged rods. */
                    if ((o_ptr->tval == TV_ROD)
                            && (o_ptr->timeout < randcalc(o_ptr->time, 0,
                                                          MINIMISE)))
                        num = 1;


                    if (num == 1) {
                        /* Message */
                        msg_print("Energy drains from your pack!");

                        /* Uncharge */
                        if ((o_ptr->tval == TV_STAFF)
                                || (o_ptr->tval == TV_WAND))
                            o_ptr->pval = 0;

                        if (o_ptr->tval == TV_ROD)
                            o_ptr->timeout = randcalc(o_ptr->time, 0, RANDOMISE) * o_ptr->number * 2;


                        /* Combine / Reorder the pack */
                        p_ptr->notice |= (PN_COMBINE | PN_REORDER);

                        /* not more than one inventory slot effected. */
                        break;
                    } else
                        continue;
                }
            }
        }

        /* trap of forgetting. */
        else if (nastyness < 35) {
            if (check_save(100)) {
                msg_print("You hang on to your memories!");
            } else if (lose_all_info()) {
                msg_print("Your memories fade away.");
            }
        }

        /* trap of alter reality. */
        else if (nastyness < 50) {
            if (OPT(adult_ironman))
                msg_print("Nothing happens.");
            else {
                msg_print("The world changes!");

                /* Leaving */
                p_ptr->leaving = TRUE;
            }
        }

        /* trap of remold player. */
        else if (nastyness < 75) {
            int max1, cur1, max2, cur2, ii, jj;

            msg_print("You feel yourself being twisted by wild magic!");

            if (check_save(100)) {
                msg_print("You resist the effects!");
            } else {
                msg_print("Your body starts to scramble...");

                /* Pick a pair of stats */
                ii = randint0(6);
                for (jj = ii; jj == ii; jj = randint0(6))	/* loop */
                    ;

                max1 = p_ptr->stat_max[ii];
                cur1 = p_ptr->stat_cur[ii];
                max2 = p_ptr->stat_max[jj];
                cur2 = p_ptr->stat_cur[jj];

                p_ptr->stat_max[ii] = max2;
                p_ptr->stat_cur[ii] = cur2;
                p_ptr->stat_max[jj] = max1;
                p_ptr->stat_cur[jj] = cur1;

                p_ptr->update |= (PU_BONUS);
            }
        }

        /* time ball trap. */
        else if (nastyness < 90) {
            msg_print("You feel time itself assault you!");

            /* Target the player with a radius 0 ball attack. */
            fire_meteor(0, GF_TIME, p_ptr->py, p_ptr->px, 75, 0, TRUE);
        }

        /* trap of bugs gone berserk. */
        else {
            /* explain what the dickens is going on. */
            msg_print("GRUESOME Gnawing Bugs leap out at you!");

            if (!p_resist_good(P_RES_CONFU)) {
                (void) inc_timed(TMD_CONFUSED, randint0(20) + 10, TRUE);
            } else
                notice_other(IF_RES_CONFU, 0);

            if (!p_resist_good(P_RES_CHAOS)) {
                (void) inc_timed(TMD_IMAGE, randint1(40), TRUE);
            } else
                notice_other(IF_RES_CHAOS, 0);

            /* XXX (hard coded) summon 3-6 bugs. */
            k = randint1(4) + 2;
            for (i = 0; i < k; ++i) {
                /* Look for a location */
                for (j = 0; j < 20; ++j) {
                    /* Pick a (scattered) distance. */
                    int d = (j / 10) + randint1(3);

                    /* Pick a location */
                    scatter(&y, &x, y, x, d, 0);

                    /* Require passable terrain */
                    if (!cave_passable_bold(y, x))
                        continue;

                    /* Hack -- no summon on glyph of warding */
                    if (cave_feat[y][x] == FEAT_RUNE_PROTECT)
                        continue;

                    /* Okay */
                    break;
                }

                /* Attempt to place the awake bug */
                place_monster_aux(y, x, 453, FALSE, TRUE);
            }

            /* herald the arrival of bugs. */
            msg_print("AAAAAAAHHHH! THEY'RE EVERYWHERE!");
        }

        Rand_quick = TRUE;

        break;
    }

    /* teleport trap */
    case FEAT_TRAP_HEAD + 0x08:
    {
        if (stage_map[p_ptr->stage][STAGE_TYPE] >= CAVE)
            msg_print("You teleport across the dungeon.");
        else
            msg_print("You teleport across the wilderness.");

        Rand_quick = FALSE;

        teleport_player(250, FALSE);

        Rand_quick = TRUE;

        break;
    }

    /* murder holes. */
    case FEAT_TRAP_HEAD + 0x09:
    {
        /* hold the object info. */
        object_type *o_ptr;
        object_type object_type_body;

        /* hold the missile type and name. */
        int sval = 0;
        int tval = 0;
        cptr missile_name = "";



        /* Determine the missile type and base damage. */
        if (randint1(3) == 1) {
            if (p_ptr->depth < 40) {
                missile_name = "shot";
                dam = damroll(2, 3);
                tval = TV_SHOT;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker shot";
                dam = damroll(3, 7);
                tval = TV_SHOT;
                sval = SV_AMMO_HEAVY;
            }
        }

        else if (randint1(2) == 1) {
            if (p_ptr->depth < 55) {
                missile_name = "arrow";
                dam = damroll(2, 4);
                tval = TV_ARROW;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker arrow";
                dam = damroll(3, 9);
                tval = TV_ARROW;
                sval = SV_AMMO_HEAVY;
            }
        }

        else {
            if (p_ptr->depth < 65) {
                missile_name = "bolt";
                dam = damroll(2, 5);
                tval = TV_BOLT;
                sval = SV_AMMO_NORMAL;
            } else {
                missile_name = "seeker bolt";
                dam = damroll(3, 11);
                tval = TV_BOLT;
                sval = SV_AMMO_HEAVY;
            }
        }

        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            msg_format("A %s hits you from above.", missile_name);

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was well-aimed!");
                dam *= 1 + randint1(2);
            }
            if (randint1(2) == 1) {
                msg_print("It gouges you!");
                dam = 3 * dam / 2;

                /* cut the player. */
                (void) inc_timed(TMD_CUT, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_format("A %s wizzes by your head.", missile_name);

        /* these will eventually run out of ammo. */

        Rand_quick = FALSE;

        if (randint0(8) == 0) {
            cave_info[y][x] &= ~(CAVE_MARK);
            cave_set_feat(y, x, FEAT_FLOOR);
        }

        Rand_quick = TRUE;

        /* Get local object */
        o_ptr = &object_type_body;

        /* Make a missile, identify it, and drop it near the player. */
        object_prep(o_ptr, lookup_kind(tval, sval), MINIMISE);
        object_aware(o_ptr);
        object_known(o_ptr);
        drop_near(o_ptr, -1, y, x, TRUE);

        break;
    }

    /* falling tree branch */
    case FEAT_TRAP_HEAD + 0x0A:
    {
        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            /* Take damage */
            dam = damroll(3, 5);
            msg_print("A branch hits you from above.");

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was heavy!");
                dam = 3 * dam / 2;

                /* stun the player. */
                (void) inc_timed(TMD_STUN, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_print("A falling branch just misses you.");

        /* No more */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_TREE);

        break;
    }

    /* falling tree branch */
    case FEAT_TRAP_HEAD + 0x0B:
    {
        /* determine if the missile hits. */
        if (check_trap_hit(75 + p_ptr->depth)) {
            /* Take damage */
            dam = damroll(3, 5);
            msg_print("A branch hits you from above.");

            Rand_quick = FALSE;

            /* critical hits. */
            if (randint1(2) == 1) {
                msg_print("It was heavy!");
                dam = 3 * dam / 2;

                /* stun the player. */
                (void) inc_timed(TMD_STUN, randint1(dam), TRUE);
            }

            Rand_quick = TRUE;

            take_hit(dam, name);
        }

        /* Explain what just happened. */
        else
            msg_print("A falling branch just misses you.");

        /* No more */
        cave_info[y][x] &= ~(CAVE_MARK);
        cave_set_feat(y, x, FEAT_TREE2);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0C:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0D:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0E:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    /* undefined trap. */
    case FEAT_TRAP_HEAD + 0x0F:
    {
        msg_print("A dagger is thrown at you from the shadows!");
        dam = damroll(3, 4);
        take_hit(dam, name);

        break;
    }

    }

    /* Revert to usage of the complex RNG. */
    Rand_quick = FALSE;
}
예제 #8
0
파일: cmd-cave.c 프로젝트: Chillbon/angband
/**
 * 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;
}
예제 #9
0
/*
 * Handle monster hitting a real trap.
 */
void mon_hit_trap(int m_idx, int y, int x)
{
	feature_type *f_ptr;
	monster_type *m_ptr = &m_list[m_idx];
	monster_race *r_ptr = &r_info[m_ptr->r_idx];

	int feat = cave_feat[y][x];

	bool fear;

	/* Option */
	if (!variant_hit_traps) return;

	/* Hack --- don't activate unknown invisible traps */
	if (cave_feat[y][x] == FEAT_INVIS) return;

	/* Get feature */
	f_ptr = &f_info[cave_feat[y][x]];

	/* Hack --- trapped doors */
	/* XXX XXX Dangerous */
	while (!(f_ptr->spell) && !(f_ptr->blow.method) && (f_ptr->flags1 & (FF1_TRAP)))
	{
		pick_trap(y,x);

		/* Error */
		if (cave_feat[y][x] == feat) break;

		feat = cave_feat[y][x];

		/* Get feature */
		f_ptr = &f_info[feat];

	}

	/* Use covered or bridged if necessary */
	if ((f_ptr->flags2 & (FF2_COVERED)) || (f_ptr->flags2 & (FF2_BRIDGED)))
	{
		f_ptr = &f_info[f_ptr->mimic];
	}

	/* Hack -- monster falls onto trap */
	if ((m_ptr->fy!=y)|| (m_ptr->fx !=x))
	{
		/* Move monster */
		monster_swap(m_ptr->fy, m_ptr->fx, y, x);
	}

	/* Apply the object */
	if ((cave_o_idx[y][x]) && (f_ptr->flags1 & (FF1_HIT_TRAP)))
	{
		object_type *o_ptr = &o_list[cave_o_idx[y][x]];

		char o_name[80];

		int power = 0;

		switch (o_ptr->tval)
		{
			case TV_BOW:
			{
				object_type *j_ptr;
				u32b f1,f2,f3;

				int i, shots = 1;

				/* Get bow */
				j_ptr = o_ptr;

				/* Get bow flags */
				object_flags(o_ptr,&f1,&f2,&f3);

				/* Apply extra shots */
				if (f1 & (TR1_SHOTS)) shots += j_ptr->pval;

				/* Test for hit */
				for (i = 0; i < shots; i++)
				{
					if (j_ptr->next_o_idx)
					{
						int ammo = j_ptr->next_o_idx;
						object_type *i_ptr;
						object_type object_type_body;

						/* Use ammo instead of bow */
						o_ptr = &o_list[ammo];

						/* Describe ammo */
						object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0);

						if ((ammo) && (test_hit_fire((j_ptr->to_h + o_ptr->to_h)* BTH_PLUS_ADJ + f_ptr->power,  r_ptr->ac * (r_ptr->flags2 & (RF2_ARMOR) ? 2 : 1), TRUE)))
						{
							int k, mult;

							switch (j_ptr->sval)
							{
								case SV_SLING:
								case SV_SHORT_BOW:
								mult = 2;
								break;
								case SV_LONG_BOW:
								case SV_LIGHT_XBOW:
									mult = 3;
									break;
								case SV_HEAVY_XBOW:
									mult = 4;
									break;
								default:
									mult = 1;
									break;
							}

							/* Apply extra might */
							if (f1 & (TR1_MIGHT)) mult += j_ptr->pval;

							k = damroll(o_ptr->dd, o_ptr->ds);
							k *= mult;

							k = tot_dam_aux(o_ptr, k, m_ptr);

							k = critical_shot(o_ptr->weight, o_ptr->to_h + j_ptr->to_h, k);
							k += o_ptr->to_d + j_ptr->to_d;

							/* No negative damage */
							if (k < 0) k = 0;

							/* Trap description */
							msg_format("%^s hits you.",o_name);

							/* Damage, check for fear and death */
							(void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL);

						}
						else
						{
							/* Trap description */
							msg_format("%^s narrowly misses you.",o_name);
						}

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Drop nearby - some chance of breakage */
						drop_near(i_ptr,y,x,breakage_chance(i_ptr));

						/* Decrease the item */
						floor_item_increase(ammo, -1);
						floor_item_optimize(ammo);

						break;
					}
					else
					{
						/* Disarm */
						cave_alter_feat(y,x,FS_DISARM);
					}
				}
			}

			case TV_SHOT:
			case TV_ARROW:
			case TV_BOLT:
			case TV_HAFTED:
			case TV_SWORD:
			case TV_POLEARM:
			{
				object_type *i_ptr;
				object_type object_type_body;

				/* Describe ammo */
				object_desc(o_name, sizeof(o_name), o_ptr, TRUE, 0);

				/* Test for hit */
				if (test_hit_norm(o_ptr->to_h * BTH_PLUS_ADJ + f_ptr->power, r_ptr->ac, TRUE))
				{
					int k;

					k = damroll(o_ptr->dd, o_ptr->ds);

					k = tot_dam_aux(o_ptr, k, m_ptr);

					k = critical_norm(o_ptr->weight, o_ptr->to_h, k);
					k += o_ptr->to_d;

					/* Armour reduces total damage */
					k -= (k * ((p_ptr->ac < 150) ? p_ptr->ac : 150) / 250);

					/* No negative damage */
					if (k < 0) k = 0;

					/* Trap description */
					msg_format("%^s hits you.",o_name);

					/* Damage, check for fear and death */
					(void)mon_take_hit(cave_m_idx[y][x], k, &fear, NULL);

				}
				else
				{
					/* Trap description */
					msg_format("%^s narrowly misses you.",o_name);					
				}

				/* Get local object */
				i_ptr = &object_type_body;

				/* Obtain a local object */
				object_copy(i_ptr, o_ptr);

				/* Modify quantity */
				i_ptr->number = 1;

				/* Drop nearby - some chance of breakage */
				drop_near(i_ptr,y,x,breakage_chance(i_ptr));

				/* Decrease the item */
				floor_item_increase(cave_o_idx[y][x], -1);
				floor_item_optimize(cave_o_idx[y][x]);

				/* Disarm if runs out */
				if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);

				break;
			}

			case TV_WAND:
			case TV_STAFF:
			{
				if (o_ptr->pval > 0)
				{
					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* XXX Hack -- new unstacking code */
					o_ptr->stackc++;

					/* No spare charges */	
					if (o_ptr->stackc >= o_ptr->number)
					{
						/* Use a charge off the stack */
						o_ptr->pval--;

						/* Reset the stack count */
						o_ptr->stackc = 0;
					}

					/* XXX Hack -- unstack if necessary */
					if ((o_ptr->number > 1) &&
					((!variant_pval_stacks) || 
					((!object_known_p(o_ptr) && (o_ptr->pval == 2) && (o_ptr->stackc > 1)) ||
					  (!object_known_p(o_ptr) && (rand_int(o_ptr->number) <= o_ptr->stackc) &&
					  (o_ptr->stackc != 1) && (o_ptr->pval > 2)))))
					{
						object_type *i_ptr;
						object_type object_type_body;

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Reset stack counter */
						i_ptr->stackc = 0;
 
				 		/* Unstack the used item */
				 		o_ptr->number--;

						/* Reduce the charges on the new item */
						if (o_ptr->stackc > 1)
						{
							i_ptr->pval-=2;
							o_ptr->stackc--;
						}
						else if (!o_ptr->stackc)
						{
							i_ptr->pval--;
							o_ptr->pval++;
							o_ptr->stackc = o_ptr->number-1;
						}

						(void)floor_carry(y,x,i_ptr);
					}
				}
				else
				{
					/* Disarm if runs out */
					cave_alter_feat(y,x,FS_DISARM);
				}

				break;
			}

			case TV_ROD:
			case TV_DRAG_ARMOR:
			{
				if (!((o_ptr->timeout) && ((!o_ptr->stackc) || (o_ptr->stackc >= o_ptr->number))))
				{
					int tmpval;

					/* Store pval */
					tmpval = o_ptr->timeout;

					/* Time rod out */
					o_ptr->timeout = o_ptr->pval;

					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* Has a power */
					/* Hack -- check if we are stacking rods */
					if ((o_ptr->timeout > 0) && (!(tmpval) || stack_force_times))
					{
						/* Hack -- one more rod charging */
						if (o_ptr->timeout) o_ptr->stackc++;

						/* Reset stack count */
						if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0;

						/* Hack -- always use maximum timeout */
						if (tmpval > o_ptr->timeout) o_ptr->timeout = tmpval;
					}

					/* XXX Hack -- unstack if necessary */
					if ((o_ptr->number > 1) && (o_ptr->timeout > 0))
					{
						object_type *i_ptr;
						object_type object_type_body;

						/* Get local object */
						i_ptr = &object_type_body;

						/* Obtain a local object */
						object_copy(i_ptr, o_ptr);

						/* Modify quantity */
						i_ptr->number = 1;

						/* Clear stack counter */
						i_ptr->stackc = 0;

						/* Restore "charge" */
						o_ptr->timeout = tmpval;

						/* Unstack the used item */
						o_ptr->number--;

						/* Reset the stack if required */
						if (o_ptr->stackc == o_ptr->number) o_ptr->stackc = 0;

						(void)floor_carry(y,x,i_ptr);
					}
				}
				break;
			}

			case TV_POTION:
			case TV_SCROLL:
			case TV_FLASK:
			case TV_FOOD:
			{
				/* Hack -- boring food */
				if ((o_ptr->tval == TV_FOOD) && (o_ptr->sval >= SV_FOOD_MIN_FOOD))
				{
					/* Disarm */
					cave_alter_feat(y,x,FS_DISARM);
				}
				else
				{
					/* Get item effect */
					get_spell(&power, "use", o_ptr, FALSE);

					/* Decrease the item */
					floor_item_increase(cave_o_idx[y][x], -1);
					floor_item_optimize(cave_o_idx[y][x]);

					/* Disarm if runs out */
					if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);
				}

				break;
			}

			case TV_RUNESTONE:
			{
				u32b runes = p_ptr->cur_runes;

				int num = 0;
				s16b book[26];

				/* Hack -- use current rune */
				p_ptr->cur_runes = (2 << (o_ptr->sval-1));

				/* Fill the book with spells */
				fill_book(o_ptr,book,&num);

				/* Unhack */
				p_ptr->cur_runes = runes;

				/* Get a power */
				power = book[rand_int(num)];

				/* Decrease the item */
				floor_item_increase(cave_o_idx[y][x], -1);
				floor_item_optimize(cave_o_idx[y][x]);

				/* Disarm if runs out */
				if (!cave_o_idx[y][x]) cave_alter_feat(y,x,FS_DISARM);

				break;
			}

			default:
			{
				/* Disarm */
				cave_alter_feat(y,x,FS_DISARM);

				break;
			}
		}

		/* Has a power */
		if (power > 0)
		{
			spell_type *s_ptr = &s_info[power];

			int ap_cnt;

			/* Object is used */
			if (k_info[o_ptr->k_idx].used < MAX_SHORT) k_info[o_ptr->k_idx].used++;

			/* Scan through all four blows */
			for (ap_cnt = 0; ap_cnt < 4; ap_cnt++)
			{
				int damage = 0;

				/* Extract the attack infomation */
				int effect = s_ptr->blow[ap_cnt].effect;
				int method = s_ptr->blow[ap_cnt].method;
				int d_dice = s_ptr->blow[ap_cnt].d_dice;
				int d_side = s_ptr->blow[ap_cnt].d_side;
				int d_plus = s_ptr->blow[ap_cnt].d_plus;

				/* Hack -- no more attacks */
				if (!method) break;

				/* Mega hack -- dispel evil/undead objects */
				if (!d_side)
				{
					d_plus += 25 * d_dice;
				}

				/* Roll out the damage */
				if ((d_dice) && (d_side))
				{
					damage = damroll(d_dice, d_side) + d_plus;
				}
				else
				{
					damage = d_plus;
				}

				(void)project_m(0,0,y,x,damage, effect);
				(void)project_f(0,0,y,x,damage, effect);
			}
		}
	}

	/* Regular traps */
	else
	{
		if (f_ptr->spell)
		{
	      		make_attack_spell_aux(0,y,x,f_ptr->spell);
		}
		else if (f_ptr->blow.method)
		{
			int damage = damroll(f_ptr->blow.d_side,f_ptr->blow.d_dice);
   
			/* Apply the blow */
			project_m(0, 0, y, x, damage, f_ptr->blow.effect);
		}

		/* Get feature */
		f_ptr = &f_info[cave_feat[p_ptr->py][p_ptr->px]];

		if (f_ptr->flags1 & (FF1_HIT_TRAP))
		{
			/* Modify the location hit by the trap */
			cave_alter_feat(y,x,FS_HIT_TRAP);
		}
		else if (f_ptr->flags1 & (FF1_SECRET))
		{
			/* Discover */
			cave_alter_feat(y,x,FS_SECRET);
		}
	}
}
예제 #10
0
파일: cmd1.c 프로젝트: Rydelfox/Ponyband
/**
 * Move player in the given direction, with the given "pickup" flag.
 *
 * 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/etc.
 */
void move_player(int dir, bool no_options)
{
	unsigned int py = p_ptr->py;
	unsigned int px = p_ptr->px;

	byte str_escape, dex_escape;

	/* Permit the player to move? */
	bool can_move = FALSE;

	/* Player is jumping off a cliff */
	bool falling = FALSE;

	/* Player hits a trap (always unless flying) */
	bool trapped = TRUE;
	
	/* Sliding on the ice */
	bool icy_slide = FALSE;

	int temp;
	unsigned int y, x;

	feature_type *f_ptr;

	/* Find the result of moving */
	y = py + ddy[dir];
	x = px + ddx[dir];
	f_ptr = &f_info[cave_feat[y][x]];


	/* Hack -- attack monsters */
	if (cave_m_idx[y][x] > 0) {
		/* Attack */
		if (py_attack(y, x, TRUE))
			return;
	}

	/* It takes some dexterity, or failing that strength, to get out of pits */
	if (cave_feat[py][px] == FEAT_PIT) {
		str_escape = adj_dex_dis[p_ptr->state.stat_ind[A_STR]];
		dex_escape = adj_dex_dis[p_ptr->state.stat_ind[A_DEX]];

		/* First attempt to leap out of the pit, */
		if ((dex_escape + 1) * 2 < randint1(16)) {
			/* then attempt to climb out of the pit. */
			if (str_escape + 3 < randint1(16)) {
				/* Failure costs a turn. */
				msg("You remain stuck in the pit.");
				/* Failure clears movement */
				p_ptr->previous_action[0] = ACTION_NOTHING;
				return;
			} else
				msg("You clamber out of the pit.");
		} else
			msg("You leap out of the pit.");
	}


	/* Rooted players cannot move */
	if (p_ptr->timed[TMD_ROOT])
	{
		can_move = FALSE;
		msg("You are rooted to the ground and can't move.");
		
		/* Prevent repeated attempts */
		disturb(0, 0);
		
		return;
	}
	
	/* Option to disarm a visible trap. -TNB- */
	/* Hack - Rogues can walk over their own trap - BR */
	else if (cave_visible_trap(y, x) && cave_player_trap(y, x)
			&& OPT(easy_alter)) {
		bool more = FALSE;
		/* Auto-repeat if not already repeating */
		if (cmd_get_nrepeats() == 0)
			cmd_set_repeat(99);

		more = do_cmd_disarm_aux(y, x);

		/* Cancel repeat unless we may continue */
		if (!more)
			disturb(0, 0);
		return;
	}

	/* Some terrain is impassable for the player, such as stone walls. */
	else if (!tf_has(f_ptr->flags, TF_PASSABLE)) {
		/* Disturb the player */
		disturb(0, 0);

		/* Notice unknown obstacles */
		if (!sqinfo_has(cave_info[y][x], SQUARE_MARK)) {
			/* Closed door */
			if (tf_has(f_ptr->flags, TF_DOOR_CLOSED)) {
				msgt(MSG_HITWALL, "You feel a door blocking your way.");
				sqinfo_on(cave_info[y][x], SQUARE_MARK);
				light_spot(y, x);
			}

			/* Wall (or secret door) */
			else {
				msgt(MSG_HITWALL, "You feel a wall blocking your way.");
				sqinfo_on(cave_info[y][x], SQUARE_MARK);
				light_spot(y, x);
			}
		}

		/* Mention known obstacles */
		else {
			/* Closed door */
			if (tf_has(f_ptr->flags, TF_DOOR_CLOSED)) {
				/* Option to automatically open doors. -TNB- */
				if (OPT(easy_alter)) {
					bool more = FALSE;

					/* Auto-repeat if not already repeating */
					if (cmd_get_nrepeats() == 0)
						cmd_set_repeat(99);

					/* Open the door */
					more = do_cmd_open_aux(y, x);

					/* Cancel repeat unless we may continue */
					if (!more)
						disturb(0, 0);
					/* Clear action list */
					p_ptr->previous_action[0] = ACTION_NOTHING;
                    return;
				}

				/* Otherwise, a message. */
				msgt(MSG_HITWALL, "There is a door blocking your way.");
			}

			/* Wall (or secret door) */
			else {
				msgt(MSG_HITWALL, "There is a wall blocking your way.");
			}
		}

		/* Sound */
		sound(MSG_HITWALL);
	}

	/* Normal movement */
	else {
		/* Assume terrain can be traversed normally. */
		can_move = TRUE;

		/* Terrain blocked by a friendly monster */
		if (cave_m_idx[y][x] > 0)
		{
		    monster_type *n_ptr = & m_list[cave_m_idx[y][x]];
		    
		    /* Push monster if it doesn't have a target and hasn't been pushed.
			 * This allows the player to move into a corridor with a monster in
			 * front of him, and have the monster move ahead, if it is faster. If its
			 * not faster, the player will push over it on the second move, as the push
			 * flag below will have been set. */
			 if(((n_ptr->mflag & MFLAG_PUSH) == 0) && !(n_ptr->ty) && !(n_ptr->tx) && push_aside_player(p_ptr->py, p_ptr->px, n_ptr))
			 {
			     int dy = n_ptr->fy - y;
			     int dx = n_ptr->fx - x;
			     unsigned int count = 0;
			     
			     n_ptr->ty = n_ptr->fy;
			     n_ptr->tx = n_ptr->fx;
			     
			     /* Hack -- get new target as far as the monster can move in the direction
				 * pushed. We do this with a walking stick approach to prevent us getting
				 * invalid target locations like (0,0) */
				while (in_bounds_fully(n_ptr->ty + dy, n_ptr->tx + dx)
						&& cave_exist_mon(&r_info[n_ptr->r_idx], n_ptr->ty + dy, n_ptr->tx + dx, TRUE)
						&& (count++ < (MAX_SIGHT / 2)))
				{
					n_ptr->ty = n_ptr->ty + dy;
					n_ptr->tx = n_ptr->tx + dx;
				}

				/* Clear target if none available */
				if ((n_ptr->ty == n_ptr->fy) && (n_ptr->tx == n_ptr->fx))
				{
					n_ptr->ty = 0;
					n_ptr->tx = 0;
				}
			}

			/* The other monster cannot switch places */
			else if (!cave_exist_mon(&r_info[n_ptr->r_idx], p_ptr->py, p_ptr->px, TRUE))
			{
				/* Try to push it aside. Allow aborting of move if an ally */
				if ((!push_aside_player(p_ptr->py, p_ptr->px, n_ptr)) && (get_reaction(F_PLAYER, n_ptr->faction) <= REACT_FRIEND))
				{
					/* No warning if sliding */
					if (no_options)	{}
					/* Don't provide more warning */
					else if (!get_check("Are you sure?")) 
					{
					    temp = FALSE;
					    p_ptr->running = 0;
					    can_move = FALSE;
					}
				}
			}

			/* Hack -- we clear the target if we move over a monster */
			else
			{
				n_ptr->ty = 0;
				n_ptr->tx = 0;
			}

			/* Mark monsters as pushed */
			n_ptr->mflag |= (MFLAG_PUSH);
		}
        
        /*** Handle traversable terrain.  ***/
		if (tf_has(f_ptr->flags, TF_ROCK)) {
			/* Dwarves move easily through rubble */
			if (player_has(PF_DWARVEN))
				can_move = TRUE;

			/* Bats, dragons can fly */
			else if ((p_ptr->schange == SHAPE_BAT)
					 || (p_ptr->schange == SHAPE_WYRM))
				can_move = TRUE;

			/* Require more energy */
			else {
				can_move = TRUE;
				p_ptr->energy_use += 100;
			}
		}

		if (tf_has(f_ptr->flags, TF_TREE)) {
			/* Druids, rangers, Plant Cutie Marks slip easily under
			 * trees */
			if ((player_has(PF_WOODSMAN)) || (player_has(PF_PLANT_FRIEND)))
				can_move = TRUE;

			/* Bats, dragons can fly */
			else if ((p_ptr->schange == SHAPE_BAT)
					 || (p_ptr->schange == SHAPE_WYRM))
				can_move = TRUE;

			/* Require more energy */
			else {
				can_move = TRUE;
				p_ptr->energy_use += 100;
			}
		}

		/* Water now slows rather than stopping -NRM- */
		if (tf_has(f_ptr->flags, TF_WATERY)) {
			/* Stop any run. */
			disturb(0, 0);

			can_move = TRUE;

			/* Speed will need updating */
			p_ptr->update |= PU_BONUS;
		}
		
		/* Walking on to ice can cause you to slide an additional square. */
		if (tf_has(f_ptr->flags, TF_ICY)) {
			/* Stop any run */
			disturb(0, 0);
			
			can_move = TRUE;
			
			/* Slide is less likely with Cold Resist. Never slide with Levitation */
			if (!p_ptr->state.ffall && ((!p_immune(P_RES_COLD)) && (randint1((p_resist_pos(P_RES_COLD) || p_resist_strong(P_RES_COLD)) ? 2 : 4) != 1)))
			    icy_slide = TRUE;
			
			/* Speed will need updating */
			p_ptr->update |= PU_BONUS;
		}

		if (tf_has(f_ptr->flags, TF_FIERY)) {
			/* Assume player will continue. */
			temp = TRUE;

			/* Smart enough to stop running. */
			if (p_ptr->running) {
				/* Ice keeps sliding */
				if (no_options) {}
				else if (!get_check("Lava blocks your path.  Step into it? ")) {
					temp = FALSE;
					p_ptr->running = 0;
				}
			}

			/* Smart enough to sense trouble. */
			else if ((!p_resist_pos(P_RES_FIRE))
					 || (!p_resist_strong(P_RES_FIRE)
						 && (p_ptr->chp <= 100))
					 || (!p_immune(P_RES_FIRE) && (p_ptr->chp <= 30))) {
				/* Sliding continues regardless */
				if (no_options) {}
				else if (!get_check
					("The heat of the lava scalds you! Really enter? ")) {
					temp = FALSE;
				}
			}

			/* Enter if OK or confirmed. */
			if (temp) {
				/* Can always cross. */
				can_move = TRUE;

				/* Feather fall makes one lightfooted. */
				if (p_ptr->state.ffall) {
					notice_obj(OF_FEATHER, 0);
					temp = 49 + randint1(51);
				} else
					temp = 124 + randint1(126);

				/* Will take serious fire damage. */
				fire_dam(temp, "burnt to a cinder in molten lava", SOURCE_ENVIRONMENTAL);
			}
			else
				/* Player refuse to go. */
				can_move = FALSE;
		}
		
		if (tf_has(f_ptr->flags, TF_BURNING))
		{
            /* Assume player will continue */
            temp = TRUE;
            
            /* Smart enough to stop running */
            if (p_ptr->running)
            {
            	if (no_options) {}
				else if (!get_check("Your path is block by a burning tree. Step into it? "))
            	{
            		temp = FALSE;
            		p_ptr->running = 9;
            	}
            }
            
            /* Smart enough to sense trouble */
            else if ((!p_resist_pos(P_RES_FIRE))
					 || (!p_resist_strong(P_RES_FIRE)
						 && (p_ptr->chp <= 100))
					 || (!p_immune(P_RES_FIRE) && (p_ptr->chp <= 30))) {
				if (no_options) {}
				else if (!get_check
					("The heat of the fire burns you! Really enter? ")) {
					temp = FALSE;
				}
			}

			/* Enter if OK or confirmed. */
			if (temp) {
				/* Can always cross. */
				can_move = TRUE;

				/* Take light damage from the fire */
				temp = 49 + randint1(51);

				/* Will take serious fire damage. */
				fire_dam(temp, "burnt to death in a fire.", SOURCE_ENVIRONMENTAL);
			}
			else
				/* Player refuse to go. */
				can_move = FALSE;
		}

		if (tf_has(f_ptr->flags, TF_FALL)) {
			/* Bats, dragons can fly */
			if (!(p_ptr->schange == SHAPE_BAT) &&
				!(p_ptr->schange == SHAPE_WYRM)) {
				/* Assume player will continue. */
				temp = TRUE;

				/* Smart enough to stop running. */
				if (p_ptr->running) {
					if (no_options) {}
					else if (!get_check
						("You have come to a cliff.  Step off it? ")) {
						can_move = FALSE;
						temp = FALSE;
						p_ptr->running = 0;
					}
				}

				/* Smart enough to sense trouble. */
				else if (!p_ptr->timed[TMD_BLIND]) {
					if (no_options) {}
					else if (!get_check("It's a cliff! Really step off it? ")) {
						can_move = FALSE;
						temp = FALSE;
					}
				}

				/* Step off if confirmed. */
				if (temp) {
					/* Will take serious damage. */
					falling = TRUE;
				}
			}
		}
	}

	/* If the player can move, handle various things. */
	if (can_move) {
		/* Move player */
		monster_swap(py, px, y, x);

		/* Update speed if stepping out of water */
		if (tf_has(f_info[cave_feat[py][px]].flags, TF_WATERY))
			p_ptr->update |= PU_BONUS;

		/* Update stealth for Unlight */
		if (player_has(PF_UNLIGHT))
			p_ptr->update |= PU_BONUS;

		/* Update speed for Plant cutie mark woodspersons */
		if (player_has(PF_WOODSMAN) && player_has(PF_PLANT_FRIEND))
			p_ptr->update |= PU_BONUS;

		/* New location */
		y = py = p_ptr->py;
		x = px = p_ptr->px;
		f_ptr = &f_info[cave_feat[y][x]];
		    

		/* Fall off a cliff */
		if (falling)
			fall_off_cliff();
			
		
        /* Sliding on ice prevents searching */
        if (!icy_slide)
        {
			/* Spontaneous Searching */
			if (p_ptr->state.skills[SKILL_SEARCH_FREQUENCY] > 49) {
				(void) search(FALSE);
			} else if (0 ==
					   randint0(50 -
								p_ptr->state.skills[SKILL_SEARCH_FREQUENCY])) {
				(void) search(FALSE);
			}
	
			/* Continuous Searching */
			if (p_ptr->searching) {
				(void) search(FALSE);
			}
		}

		/* Handle "store doors" */
		if (tf_has(f_ptr->flags, TF_SHOP)) {
			/* Disturb */
			disturb(0, 0);
			cmd_insert(CMD_ENTER_STORE);
		}

		/* All other grids (including traps) */
		else {
			/* Handle objects (later) */
			p_ptr->notice |= (PN_PICKUP);
		}

		/* Flying players have a chance to miss traps */
		if ((p_ptr->schange == SHAPE_BAT)
			|| (p_ptr->schange == SHAPE_WYRM)) {
			if (cave_invisible_trap(y, x) && cave_player_trap(y, x)
				&& (randint0(3) != 0))
				trapped = FALSE;
			else if (cave_visible_trap(y, x) && cave_player_trap(y, x) &&
					 (randint0(10) != 0))
				trapped = FALSE;
		}

		/* Discover invisible traps */
		if (cave_invisible_trap(y, x) && trapped) {
			/* Disturb */
			disturb(0, 0);

			/* Hit the trap. */
			hit_trap(y, x);
		}

		/* Set off a visible trap */
		else if (cave_visible_trap(y, x) && cave_player_trap(y, x) &&
				 trapped) {
			/* Disturb */
			disturb(0, 0);

			/* Hit the trap. */
			hit_trap(y, x);
		}

		/* Walk on a monster trap */
		else if (cave_monster_trap(y, x)) {
			msg("You inspect your cunning trap.");
		}
		
		/* Slide an additional square on the ice */
		if (icy_slide)
		    move_player(dir, TRUE);
	}
}
예제 #11
0
파일: trap.c 프로젝트: magnate/angband
/**
 * Hit a trap. 
 */
extern void hit_trap(int y, int x)
{
	bool ident = false;
	struct trap *trap;
	struct effect *effect;

    /* Count the hidden traps here */
    int num = num_traps(cave, y, x, -1);

	/* The player is safe from all traps */
	if (player_is_trapsafe(player)) return;

    /* Oops.  We've walked right into trouble. */
    if      (num == 1) msg("You stumble upon a trap!");
    else if (num >  1) msg("You stumble upon some traps!");


	/* Look at the traps in this grid */
	for (trap = square_trap(cave, y, x); trap; trap = trap->next) {
		int flag;
		bool saved = false;

		/* Require that trap be capable of affecting the character */
		if (!trf_has(trap->kind->flags, TRF_TRAP)) continue;
		if (trap->timeout) continue;

		/* Disturb the player */
		disturb(player, 0);

		/* Give a message */
		if (trap->kind->msg)
			msg(trap->kind->msg);

		/* Test for save due to flag */
		for (flag = of_next(trap->kind->save_flags, FLAG_START);
			 flag != FLAG_END;
			 flag = of_next(trap->kind->save_flags, flag + 1))
			if (player_of_has(player, flag)) {
				saved = true;
				equip_learn_flag(player, flag);
			}

		/* Test for save due to armor */
		if (trf_has(trap->kind->flags, TRF_SAVE_ARMOR) && !trap_check_hit(125))
			saved = true;

		/* Test for save due to saving throw */
		if (trf_has(trap->kind->flags, TRF_SAVE_THROW) &&
			(randint0(100) < player->state.skills[SKILL_SAVE]))
			saved = true;

		/* Save, or fire off the trap */
		if (saved) {
			if (trap->kind->msg_good)
				msg(trap->kind->msg_good);
		} else {
			if (trap->kind->msg_bad)
				msg(trap->kind->msg_bad);
			effect = trap->kind->effect;
			effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0);

			/* Do any extra effects */
			if (trap->kind->effect_xtra && one_in_(2)) {
				if (trap->kind->msg_xtra)
					msg(trap->kind->msg_xtra);
				effect = trap->kind->effect_xtra;
				effect_do(effect, source_trap(trap), NULL, &ident, false, 0, 0, 0);
			}
		}

		/* Some traps drop you a dungeon level */
		if (trf_has(trap->kind->flags, TRF_DOWN))
			dungeon_change_level(player,
								 dungeon_get_next_level(player->depth, 1));

		/* Some traps drop you onto them */
		if (trf_has(trap->kind->flags, TRF_PIT))
			monster_swap(player->py, player->px, trap->fy, trap->fx);

		/* Some traps disappear after activating, all have a chance to */
		if (trf_has(trap->kind->flags, TRF_ONETIME) || one_in_(3)) {
			square_destroy_trap(cave, y, x);
			square_forget(cave, y, x);
		}

		/* Trap may have gone */
		if (!square_trap(cave, y, x)) break;

		/* Trap becomes visible (always XXX) */
		trf_on(trap->flags, TRF_VISIBLE);
		square_memorize(cave, y, x);
	}

    /* Verify traps (remove marker if appropriate) */
    (void)square_verify_trap(cave, y, x, 0);
}