/* Make doors */ static void project_feature_handler_MAKE_DOOR(project_feature_handler_context_t *context) { const int x = context->x; const int y = context->y; /* Require a grid without monsters */ if (square_monster(cave, y, x)) return; /* Require a floor grid */ if (!square_isfloor(cave, y, x)) return; /* Push objects off the grid */ if (square_object(cave, y, x)) push_object(y,x); /* Create closed door */ square_add_door(cave, y, x, true); /* Observe */ if (square_isknown(cave, y, x)) context->obvious = true; /* Update the visuals */ player->upkeep->update |= (PU_UPDATE_VIEW | PU_MONSTERS); }
static bool is_valid_pf(int y, int x) { /* Unvisited means allowed */ if (!square_isknown(cave, y, x)) return (true); /* Require open space */ return (square_ispassable(cave, y, x)); }
/** * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->squares[y][x].mon; struct monster *mon = cave_monster(cave, m_idx); /* Allow attack on visible monsters if unafraid */ if (m_idx > 0 && mflag_has(mon->mflag, MFLAG_VISIBLE) && !is_mimicking(mon)) { /* Handle player fear */ if (player_of_has(player, OF_AFRAID)) { /* Extract monster name (or "it") */ char m_name[80]; monster_desc(m_name, sizeof(m_name), mon, MDESC_DEFAULT); /* Message */ msgt(MSG_AFRAID, "You are too afraid to attack %s!", m_name); /* Nope */ return (false); } return (true); } /* If we don't know the grid, allow attempts to walk into it */ if (!square_isknown(cave, y, x)) return true; /* Require open space */ if (!square_ispassable(cave, y, x)) { if (square_isrubble(cave, y, x)) /* Rubble */ msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); else if (square_iscloseddoor(cave, y, x)) /* Door */ return true; else if (square_isbright(cave, y, x)) /* Lava */ msgt(MSG_HITWALL, "The heat of the lava turns you away!"); else /* Wall */ msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(player, 0); /* Nope */ return (false); } /* Okay */ return (true); }
/** * Determine if a given grid may be "opened" */ static bool do_cmd_open_test(int y, int x) { /* Must have knowledge */ if (!square_isknown(cave, y, x)) { msg("You see nothing there."); return false; } /* Must be a closed door */ if (!square_iscloseddoor(cave, y, x)) { msgt(MSG_NOTHING_TO_OPEN, "You see nothing there to open."); return false; } return (true); }
/** * Hack -- Check for a "known wall" (see below) */ static int see_wall(int dir, int y, int x) { /* Get the new location */ y += ddy[dir]; x += ddx[dir]; /* Illegal grids are not known walls XXX XXX XXX */ if (!square_in_bounds(cave, y, x)) return (false); /* Non-wall grids are not known walls */ if (!square_seemslikewall(cave, y, x)) return false; /* Unknown walls are not known walls */ if (!square_isknown(cave, y, x)) return (false); /* Default */ return (true); }
/** * Memorize interesting viewable object/features in the given grid * * This function should only be called on "legal" grids. * * This function will memorize the object and/or feature in the given grid, * if they are (1) see-able and (2) interesting. Note that all objects are * interesting, all terrain features except floors (and invisible traps) are * interesting, and floors (and invisible traps) are interesting sometimes * (depending on various options involving the illumination of floor grids). * * The automatic memorization of all objects and non-floor terrain features * as soon as they are displayed allows incredible amounts of optimization * in various places, especially "map_info()" and this function itself. * * Note that the memorization of objects is completely separate from the * memorization of terrain features, preventing annoying floor memorization * when a detected object is picked up from a dark floor, and object * memorization when an object is dropped into a floor grid which is * memorized but out-of-sight. * * This function should be called every time the "memorization" of a grid * (or the object in a grid) is called into question, such as when an object * is created in a grid, when a terrain feature "changes" from "floor" to * "non-floor", and when any grid becomes "see-able" for any reason. * * This function is called primarily from the "update_view()" function, for * each grid which becomes newly "see-able". */ void square_note_spot(struct chunk *c, int y, int x) { /* Require "seen" flag and the current level */ if (c != cave) return; if (!square_isseen(c, y, x)) return; /* Make the player know precisely what is on this grid */ square_know_pile(c, y, x); /* Notice traps */ if (square_issecrettrap(c, y, x)) { square_reveal_trap(c, y, x, false, true); } if (square_isknown(c, y, x)) return; /* Memorize this grid */ square_memorize(c, y, x); }
/** * Determine if a given grid may be "disarmed" */ static bool do_cmd_disarm_test(int y, int x) { /* Must have knowledge */ if (!square_isknown(cave, y, x)) { msg("You see nothing there."); return false; } /* Look for a closed, unlocked door to lock */ if (square_iscloseddoor(cave, y, x) && !square_islockeddoor(cave, y, x)) return true; /* Look for a trap */ if (!square_isknowntrap(cave, y, x)) { msg("You see nothing there to disarm."); return false; } /* Okay */ return true; }
/** * Return the number of doors/traps around (or under) the character. */ int count_feats(int *y, int *x, bool (*test)(struct chunk *c, int y, int x), bool under) { int d; int xx, yy; int count = 0; /* Count how many matches */ /* Check around (and under) the character */ for (d = 0; d < 9; d++) { /* if not searching under player continue */ if ((d == 8) && !under) continue; /* Extract adjacent (legal) location */ yy = player->py + ddy_ddd[d]; xx = player->px + ddx_ddd[d]; /* Paranoia */ if (!square_in_bounds_fully(cave, yy, xx)) continue; /* Must have knowledge */ if (!square_isknown(cave, yy, xx)) continue; /* Not looking for this feature */ if (!((*test)(cave, yy, xx))) continue; /* Count it */ ++count; /* Remember the location of the last door found */ if (x && y) { *y = yy; *x = xx; } } /* All done */ return count; }
/** * Determine if a given location is "interesting" */ bool target_accept(int y, int x) { struct loc grid = loc(x, y); struct object *obj; /* Player grids are always interesting */ if (square(cave, grid).mon < 0) return true; /* Handle hallucination */ if (player->timed[TMD_IMAGE]) return false; /* Obvious monsters */ if (square(cave, grid).mon > 0) { struct monster *mon = square_monster(cave, grid); if (monster_is_obvious(mon)) { return true; } } /* Traps */ if (square_isvisibletrap(cave, grid)) return true; /* Scan all objects in the grid */ for (obj = square_object(player->cave, grid); obj; obj = obj->next) { /* Memorized object */ if ((obj->kind == unknown_item_kind) || !ignore_known_item_ok(obj)) { return true; } } /* Interesting memorized features */ if (square_isknown(cave, grid) && square_isinteresting(cave, grid)) { return true; } /* Nope */ 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); }
/** * Determine if a given grid may be "closed" */ static bool do_cmd_close_test(int y, int x) { /* Must have knowledge */ if (!square_isknown(cave, y, x)) { /* Message */ msg("You see nothing there."); /* Nope */ return (false); } /* Require open/broken door */ if (!square_isopendoor(cave, y, x) && !square_isbrokendoor(cave, y, x)) { /* Message */ msg("You see nothing there to close."); /* Nope */ return (false); } /* Okay */ return (true); }
/** * Determine if a given location is "interesting" */ bool target_accept(int y, int x) { struct object *obj; /* Player grids are always interesting */ if (cave->squares[y][x].mon < 0) return (true); /* Handle hallucination */ if (player->timed[TMD_IMAGE]) return (false); /* Visible monsters */ if (cave->squares[y][x].mon > 0) { struct monster *mon = square_monster(cave, y, x); /* Visible monsters */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && !mflag_has(mon->mflag, MFLAG_UNAWARE)) return (true); } /* Traps */ if (square_isvisibletrap(cave, y, x)) return(true); /* Scan all objects in the grid */ for (obj = square_object(cave_k, y, x); obj; obj = obj->next) /* Memorized object */ if (!ignore_known_item_ok(obj)) return (true); /* Interesting memorized features */ if (square_isknown(cave, y, x) && square_isinteresting(cave, y, x)) return (true); /* Nope */ return (false); }
/** * This function takes a grid location (x, y) and extracts information the * player is allowed to know about it, filling in the grid_data structure * passed in 'g'. * * The information filled in is as follows: * - g->f_idx is filled in with the terrain's feature type, or FEAT_NONE * if the player doesn't know anything about the grid. The function * makes use of the "mimic" field in terrain in order to allow one * feature to look like another (hiding secret doors, invisible traps, * etc). This will return the terrain type the player "Knows" about, * not necessarily the real terrain. * - g->m_idx is set to the monster index, or 0 if there is none (or the * player doesn't know it). * - g->first_kind is set to the object_kind of the first object in a grid * that the player knows about, or NULL for no objects. * - g->muliple_objects is true if there is more than one object in the * grid that the player knows and cares about (to facilitate any special * floor stack symbol that might be used). * - g->in_view is true if the player can currently see the grid - this can * be used to indicate field-of-view, such as through the * OPT(player, view_bright_light) option. * - g->lighting is set to indicate the lighting level for the grid: * LIGHTING_DARK for unlit grids, LIGHTING_LIT for inherently light * grids (lit rooms, etc), LIGHTING_TORCH for grids lit by the player's * light source, and LIGHTING_LOS for grids in the player's line of sight. * Note that lighting is always LIGHTING_LIT for known "interesting" grids * like walls. * - g->is_player is true if the player is on the given grid. * - g->hallucinate is true if the player is hallucinating something "strange" * for this grid - this should pick a random monster to show if the m_idx * is non-zero, and a random object if first_kind is non-zero. * * NOTES: * This is called pretty frequently, whenever a grid on the map display * needs updating, so don't overcomplicate it. * * Terrain is remembered separately from objects and monsters, so can be * shown even when the player can't "see" it. This leads to things like * doors out of the player's view still change from closed to open and so on. * * TODO: * Hallucination is currently disabled (it was a display-level hack before, * and we need it to be a knowledge-level hack). The idea is that objects * may turn into different objects, monsters into different monsters, and * terrain may be objects, monsters, or stay the same. */ void map_info(unsigned y, unsigned x, struct grid_data *g) { struct object *obj; assert(x < (unsigned) cave->width); assert(y < (unsigned) cave->height); /* Default "clear" values, others will be set later where appropriate. */ g->first_kind = NULL; g->trap = NULL; g->multiple_objects = false; g->lighting = LIGHTING_DARK; g->unseen_object = false; g->unseen_money = false; /* Use real feature (remove later) */ g->f_idx = cave->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = lookup_feat(f_info[g->f_idx].mimic); g->in_view = (square_isseen(cave, y, x)) ? true : false; g->is_player = (cave->squares[y][x].mon < 0) ? true : false; g->m_idx = (g->is_player) ? 0 : cave->squares[y][x].mon; g->hallucinate = player->timed[TMD_IMAGE] ? true : false; if (g->in_view) { g->lighting = LIGHTING_LOS; if (!square_isglow(cave, y, x) && OPT(player, view_yellow_light)) g->lighting = LIGHTING_TORCH; /* Remember seen feature */ square_memorize(cave, y, x); } else if (!square_isknown(cave, y, x)) { g->f_idx = FEAT_NONE; } else if (square_isglow(cave, y, x)) { g->lighting = LIGHTING_LIT; } /* Use known feature */ g->f_idx = player->cave->squares[y][x].feat; if (f_info[g->f_idx].mimic) g->f_idx = lookup_feat(f_info[g->f_idx].mimic); /* There is a trap in this square */ if (square_istrap(cave, y, x) && square_isknown(cave, y, x)) { struct trap *trap = cave->squares[y][x].trap; /* Scan the square trap list */ while (trap) { if (trf_has(trap->flags, TRF_TRAP) || trf_has(trap->flags, TRF_RUNE)) { /* Accept the trap - only if not disabled, maybe we need * a special graphic for this */ if (!trap->timeout) { g->trap = trap; break; } } trap = trap->next; } } /* Objects */ for (obj = square_object(player->cave, y, x); obj; obj = obj->next) { if (obj->kind == unknown_gold_kind) { g->unseen_money = true; } else if (obj->kind == unknown_item_kind) { g->unseen_object = true; } else if (ignore_known_item_ok(obj)) { /* Item stays hidden */ } else if (!g->first_kind) { g->first_kind = obj->kind; } else { g->multiple_objects = true; break; } } /* Monsters */ if (g->m_idx > 0) { /* If the monster isn't "visible", make sure we don't list it.*/ struct monster *mon = cave_monster(cave, g->m_idx); if (!monster_is_visible(mon)) g->m_idx = 0; } /* Rare random hallucination on non-outer walls */ if (g->hallucinate && g->m_idx == 0 && g->first_kind == 0) { if (one_in_(128) && (int) g->f_idx != FEAT_PERM) g->m_idx = 1; else if (one_in_(128) && (int) g->f_idx != FEAT_PERM) /* if hallucinating, we just need first_kind to not be NULL */ g->first_kind = k_info; else g->hallucinate = false; } assert((int) g->f_idx <= FEAT_PASS_RUBBLE); if (!g->hallucinate) assert((int)g->m_idx < cave->mon_max); /* All other g fields are 'flags', mostly booleans. */ }
/** * Take one step along the current "run" path * * Called with a real direction to begin a new run, and with zero * to continue a run in progress. */ void run_step(int dir) { /* Start or continue run */ if (dir) { /* Initialize */ run_init(dir); /* Hack -- Set the run counter */ player->upkeep->running = 1000; /* Calculate torch radius */ player->upkeep->update |= (PU_TORCH); } else { /* Continue running */ if (!player->upkeep->running_withpathfind) { /* Update regular running */ if (run_test()) { /* Disturb */ disturb(player, 0); return; } } else if (pf_result_index < 0) { /* Pathfinding, and the path is finished */ disturb(player, 0); player->upkeep->running_withpathfind = false; return; } else { int y = player->py + ddy[pf_result[pf_result_index] - '0']; int x = player->px + ddx[pf_result[pf_result_index] - '0']; if (pf_result_index == 0) { /* Known wall */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } } else if (pf_result_index > 0) { struct object *obj; /* If the player has computed a path that is going to end up * in a wall, we notice this and convert to a normal run. This * allows us to click on unknown areas to explore the map. * * We have to look ahead two, otherwise we don't know which is * the last direction moved and don't initialise the run * properly. */ y = player->py + ddy[pf_result[pf_result_index] - '0']; x = player->px + ddx[pf_result[pf_result_index] - '0']; /* Known wall */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } /* Visible monsters abort running */ if (cave->squares[y][x].mon > 0) { struct monster *mon = square_monster(cave, y, x); /* Visible monster */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } } /* Visible objects abort running */ for (obj = square_object(cave, y, x); obj; obj = obj->next) /* Visible object */ if (obj->known && !ignore_item_ok(obj)) { disturb(player, 0); player->upkeep->running_withpathfind = false; return; } /* Get step after */ y = y + ddy[pf_result[pf_result_index - 1] - '0']; x = x + ddx[pf_result[pf_result_index - 1] - '0']; /* Known wall, so run the direction we were going */ if (square_isknown(cave, y, x) && !square_ispassable(cave, y, x)) { player->upkeep->running_withpathfind = false; run_init(pf_result[pf_result_index] - '0'); } } /* Now actually run the step if we're still going */ run_cur_dir = pf_result[pf_result_index--] - '0'; } } /* Decrease counter if it hasn't been cancelled */ if (player->upkeep->running) player->upkeep->running--; else if (!player->upkeep->running_withpathfind) return; /* Take time */ player->upkeep->energy_use = z_info->move_energy; /* Move the player; running straight into a trap == trying to disarm */ move_player(run_cur_dir, dir ? true : false); /* Prepare the next step */ if (player->upkeep->running) { cmdq_push(CMD_RUN); cmd_set_arg_direction(cmdq_peek(), "direction", 0); } }
/** * Update the current "run" path * * Return true if the running should be stopped */ static bool run_test(void) { int py = player->py; int px = player->px; int prev_dir; int new_dir; int row, col; int i, max, inv; int option, option2; /* No options yet */ option = 0; option2 = 0; /* Where we came from */ prev_dir = run_old_dir; /* Range of newly adjacent grids */ max = (prev_dir & 0x01) + 1; /* Look at every newly adjacent square. */ for (i = -max; i <= max; i++) { struct object *obj; /* New direction */ new_dir = cycle[chome[prev_dir] + i]; /* New location */ row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Visible monsters abort running */ if (cave->squares[row][col].mon > 0) { struct monster *mon = square_monster(cave, row, col); /* Visible monster */ if (mflag_has(mon->mflag, MFLAG_VISIBLE)) return (true); } /* Visible objects abort running */ for (obj = square_object(cave, row, col); obj; obj = obj->next) /* Visible object */ if (obj->known && !ignore_item_ok(obj)) return (true); /* Assume unknown */ inv = true; /* Check memorized grids */ if (square_isknown(cave, row, col)) { bool notice = square_isinteresting(cave, row, col); /* Interesting feature */ if (notice) return (true); /* The grid is "visible" */ inv = false; } /* Analyze unknown grids and floors */ if (inv || square_ispassable(cave, row, col)) { /* Looking for open area */ if (run_open_area) { /* Nothing */ } else if (!option) { /* The first new direction. */ option = new_dir; } else if (option2) { /* Three new directions. Stop running. */ return (true); } else if (option != cycle[chome[prev_dir] + i - 1]) { /* Two non-adjacent new directions. Stop running. */ return (true); } else if (new_dir & 0x01) { /* Two new (adjacent) directions (case 1) */ option2 = new_dir; } else { /* Two new (adjacent) directions (case 2) */ option2 = option; option = new_dir; } } else { /* Obstacle, while looking for open area */ if (run_open_area) { if (i < 0) { /* Break to the right */ run_break_right = true; } else if (i > 0) { /* Break to the left */ run_break_left = true; } } } } /* Look at every soon to be newly adjacent square. */ for (i = -max; i <= max; i++) { /* New direction */ new_dir = cycle[chome[prev_dir] + i]; /* New location */ row = py + ddy[prev_dir] + ddy[new_dir]; col = px + ddx[prev_dir] + ddx[new_dir]; /* HACK: Ugh. Sometimes we come up with illegal bounds. This will * treat the symptom but not the disease. */ if (row >= cave->height || col >= cave->width) continue; if (row < 0 || col < 0) continue; /* Visible monsters abort running */ if (cave->squares[row][col].mon > 0) { struct monster *mon = square_monster(cave, row, col); /* Visible monster */ if (mflag_has(mon->mflag, MFLAG_VISIBLE) && !is_mimicking(mon)) return (true); } } /* Looking for open area */ if (run_open_area) { /* Hack -- look again */ for (i = -max; i < 0; i++) { new_dir = cycle[chome[prev_dir] + i]; row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Unknown grid or non-wall */ /* Was: square_ispassable(cave, row, col) */ if (!square_isknown(cave, row, col) || (square_ispassable(cave, row, col))) { /* Looking to break right */ if (run_break_right) { return (true); } } else { /* Obstacle */ /* Looking to break left */ if (run_break_left) { return (true); } } } /* Hack -- look again */ for (i = max; i > 0; i--) { new_dir = cycle[chome[prev_dir] + i]; row = py + ddy[new_dir]; col = px + ddx[new_dir]; /* Unknown grid or non-wall */ /* Was: square_ispassable(cave, row, col) */ if (!square_isknown(cave, row, col) || (square_ispassable(cave, row, col))) { /* Looking to break left */ if (run_break_left) { return (true); } } else { /* Obstacle */ /* Looking to break right */ if (run_break_right) { return (true); } } } } else { /* Not looking for open area */ /* No options */ if (!option) { return (true); } else if (!option2) { /* One option */ /* Primary option */ run_cur_dir = option; /* No other options */ run_old_dir = option; } else { /* Two options, examining corners */ /* Primary option */ run_cur_dir = option; /* Hack -- allow curving */ run_old_dir = option2; } } /* About to hit a known wall, stop */ if (see_wall(run_cur_dir, py, px)) return (true); /* Failure */ return (false); }
/** * 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; }
/** * 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; }