/* * Determine if a given grid may be "walked" */ static bool do_cmd_walk_test(int y, int x) { int m_idx = cave->m_idx[y][x]; struct monster *m_ptr = cave_monster(cave, m_idx); /* Allow attack on visible monsters if unafraid */ if (m_idx > 0 && m_ptr->ml && !is_mimicking(m_ptr)) { /* Handle player fear */ if (check_state(p_ptr, OF_AFRAID, p_ptr->state.flags)) { /* Extract monster name (or "it") */ char m_name[80]; monster_desc(m_name, sizeof(m_name), m_ptr, 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 (!(cave->info[y][x] & CAVE_MARK)) return TRUE; /* Require open space */ if (!cave_ispassable(cave, y, x)) { /* Rubble */ if (cave_isrubble(cave, y, x)) msgt(MSG_HITWALL, "There is a pile of rubble in the way!"); /* Door */ else if (cave_iscloseddoor(cave, y, x)) return TRUE; /* Wall */ else msgt(MSG_HITWALL, "There is a wall in the way!"); /* Cancel repeat */ disturb(p_ptr, 0, 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 (!(cave->info[y][x] & (CAVE_MARK))) { msg("You see nothing there."); return FALSE; } if (!cave_iscloseddoor(cave, y, x)) { msgt(MSG_NOTHING_TO_OPEN, "You see nothing there to open."); return FALSE; } /* Okay */ return (TRUE); }
/* * Determine if a given grid may be "bashed" */ static bool do_cmd_bash_test(int y, int x) { /* Must have knowledge */ if (!(cave->info[y][x] & (CAVE_MARK))) { msg("You see nothing there."); return (FALSE); } if (!cave_iscloseddoor(cave, y, x)) { msg("You see nothing there to bash."); return FALSE; } /* Okay */ return (TRUE); }
/* * Manipulate an adjacent grid in some way * * Attack monsters, tunnel through walls, disarm traps, open doors. * * This command must always take energy, to prevent free detection * of invisible monsters. * * The "semantics" of this command must be chosen before the player * is confused, and it must be verified against the new grid. */ void do_cmd_alter_aux(int dir) { int y, x; bool more = FALSE; /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; /* Take a turn */ p_ptr->energy_use = 100; /* Apply confusion */ if (player_confuse_dir(p_ptr, &dir, FALSE)) { /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; } /* Attack monsters */ if (cave->m_idx[y][x] > 0) py_attack(y, x); /* Tunnel through walls and rubble */ else if (cave_isdiggable(cave, y, x)) more = do_cmd_tunnel_aux(y, x); /* Open closed doors */ else if (cave_iscloseddoor(cave, y, x)) more = do_cmd_open_aux(y, x); /* Disarm traps */ else if (cave_isknowntrap(cave, y, x)) more = do_cmd_disarm_aux(y, x); /* Oops */ else msg("You spin around."); /* Cancel repetition unless we can continue */ if (!more) disturb(p_ptr, 0, 0); }
/* * Determine if a given grid may be "disarmed" */ static bool do_cmd_disarm_test(int y, int x) { /* Must have knowledge */ if (!(cave->info[y][x] & (CAVE_MARK))) { msg("You see nothing there."); return FALSE; } /* Look for a closed, unlocked door to lock */ if (cave_iscloseddoor(cave, y, x) && !cave_islockeddoor(cave, y, x)) return TRUE; /* Look for a trap */ if (!cave_isknowntrap(cave, y, x)) { msg("You see nothing there to disarm."); return FALSE; } /* Okay */ return TRUE; }
/* * Determine if a given grid may be "spiked" */ static bool do_cmd_spike_test(int y, int x) { /* Must have knowledge */ if (!(cave->info[y][x] & (CAVE_MARK))) { msg("You see nothing there."); return FALSE; } /* Check if door is closed */ if (!cave_iscloseddoor(cave, y, x)) { msg("You see nothing there to spike."); return FALSE; } /* Check that the door is not fully spiked */ if (!(cave->feat[y][x] < FEAT_DOOR_TAIL)) { msg("You can't use more spikes on this door."); return FALSE; } /* Okay */ return TRUE; }
/* * 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; }
int context_menu_cave(struct cave *c, int y, int x, int adjacent, int mx, int my) { menu_type *m; region r; int selected; char *labels; bool allowed = TRUE; int mode = OPT(rogue_like_commands) ? KEYMAP_MODE_ROGUE : KEYMAP_MODE_ORIG; unsigned char cmdkey; m = menu_dynamic_new(); if (!m) { return 0; } labels = string_make(lower_case); m->selections = labels; /* Looking has different keys, but we don't have a way to look them up (see cmd-process.c). */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? 'l' : 'x'; menu_dynamic_add_label(m, "Look At", cmdkey, MENU_VALUE_LOOK, labels); if (c->m_idx[y][x]) { /* '/' is used for recall in both keymaps. */ menu_dynamic_add_label(m, "Recall Info", '/', MENU_VALUE_RECALL, labels); } ADD_LABEL("Use Item On", CMD_USE_ANY, MN_ROW_VALID); if (player_can_cast(p_ptr, FALSE)) { ADD_LABEL("Cast On", CMD_CAST, MN_ROW_VALID); } if (adjacent) { ADD_LABEL((c->m_idx[y][x]) ? "Attack" : "Alter", CMD_ALTER, MN_ROW_VALID); if (c->o_idx[y][x]) { s16b o_idx = chest_check(y,x, CHEST_ANY); if (o_idx) { object_type *o_ptr = object_byid(o_idx); if (!squelch_item_ok(o_ptr)) { if (object_is_known(o_ptr)) { if (is_locked_chest(o_ptr)) { ADD_LABEL("Disarm Chest", CMD_DISARM, MN_ROW_VALID); ADD_LABEL("Open Chest", CMD_OPEN, MN_ROW_VALID); } else { ADD_LABEL("Open Disarmed Chest", CMD_OPEN, MN_ROW_VALID); } } else { ADD_LABEL("Open Chest", CMD_OPEN, MN_ROW_VALID); } } } } if (cave_istrap(c, y, x)) { ADD_LABEL("Disarm", CMD_DISARM, MN_ROW_VALID); ADD_LABEL("Jump Onto", CMD_JUMP, MN_ROW_VALID); } if (cave_isopendoor(c, y, x)) { ADD_LABEL("Close", CMD_CLOSE, MN_ROW_VALID); } else if (cave_iscloseddoor(c, y, x)) { ADD_LABEL("Open", CMD_OPEN, MN_ROW_VALID); ADD_LABEL("Lock", CMD_DISARM, MN_ROW_VALID); } else if (cave_isdiggable(c, y, x)) { ADD_LABEL("Tunnel", CMD_TUNNEL, MN_ROW_VALID); } ADD_LABEL("Search", CMD_SEARCH, MN_ROW_VALID); ADD_LABEL("Walk Towards", CMD_WALK, MN_ROW_VALID); } else { /* ',' is used for squelch in rogue keymap, so we'll just swap letters. */ cmdkey = (mode == KEYMAP_MODE_ORIG) ? ',' : '.'; menu_dynamic_add_label(m, "Pathfind To", cmdkey, CMD_PATHFIND, labels); ADD_LABEL("Walk Towards", CMD_WALK, MN_ROW_VALID); ADD_LABEL("Run Towards", CMD_RUN, MN_ROW_VALID); } if (player_can_fire(p_ptr, FALSE)) { ADD_LABEL("Fire On", CMD_FIRE, MN_ROW_VALID); } ADD_LABEL("Throw To", CMD_THROW, MN_ROW_VALID); /* work out display region */ r.width = (int)menu_dynamic_longest_entry(m) + 3 + 2; /* +3 for tag, 2 for pad */ if (mx > Term->wid - r.width - 1) { r.col = Term->wid - r.width - 1; } else { r.col = mx + 1; } r.page_rows = m->count; if (my > Term->hgt - r.page_rows - 1) { if (my - r.page_rows - 1 <= 0) { /* menu has too many items, so put in upper right corner */ r.row = 1; r.col = Term->wid - r.width - 1; } else { r.row = Term->hgt - r.page_rows - 1; } } else { r.row = my + 1; } /* Hack -- no flush needed */ msg_flag = FALSE; screen_save(); menu_layout(m, &r); region_erase_bordered(&r); if (p_ptr->timed[TMD_IMAGE]) { prt("(Enter to select command, ESC to cancel) You see something strange:", 0, 0); } else if (c->m_idx[y][x]) { char m_name[80]; monster_type *m_ptr = cave_monster_at(c, y, x); /* Get the monster name ("a kobold") */ monster_desc(m_name, sizeof(m_name), m_ptr, MDESC_IND_VIS); prt(format("(Enter to select command, ESC to cancel) You see %s:", m_name), 0, 0); } else if (c->o_idx[y][x] && !squelch_item_ok(object_byid(c->o_idx[y][x]))) { char o_name[80]; /* Get the single object in the list */ object_type *o_ptr = object_byid(c->o_idx[y][x]); /* Obtain an object description */ object_desc(o_name, sizeof (o_name), o_ptr, ODESC_PREFIX | ODESC_FULL); prt(format("(Enter to select command, ESC to cancel) You see %s:", o_name), 0, 0); } else { /* Feature (apply mimic) */ const char *name = cave_apparent_name(c, p_ptr, y, x); /* Hack -- special introduction for store doors */ if (cave_isshop(cave, y, x)) { prt(format("(Enter to select command, ESC to cancel) You see the entrance to the %s:", name), 0, 0); } else { prt(format("(Enter to select command, ESC to cancel) You see %s %s:", (is_a_vowel(name[0])) ? "an" : "a", name), 0, 0); } } selected = menu_dynamic_select(m); menu_dynamic_free(m); string_free(labels); screen_load(); cmdkey = cmd_lookup_key(selected, mode); /* Check the command to see if it is allowed. */ switch (selected) { case -1: /* User cancelled the menu. */ return 3; case MENU_VALUE_LOOK: case MENU_VALUE_RECALL: case CMD_PATHFIND: allowed = TRUE; break; case CMD_SEARCH: case CMD_ALTER: case CMD_DISARM: case CMD_JUMP: case CMD_CLOSE: case CMD_OPEN: case CMD_TUNNEL: case CMD_WALK: case CMD_RUN: case CMD_CAST: case CMD_FIRE: case CMD_THROW: case CMD_USE_ANY: /* Only check for ^ inscriptions, since we don't have an object selected (if we need one). */ allowed = key_confirm_command(cmdkey); break; default: /* Invalid command; prevent anything from happening. */ bell("Invalid context menu command."); allowed = FALSE; break; } if (!allowed) return 1; /* Perform the command. */ switch (selected) { case MENU_VALUE_LOOK: /* look at the spot */ if (target_set_interactive(TARGET_LOOK, x, y)) { msg("Target Selected."); } break; case MENU_VALUE_RECALL: { /* recall monster Info */ monster_type *m_ptr = cave_monster_at(c, y, x); if (m_ptr) { monster_lore *lore = get_lore(m_ptr->race); lore_show_interactive(m_ptr->race, lore); } } break; case CMD_SEARCH: cmd_insert(selected); break; case CMD_PATHFIND: cmd_insert(selected); cmd_set_arg_point(cmd_get_top(), 0, x, y); break; case CMD_ALTER: case CMD_DISARM: case CMD_JUMP: case CMD_CLOSE: case CMD_OPEN: case CMD_TUNNEL: case CMD_WALK: case CMD_RUN: cmd_insert(selected); cmd_set_arg_direction(cmd_get_top(), 0, coords_to_dir(y,x)); break; case CMD_CAST: if (textui_obj_cast_ret() >= 0) { cmd_set_arg_target(cmd_get_top(), 1, DIR_TARGET); } break; case CMD_FIRE: case CMD_THROW: case CMD_USE_ANY: cmd_insert(selected); cmd_set_arg_target(cmd_get_top(), 1, DIR_TARGET); break; default: break; } return 1; }
/* * Hack -- determine if a given location is "interesting" */ static bool target_set_interactive_accept(int y, int x) { object_type *o_ptr; /* Player grids are always interesting */ if (cave->m_idx[y][x] < 0) return (TRUE); /* Handle hallucination */ if (p_ptr->timed[TMD_IMAGE]) return (FALSE); /* Visible monsters */ if (cave->m_idx[y][x] > 0) { monster_type *m_ptr = cave_monster(cave, cave->m_idx[y][x]); /* Visible monsters */ if (m_ptr->ml && !m_ptr->unaware) return (TRUE); } /* Scan all objects in the grid */ for (o_ptr = get_first_object(y, x); o_ptr; o_ptr = get_next_object(o_ptr)) { /* Memorized object */ if (o_ptr->marked && !squelch_item_ok(o_ptr)) return (TRUE); } /* Interesting memorized features */ if (cave->info[y][x] & (CAVE_MARK)) { /* Notice glyphs */ if (cave->feat[y][x] == FEAT_GLYPH) return (TRUE); /* Notice doors */ if (cave->feat[y][x] == FEAT_OPEN) return (TRUE); if (cave->feat[y][x] == FEAT_BROKEN) return (TRUE); /* Notice stairs */ if (cave->feat[y][x] == FEAT_LESS) return (TRUE); if (cave->feat[y][x] == FEAT_MORE) return (TRUE); /* Notice shops */ if ((cave->feat[y][x] >= FEAT_SHOP_HEAD) && (cave->feat[y][x] <= FEAT_SHOP_TAIL)) return (TRUE); /* Notice traps */ if (cave_isknowntrap(cave, y, x)) return TRUE; /* Notice doors */ if (cave_iscloseddoor(cave, y, x)) return TRUE; /* Notice rubble */ if (cave->feat[y][x] == FEAT_RUBBLE) return (TRUE); /* Notice veins with treasure */ if (cave->feat[y][x] == FEAT_MAGMA_K) return (TRUE); if (cave->feat[y][x] == FEAT_QUARTZ_K) return (TRUE); } /* Nope */ return (FALSE); }
/* * Disarms a trap, or a chest */ void do_cmd_disarm(cmd_code code, cmd_arg args[]) { int y, x, dir; s16b o_idx; bool more = FALSE; dir = args[0].direction; /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; /* Check for chests */ o_idx = chest_check(y, x, CHEST_TRAPPED); /* Verify legality */ if (!o_idx && !do_cmd_disarm_test(y, x)) { /* Cancel repeat */ disturb(p_ptr, 0, 0); return; } /* Take a turn */ p_ptr->energy_use = 100; /* Apply confusion */ if (player_confuse_dir(p_ptr, &dir, FALSE)) { /* Get location */ y = p_ptr->py + ddy[dir]; x = p_ptr->px + ddx[dir]; /* Check for chests */ o_idx = chest_check(y, x, CHEST_TRAPPED); } /* Monster */ if (cave->m_idx[y][x] > 0) { msg("There is a monster in the way!"); py_attack(y, x); } /* Chest */ else if (o_idx) more = do_cmd_disarm_chest(y, x, o_idx); /* Door to lock */ else if ( cave_iscloseddoor(cave, y, x) && !cave_islockeddoor(cave, y, x)) more = do_cmd_lock_door(y, x); /* Disarm trap */ else more = do_cmd_disarm_aux(y, x); /* Cancel repeat unless told not to */ if (!more) disturb(p_ptr, 0, 0); }