/* Destroy Traps (and Locks) */ static void project_feature_handler_KILL_TRAP(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Reveal secret doors */ if (square_issecretdoor(cave, y, x)) { place_closed_door(cave, y, x); /* Check line of sight */ if (square_isseen(cave, y, x)) context->obvious = true; } /* Destroy traps, unlock doors */ if (square_istrap(cave, y, x)) { /* Check line of sight */ if (square_isview(cave, y, x)) { msg("There is a bright flash of light!"); context->obvious = true; } /* Destroy the trap */ square_destroy_trap(cave, y, x); } else if (square_islockeddoor(cave, y, x)) { /* Unlock the door */ square_unlock_door(cave, y, x); /* Check line of sound */ if (square_isview(cave, y, x)) { msg("Click!"); context->obvious = true; } } }
/** * Perform the basic "tunnel" command * * Assumes that no monster is blocking the destination. * Uses twall() (above) to do all "terrain feature changing". * Returns true if repeated commands may continue. */ static bool do_cmd_tunnel_aux(int y, int x) { bool more = false; int digging_chances[DIGGING_MAX]; bool okay = false; bool gold = square_hasgoldvein(cave, y, x); bool rubble = square_isrubble(cave, y, x); /* Verify legality */ if (!do_cmd_tunnel_test(y, x)) return (false); calc_digging_chances(&player->state, digging_chances); /* Do we succeed? */ okay = (digging_chances[square_digging(cave, y, x) - 1] > randint0(1600)); /* Success */ if (okay && twall(y, x)) { /* Rubble is a special case - could be handled more generally NRM */ if (rubble) { /* Message */ msg("You have removed the rubble."); /* Place an object (except in town) */ if ((randint0(100) < 10) && player->depth) { /* Create a simple object */ place_object(cave, y, x, player->depth, false, false, ORIGIN_RUBBLE, 0); /* Observe the new object */ if (!ignore_item_ok(square_object(cave, y, x)) && square_isseen(cave, y, x)) msg("You have found something!"); } } else if (gold) { /* Found treasure */ place_gold(cave, y, x, player->depth, ORIGIN_FLOOR); msg("You have found something!"); } else { msg("You have finished the tunnel."); } } else { /* Failure, continue digging */ if (rubble) msg("You dig in the rubble."); else msg("You tunnel into the %s.", square_apparent_name(cave, player, y, x)); more = true; if (square_issecretdoor(cave, y, x)) /* Occasional Search XXX XXX */ if (randint0(100) < 25) search(false); } /* Result */ return (more); }
/** * Search for traps or secret doors */ static void search(void) { int py = player->py; int px = player->px; int y, x; struct object *obj; /* Various conditions mean no searching */ if (player->timed[TMD_BLIND] || no_light() || player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) return; /* Search the nearby grids, which are always in bounds */ for (y = (py - 1); y <= (py + 1); y++) { for (x = (px - 1); x <= (px + 1); x++) { /* Traps */ if (square_issecrettrap(cave, y, x)) { if (square_reveal_trap(cave, y, x, true)) disturb(player, 0); } /* Secret doors */ if (square_issecretdoor(cave, y, x)) { msg("You have found a secret door."); place_closed_door(cave, y, x); disturb(player, 0); } /* Traps on chests */ for (obj = square_object(cave, y, x); obj; obj = obj->next) { if (!obj->known || !is_trapped_chest(obj)) continue; if (obj->known->pval != obj->pval) { msg("You have discovered a trap on the chest!"); obj->known->pval = obj->pval; disturb(player, 0); } } } } }
/** * True if the square can be dug: this includes rubble and non-permanent walls. */ bool square_isdiggable(struct chunk *c, int y, int x) { return (square_ismineral(c, y, x) || square_issecretdoor(c, y, x) || square_isrubble(c, y, x)); }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns true if the monster is able to move through the grid. */ static bool process_monster_can_move(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny, bool *did_something) { struct monster_lore *lore = get_lore(mon->race); /* Only fiery creatures can handle lava */ if (square_isfiery(c, ny, nx) && !rf_has(mon->race->flags, RF_IM_FIRE)) return false; /* Floor is open? */ if (square_ispassable(c, ny, nx)) return true; /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) return false; /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_PASS_WALL); rf_on(lore->flags, RF_KILL_WALL); } /* Monster may be able to deal with walls and doors */ if (rf_has(mon->race->flags, RF_PASS_WALL)) { return true; } else if (rf_has(mon->race->flags, RF_KILL_WALL)) { /* Remove the wall */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow since terrain changed */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); return true; } else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool may_bash = rf_has(mon->race->flags, RF_BASH_DOOR) && one_in_(2); /* Take a turn */ *did_something = true; /* Learn about door abilities */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { rf_on(lore->flags, RF_OPEN_DOOR); rf_on(lore->flags, RF_BASH_DOOR); } /* Creature can open or bash doors */ if (!rf_has(mon->race->flags, RF_OPEN_DOOR) && !rf_has(mon->race->flags, RF_BASH_DOOR)) return false; /* Stuck door -- try to unlock it */ if (square_islockeddoor(c, ny, nx)) { int k = square_door_power(c, ny, nx); if (randint0(mon->hp / 10) > k) { if (may_bash) msg("%s slams against the door.", m_name); else msg("%s fiddles with the lock.", m_name); /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Handle viewable doors */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Closed or secret door -- open or bash if allowed */ if (may_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return true; } else if (rf_has(mon->race->flags, RF_OPEN_DOOR)) { square_open_door(c, ny, nx); } } } return false; }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns TRUE if the monster is able to move through the grid. */ static bool process_monster_can_move(struct chunk *c, struct monster *m_ptr, const char *m_name, int nx, int ny, bool *did_something) { monster_lore *l_ptr = get_lore(m_ptr->race); /* Floor is open? */ if (square_ispassable(c, ny, nx)) return TRUE; /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) return FALSE; /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) { rf_on(l_ptr->flags, RF_PASS_WALL); rf_on(l_ptr->flags, RF_KILL_WALL); } /* Monster moves through walls (and doors) */ if (rf_has(m_ptr->race->flags, RF_PASS_WALL)) return TRUE; /* Monster destroys walls (and doors) */ else if (rf_has(m_ptr->race->flags, RF_KILL_WALL)) { /* Forget the wall */ sqinfo_off(c->squares[ny][nx].info, SQUARE_MARK); /* Notice */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (player_has_los_bold(ny, nx)) player->upkeep->update |= PU_UPDATE_VIEW; /* Update the flow, since walls affect flow */ player->upkeep->update |= PU_UPDATE_FLOW; return TRUE; } /* Handle doors and secret doors */ else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool may_bash = rf_has(m_ptr->race->flags, RF_BASH_DOOR) && one_in_(2); /* Take a turn */ *did_something = TRUE; /* Learn about door abilities */ if (mflag_has(m_ptr->mflag, MFLAG_VISIBLE)) { rf_on(l_ptr->flags, RF_OPEN_DOOR); rf_on(l_ptr->flags, RF_BASH_DOOR); } /* Creature can open or bash doors */ if (!rf_has(m_ptr->race->flags, RF_OPEN_DOOR) && !rf_has(m_ptr->race->flags, RF_BASH_DOOR)) return FALSE; /* Stuck door -- try to unlock it */ if (square_islockeddoor(c, ny, nx)) { int k = square_door_power(c, ny, nx); if (randint0(m_ptr->hp / 10) > k) { if (may_bash) msg("%s slams against the door.", m_name); else msg("%s fiddles with the lock.", m_name); /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Handle viewable doors */ if (player_has_los_bold(ny, nx)) player->upkeep->update |= PU_UPDATE_VIEW; /* Closed or secret door -- open or bash if allowed */ if (may_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return TRUE; } else if (rf_has(m_ptr->race->flags, RF_OPEN_DOOR)) { square_open_door(c, ny, nx); } } } return FALSE; }
/** * Search for hidden things. Returns true if a search was attempted, returns * false when the player has a 0% chance of finding anything. Prints messages * for negative confirmation when verbose mode is requested. */ bool search(bool verbose) { int py = player->py; int px = player->px; int y, x, chance; bool found = false; struct object *obj; /* Start with base search ability */ chance = player->state.skills[SKILL_SEARCH]; /* Penalize various conditions */ if (player->timed[TMD_BLIND] || no_light()) chance = chance / 10; if (player->timed[TMD_CONFUSED] || player->timed[TMD_IMAGE]) chance = chance / 10; /* Prevent fruitless searches */ if (chance <= 0) { if (verbose) { msg("You can't make out your surroundings well enough to search."); /* Cancel repeat */ disturb(player, 0); } return false; } /* Search the nearby grids, which are always in bounds */ for (y = (py - 1); y <= (py + 1); y++) { for (x = (px - 1); x <= (px + 1); x++) { /* Sometimes, notice things */ if (randint0(100) < chance) { if (square_issecrettrap(cave, y, x)) { found = true; /* Reveal trap, display a message */ if (square_reveal_trap(cave, y, x, chance, true)) /* Disturb */ disturb(player, 0); } /* Secret door */ if (square_issecretdoor(cave, y, x)) { found = true; /* Message */ msg("You have found a secret door."); /* Pick a door */ place_closed_door(cave, y, x); /* Disturb */ disturb(player, 0); } /* Scan all objects in the grid */ for (obj = square_object(cave, y, x); obj; obj = obj->next) { /* Skip if not a trapped chest */ if (!is_trapped_chest(obj)) continue; /* Identify once */ if (!object_is_known(obj)) { found = true; /* Message */ msg("You have discovered a trap on the chest!"); /* Know the trap */ object_notice_everything(obj); /* Notice it */ disturb(player, 0); } } } } } if (verbose && !found) { if (chance >= 100) msg("There are no secrets here."); else msg("You found nothing."); } return true; }
/** * Work out if a monster can move through the grid, if necessary bashing * down doors in the way. * * Returns true if the monster is able to move through the grid. */ static bool monster_turn_can_move(struct chunk *c, struct monster *mon, const char *m_name, int nx, int ny, bool *did_something) { struct monster_lore *lore = get_lore(mon->race); /* Dangerous terrain in the way */ if (monster_hates_grid(c, mon, ny, nx)) { return false; } /* Floor is open? */ if (square_ispassable(c, ny, nx)) { return true; } /* Permanent wall in the way */ if (square_iswall(c, ny, nx) && square_isperm(c, ny, nx)) { return false; } /* Normal wall, door, or secret door in the way */ /* There's some kind of feature in the way, so learn about * kill-wall and pass-wall now */ if (monster_is_visible(mon)) { rf_on(lore->flags, RF_PASS_WALL); rf_on(lore->flags, RF_KILL_WALL); } /* Monster may be able to deal with walls and doors */ if (rf_has(mon->race->flags, RF_PASS_WALL)) { return true; } else if (rf_has(mon->race->flags, RF_KILL_WALL)) { /* Remove the wall */ square_destroy_wall(c, ny, nx); /* Note changes to viewable region */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); return true; } else if (square_iscloseddoor(c, ny, nx) || square_issecretdoor(c, ny, nx)) { bool can_open = rf_has(mon->race->flags, RF_OPEN_DOOR); bool can_bash = rf_has(mon->race->flags, RF_BASH_DOOR); bool will_bash = false; /* Take a turn */ *did_something = true; /* Learn about door abilities */ if (monster_is_visible(mon)) { rf_on(lore->flags, RF_OPEN_DOOR); rf_on(lore->flags, RF_BASH_DOOR); } /* If creature can open or bash doors, make a choice */ if (can_open) { /* Sometimes bash anyway (impatient) */ if (can_bash) { will_bash = one_in_(2) ? true : false; } } else if (can_bash) { /* Only choice */ will_bash = true; } else { /* Door is an insurmountable obstacle */ return false; } /* Now outcome depends on type of door */ if (square_islockeddoor(c, ny, nx)) { /* Locked door -- test monster strength against door strength */ int k = square_door_power(c, ny, nx); if (randint0(mon->hp / 10) > k) { if (will_bash) { msg("%s slams against the door.", m_name); } else { msg("%s fiddles with the lock.", m_name); } /* Reduce the power of the door by one */ square_set_door_lock(c, ny, nx, k - 1); } } else { /* Closed or secret door -- always open or bash */ if (square_isview(c, ny, nx)) player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); if (will_bash) { square_smash_door(c, ny, nx); msg("You hear a door burst open!"); disturb(player, 0); /* Fall into doorway */ return true; } else { square_open_door(c, ny, nx); } } } return false; }