/** * Determine if a given location may be "destroyed" * * Used by destruction spells, and for placing stairs, etc. */ bool square_changeable(struct chunk *c, int y, int x) { object_type *obj; /* Forbid perma-grids */ if (square_isperm(c, y, x) || square_isshop(c, y, x) || square_isstairs(c, y, x)) return (FALSE); /* Check objects */ for (obj = square_object(c, y, x); obj; obj = obj->next) /* Forbid artifact grids */ if (obj->artifact) return (FALSE); /* Accept */ return (TRUE); }
/* From Will Asher in DJA: * Find whether a monster is near a permanent wall * this decides whether PASS_WALL & KILL_WALL monsters * use the monster flow code */ static bool near_permwall(const struct monster *mon, struct chunk *c) { int y, x; int my = mon->fy; int mx = mon->fx; /* if PC is in LOS, there's no need to go around walls */ if (projectable(cave, my, mx, player->py, player->px, PROJECT_NONE)) return false; /* PASS_WALL & KILL_WALL monsters occasionally flow for a turn anyway */ if (randint0(99) < 5) return true; /* Search the nearby grids, which are always in bounds */ for (y = (my - 2); y <= (my + 2); y++) { for (x = (mx - 2); x <= (mx + 2); x++) { if (!square_in_bounds_fully(c, y, x)) continue; if (square_isperm(c, y, x)) return true; } } return false; }
/** * Determine if a given grid may be "tunneled" */ static bool do_cmd_tunnel_test(int y, int x) { /* Must have knowledge */ if (!square_isknown(cave, y, x)) { msg("You see nothing there."); return (false); } /* Titanium */ if (square_isperm(cave, y, x)) { msg("This seems to be permanent rock."); return (false); } /* Must be a wall/door/etc */ if (!(square_isdiggable(cave, y, x) || square_iscloseddoor(cave, y, x))) { msg("You see nothing there to tunnel."); return (false); } /* Okay */ return (true); }
/** * True if the square is a permanent wall or one of the "stronger" walls. * * The stronger walls are granite, magma and quartz. This excludes things like * secret doors and rubble. */ bool square_isstrongwall(struct chunk *c, int y, int x) { assert(square_in_bounds(c, y, x)); return square_ismineral(c, y, x) || square_isperm(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; }
/* Destroy walls (and doors) */ static void project_feature_handler_KILL_WALL(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Non-walls (etc) */ if (square_ispassable(cave, y, x)) return; /* Permanent walls */ if (square_isperm(cave, y, x)) return; /* Different treatment for different walls */ if (square_iswall(cave, y, x) && !square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The wall turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_iswall(cave, y, x) && square_hasgoldvein(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); msg("You have found something!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); /* Place some gold */ place_gold(cave, y, x, player->depth, ORIGIN_FLOOR); } else if (square_ismagma(cave, y, x) || square_isquartz(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The vein turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the wall */ square_destroy_wall(cave, y, x); } else if (square_isrubble(cave, y, x)) { /* Message */ if (square_isseen(cave, y, x)) { msg("The rubble turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the rubble */ square_destroy_rubble(cave, y, x); /* Hack -- place an object */ if (randint0(100) < 10){ if (square_isseen(cave, y, x)) { msg("There was something buried in the rubble!"); context->obvious = true; } place_object(cave, y, x, player->depth, false, false, ORIGIN_RUBBLE, 0); } } else if (square_isdoor(cave, y, x)) { /* Hack -- special message */ if (square_isseen(cave, y, x)) { msg("The door turns into mud!"); context->obvious = true; /* Forget the wall */ square_forget(cave, y, x); } /* Destroy the feature */ square_destroy_door(cave, y, x); } /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); /* Fully update the flow */ player->upkeep->update |= (PU_FORGET_FLOW | PU_UPDATE_FLOW); }
/** * 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; }