/** * Perform the basic "disarm" command * * Assume there is no monster blocking the destination * * Returns true if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int skill, power, chance; struct trap *trap = cave->squares[y][x].trap; bool more = false; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (false); /* Choose first player trap */ while (trap) { if (trf_has(trap->flags, TRF_TRAP)) break; trap = trap->next; } if (!trap) return false; /* Get the base disarming skill */ if (trf_has(trap->flags, TRF_MAGICAL)) skill = player->state.skills[SKILL_DISARM_MAGIC]; else skill = player->state.skills[SKILL_DISARM_PHYS]; /* Penalize some conditions */ if (player->timed[TMD_BLIND] || no_light() || player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) skill = skill / 10; /* Extract trap power */ power = cave->depth / 5; /* Extract the percentage success */ chance = skill - power; /* Always have a small chance of success */ if (chance < 2) chance = 2; /* Two chances - one to disarm, one not to set the trap off */ if (randint0(100) < chance) { msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); player_exp_gain(player, power); /* Trap is gone */ square_forget(cave, y, x); square_destroy_trap(cave, y, x); } else if (randint0(100) < chance) { event_signal(EVENT_INPUT_FLUSH); msg("You failed to disarm the %s.", trap->kind->name); /* Player can try again */ more = true; } else { msg("You set off the %s!", trap->kind->name); hit_trap(y, x); } /* Result */ return (more); }
/** * 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; }
/* * Perform the basic "disarm" command * * Assume there is no monster blocking the destination * * Returns TRUE if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int i, j, power; cptr name; bool more = FALSE; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (FALSE); /* Get the trap name */ name = f_info[cave_feat[y][x]].name; /* Get the "disarm" factor */ i = p_ptr->state.skills[SKILL_DISARM]; /* Penalize some conditions */ if (p_ptr->timed[TMD_BLIND] || no_light()) i = i / 10; if (p_ptr->timed[TMD_CONFUSED] || p_ptr->timed[TMD_IMAGE]) i = i / 10; /* XXX XXX XXX Variable power? */ /* Extract trap "power" */ power = 5; /* Extract the difficulty */ j = i - power; /* Always have a small chance of success */ if (j < 2) j = 2; /* Success */ if (randint0(100) < j) { /* Message */ message_format(MSG_DISARM, 0, "You have disarmed the %s.", name); /* Reward */ gain_exp(power); /* Forget the trap */ cave_info[y][x] &= ~(CAVE_MARK); /* Remove the trap */ cave_set_feat(y, x, FEAT_FLOOR); } /* Failure -- Keep trying */ else if ((i > 5) && (randint1(i) > 5)) { flush(); /* Message */ msg_format("You failed to disarm the %s.", name); /* We may keep trying */ more = TRUE; } /* Failure -- Set off the trap */ else { /* Message */ msg_format("You set off the %s!", name); /* Hit the trap */ hit_trap(y, x); } /* Result */ return (more); }
/* * 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; }
/** * 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."); } } } }
/* * Perform the basic "disarm" command on a trap or glyph. * * Assume there is no monster blocking the destination (tested by * do_cmd_disarm). Traps now have level-dependent power. * Decrement Rogue traps and glyphs of warding. -LM- * * Returns TRUE if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int i, j, power; const char * name; bool more = FALSE; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (FALSE); /* Access trap or glyph name */ name = (f_name + f_info[cave_feat[y][x]].name); /* Get the "disarm" factor */ i = p_ptr->skill_dis; /* Penalize some conditions */ if (p_ptr->blind || no_lite()) i = i / 10; if (p_ptr->confused || p_ptr->image) i = i / 10; /* Extract trap "power". */ power = 5 + p_ptr->depth / 4; /* Prevent the player's own traps granting exp. */ if ((cave_feat[y][x] >= FEAT_MTRAP_HEAD) && (cave_feat[y][x] <= FEAT_MTRAP_TAIL)) power = 0; /* Prevent glyphs of warding granting exp. */ if (cave_feat[y][x] == FEAT_GLYPH) power = 0; /* Extract the disarm probability */ j = i - power; /* Always have a small chance of success */ if (j < 2) j = 2; /* Success */ if ((power == 0) || (randint0(100) < j)) { /* Special message for glyphs. */ if (cave_feat[y][x] == FEAT_GLYPH) msg("You have desanctified the %s.", name); /* Normal message otherwise */ else msg("You have disarmed the %s.", name); /* If a Rogue's monster trap, decrement the trap count. */ if ((cave_feat[y][x] >= FEAT_MTRAP_HEAD) && (cave_feat[y][x] <= FEAT_MTRAP_TAIL)) num_trap_on_level--; /* If a glyph, decrement the glyph count. */ if (cave_feat[y][x] == FEAT_GLYPH) num_glyph_on_level--; /* Reward */ gain_exp(power); /* Forget the trap */ cave_info[y][x] &= ~(CAVE_MARK); /* Remove the trap */ cave_set_feat(y, x, FEAT_FLOOR); } /* Failure -- Keep trying */ else if ((i > 5) && (randint1(i) > 5)) { /* Failure */ if (flush_failure) flush(); /* Message */ msg("You failed to disarm the %s.", name); /* We may keep trying */ more = TRUE; } /* Failure -- Set off the trap */ else { /* Message */ msg("You set off the %s!", name); /* Hit the trap */ hit_trap(y, x); } /* Result */ return (more); }
/** * Perform the basic "disarm" command * * Assume there is no monster blocking the destination * * Returns true if repeated commands may continue */ static bool do_cmd_disarm_aux(int y, int x) { int i, j, power; struct trap *trap = cave->squares[y][x].trap; bool more = false; /* Verify legality */ if (!do_cmd_disarm_test(y, x)) return (false); /* Choose first player trap */ while (trap) { if (trf_has(trap->flags, TRF_TRAP)) break; trap = trap->next; } if (!trap) return false; /* Get the "disarm" factor */ i = player->state.skills[SKILL_DISARM]; /* Penalize some conditions */ if (player->timed[TMD_BLIND] || no_light()) i = i / 10; if (player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) i = i / 10; /* XXX XXX XXX Variable power? */ /* Extract trap "power" */ power = 5; /* Extract the difficulty */ j = i - power; /* Always have a small chance of success */ if (j < 2) j = 2; /* Success */ if (randint0(100) < j) { /* Message */ msgt(MSG_DISARM, "You have disarmed the %s.", trap->kind->name); /* Reward */ player_exp_gain(player, power); /* Forget the trap */ square_forget(cave, y, x); /* Remove the trap */ square_destroy_trap(cave, y, x); } else if ((i > 5) && (randint1(i) > 5)) { /* Failure -- Keep trying */ event_signal(EVENT_INPUT_FLUSH); msg("You failed to disarm the %s.", trap->kind->name); more = true; } else { /* Failure -- Set off the trap */ msg("You set off the %s!", trap->kind->name); hit_trap(y, x); } /* Result */ return (more); }
/** * 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; }
/** * 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); } }