summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/direct.cc
diff options
context:
space:
mode:
Diffstat (limited to 'crawl-ref/source/direct.cc')
-rw-r--r--crawl-ref/source/direct.cc521
1 files changed, 335 insertions, 186 deletions
diff --git a/crawl-ref/source/direct.cc b/crawl-ref/source/direct.cc
index 9d703cfa76..fb42388bcc 100644
--- a/crawl-ref/source/direct.cc
+++ b/crawl-ref/source/direct.cc
@@ -78,7 +78,7 @@ static const char ycomp[9] = { 1, 1, 1, 0, 0, 0, -1, -1, -1 };
// [dshaligram] Removed . and 5 from dirchars so it's easier to
// special case them.
static const char dirchars[19] = { "b1j2n3h4bbl6y7k8u9" };
-static const char *aim_prompt = "Aim (move cursor or -/+/=, change mode with CTRL-F, select with . or >)";
+static const char *aim_prompt = "Aim (move cursor or -/+, change mode with CTRL-F, select with . or >)";
static void describe_feature(int mx, int my, bool oos);
static void describe_cell(int mx, int my);
@@ -86,31 +86,76 @@ static void describe_cell(int mx, int my);
static bool find_object( int x, int y, int mode );
static bool find_monster( int x, int y, int mode );
static bool find_feature( int x, int y, int mode );
+
+static char find_square_wrapper( int tx, int ty,
+ FixedVector<char, 2> &mfp, char direction,
+ bool (*targ)(int, int, int),
+ int mode = TARG_ANY,
+ bool wrap = false,
+ int los = LOS_ANY);
+
static char find_square( unsigned char xps, unsigned char yps,
- FixedVector<char, 2> &mfp, char direction,
- bool (*targ)(int, int, int),
- int mode = TARG_ANY,
- bool wrap = false,
- int los = LOS_ANY);
+ FixedVector<char, 2> &mfp, char direction,
+ bool (*targ)(int, int, int),
+ int mode = TARG_ANY,
+ bool wrap = false,
+ int los = LOS_ANY);
+
+static int targeting_cmd_to_compass( command_type command );
static bool is_mapped(int x, int y)
{
return (is_player_mapped(x, y));
}
-static int read_direction_key()
+static command_type read_direction_key()
{
- return unmangle_direction_keys(getchm(KC_TARGETING), KC_TARGETING);
+ flush_input_buffer( FLUSH_BEFORE_COMMAND );
+ const int key = unmangle_direction_keys(getchm(KC_TARGETING),KC_TARGETING);
+ switch ( key )
+ {
+
+ case ESCAPE: return CMD_TARGET_CANCEL;
+ case '?': return CMD_TARGET_DESCRIBE;
+ case ' ': case '.': return CMD_TARGET_SELECT;
+
+ case CONTROL('F'): return CMD_TARGET_CYCLE_TARGET_MODE;
+ case 'p': case 'f': case 't': return CMD_TARGET_PREV_TARGET;
+
+ case '-': return CMD_TARGET_CYCLE_BACK;
+ case '+': return CMD_TARGET_CYCLE_FORWARD;
+ case ';': return CMD_TARGET_OBJ_CYCLE_BACK;
+ case '/': return CMD_TARGET_OBJ_CYCLE_FORWARD;
+
+ case 'b': return CMD_TARGET_DOWN_LEFT;
+ case 'h': return CMD_TARGET_LEFT;
+ case 'j': return CMD_TARGET_DOWN;
+ case 'k': return CMD_TARGET_UP;
+ case 'l': return CMD_TARGET_RIGHT;
+ case 'n': return CMD_TARGET_DOWN_RIGHT;
+ case 'u': return CMD_TARGET_UP_RIGHT;
+ case 'y': return CMD_TARGET_UP_LEFT;
+
+ case 'B': return CMD_TARGET_DIR_DOWN_LEFT;
+ case 'H': return CMD_TARGET_DIR_LEFT;
+ case 'J': return CMD_TARGET_DIR_DOWN;
+ case 'K': return CMD_TARGET_DIR_UP;
+ case 'L': return CMD_TARGET_DIR_RIGHT;
+ case 'N': return CMD_TARGET_DIR_DOWN_RIGHT;
+ case 'U': return CMD_TARGET_DIR_UP_RIGHT;
+ case 'Y': return CMD_TARGET_DIR_UP_LEFT;
+
+ default: return CMD_NO_CMD;
+ }
}
//---------------------------------------------------------------
//
// direction
//
-// input: restricts : DIR_NONE accepts keypad dir or targetting
-// DIR_TARGET must use targetting.
-// DIR_DIR must use keypad direction
-//
+// use restrict == DIR_DIR to allow only a compass direction;
+// == DIR_TARGET to allow only choosing a square;
+// == DIR_NONE to allow either.
//
// outputs: dist structure:
//
@@ -134,216 +179,302 @@ static int read_direction_key()
// targetting mode is handled by look_around()
//---------------------------------------------------------------
-void direction2( struct dist &moves, int restrict, int mode )
+void direction_choose_compass( struct dist& moves )
{
- bool dir_chosen = false;
- bool targ_chosen = false;
+ moves.isValid = true;
+ moves.isTarget = false;
+ moves.isMe = false;
+ moves.isCancel = false;
+ moves.dx = moves.dy = 0;
+
+ do {
+ const command_type key_command = read_direction_key();
+ const int i = targeting_cmd_to_compass(key_command);
+ if ( i != -1 )
+ {
+ moves.dx = Compass[i].x;
+ moves.dy = Compass[i].y;
+ }
+ else if ( key_command == CMD_TARGET_CANCEL )
+ {
+ moves.isCancel = true;
+ moves.isValid = false;
+ }
+ } while ( !moves.isCancel && moves.dx == 0 && moves.dy == 0 );
+
+ return;
+}
+
+static int targeting_cmd_to_compass( command_type command )
+{
+ switch ( command )
+ {
+ case CMD_TARGET_UP: case CMD_TARGET_DIR_UP:
+ return 0;
+ case CMD_TARGET_UP_RIGHT: case CMD_TARGET_DIR_UP_RIGHT:
+ return 1;
+ case CMD_TARGET_RIGHT: case CMD_TARGET_DIR_RIGHT:
+ return 2;
+ case CMD_TARGET_DOWN_RIGHT: case CMD_TARGET_DIR_DOWN_RIGHT:
+ return 3;
+ case CMD_TARGET_DOWN: case CMD_TARGET_DIR_DOWN:
+ return 4;
+ case CMD_TARGET_DOWN_LEFT: case CMD_TARGET_DIR_DOWN_LEFT:
+ return 5;
+ case CMD_TARGET_LEFT: case CMD_TARGET_DIR_LEFT:
+ return 6;
+ case CMD_TARGET_UP_LEFT: case CMD_TARGET_DIR_UP_LEFT:
+ return 7;
+ default:
+ return -1;
+ }
+}
+
+void direction( struct dist &moves, int restricts, int mode )
+{
+ if ( restricts == DIR_DIR )
+ {
+ direction_choose_compass( moves );
+ return;
+ }
+
int dir = 0;
+ FixedVector < char, 2 > objfind_pos;
+ FixedVector < char, 2 > monsfind_pos;
+
// init
moves.isValid = false;
moves.isTarget = false;
moves.isMe = false;
moves.isCancel = false;
moves.dx = moves.dy = 0;
- moves.tx = moves.ty = 0;
+
+ // XXX change this for default target
+ moves.tx = you.x_pos;
+ moves.ty = you.y_pos;
+
+ // XXX Add: ability to cycle between appropriate rays!
// XXX. this is ALWAYS in relation to the player. But a bit of a hack
// nonetheless! --GDL
- gotoxy( VIEW_CX + 1, VIEW_CY );
- int keyin = read_direction_key();
+ mpr(aim_prompt);
- if (keyin == 0)
- return;
-
- if (strchr( dirchars, keyin ) != NULL)
- {
- dir_chosen = true;
- dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
- }
- else if (strchr( dirchars, tolower(keyin) ) != NULL)
- {
- dir_chosen = true;
- dir = (int)(strchr(dirchars, keyin) - dirchars) / 2;
- }
- else
+ while (1)
{
- switch (keyin)
+ // I'm sure there's a perfectly good reason for the +1.
+ gotoxy( grid2viewX(moves.tx) + 1, grid2viewY(moves.ty) );
+
+ command_type key_command = read_direction_key();
+
+ bool need_redraw = true;
+ bool loop_done = false;
+
+ const int old_tx = moves.tx;
+ const int old_ty = moves.ty;
+
+ int i, mid;
+
+ switch ( key_command )
{
- case CONTROL('F'):
- mode = (mode + 1) % TARG_NUM_MODES;
- snprintf( info, INFO_SIZE, "Targeting mode is now: %s",
- (mode == TARG_ANY) ? "any" :
- (mode == TARG_ENEMY) ? "enemies"
- : "friends" );
- mpr( info );
- targ_chosen = true;
- dir = 0;
+ // standard movement
+ case CMD_TARGET_DOWN_LEFT:
+ case CMD_TARGET_DOWN:
+ case CMD_TARGET_DOWN_RIGHT:
+ case CMD_TARGET_LEFT:
+ case CMD_TARGET_RIGHT:
+ case CMD_TARGET_UP_LEFT:
+ case CMD_TARGET_UP:
+ case CMD_TARGET_UP_RIGHT:
+ i = targeting_cmd_to_compass(key_command);
+ moves.tx += Compass[i].x;
+ moves.ty += Compass[i].y;
break;
-
- case '-':
- targ_chosen = true;
- dir = -1;
+
+ case CMD_TARGET_DIR_DOWN_LEFT:
+ case CMD_TARGET_DIR_DOWN:
+ case CMD_TARGET_DIR_DOWN_RIGHT:
+ case CMD_TARGET_DIR_LEFT:
+ case CMD_TARGET_DIR_RIGHT:
+ case CMD_TARGET_DIR_UP_LEFT:
+ case CMD_TARGET_DIR_UP:
+ case CMD_TARGET_DIR_UP_RIGHT:
+ i = targeting_cmd_to_compass(key_command);
+
+ if ( restricts != DIR_TARGET )
+ {
+ // A direction is allowed, and we've selected it.
+ moves.dx = Compass[i].x;
+ moves.dy = Compass[i].y;
+ // Needed for now...eventually shouldn't be necessary
+ moves.tx = you.x_pos + moves.dx;
+ moves.ty = you.y_pos + moves.dy;
+ moves.isValid = true;
+ moves.isTarget = false;
+ loop_done = true;
+ }
+ else
+ {
+ // Direction not allowed, so just move in that direction.
+ // Maybe make this a bigger jump?
+ moves.tx += Compass[i].x;
+ moves.ty += Compass[i].y;
+ }
break;
-
- case '*':
- targ_chosen = true;
- dir = 0;
+
+ case CMD_TARGET_CYCLE_TARGET_MODE:
+ mode = (mode + 1) % TARG_NUM_MODES;
+ mprf( "Targeting mode is now: %s",
+ (mode == TARG_ANY) ? "any" :
+ (mode == TARG_ENEMY) ? "enemies" :
+ "friends" );
+ need_redraw = false;
break;
- case ';':
- targ_chosen = true;
- dir = -3;
- break;
+ case CMD_TARGET_PREV_TARGET:
+ // Do we have a previous target?
+ if (you.prev_targ == MHITNOT || you.prev_targ == MHITYOU)
+ {
+ mpr("You haven't got a previous target.");
+ need_redraw = false;
+ break;
+ }
- case '\'':
- targ_chosen = true;
- dir = -2;
- break;
-
- case '+':
- case '=':
- targ_chosen = true;
- dir = 1;
- break;
+ // we have a valid previous target (maybe)
+ {
+ const monsters *montarget = &menv[you.prev_targ];
+
+ if (!mons_near(montarget) ||
+ !player_monster_visible( montarget ))
+ {
+ mpr("You can't see that creature any more.");
+ need_redraw = false;
+ }
+ else
+ {
+ // We have all the information we need
+ moves.isValid = true;
+ moves.isTarget = true;
+ moves.tx = montarget->x;
+ moves.ty = montarget->y;
+ loop_done = true;
+ }
+ break;
+ }
- case 't':
- case 'p':
- case 'f':
- targ_chosen = true;
- dir = 2;
+ case CMD_TARGET_SELECT: // finalize current choice
+ moves.isValid = true;
+ moves.isTarget = true;
+ loop_done = true;
+ mid = mgrd[moves.tx][moves.ty];
+ if ( mid != NON_MONSTER )
+ you.prev_targ = mid;
break;
-
- case '.':
- case '5':
- dir_chosen = true;
- dir = 4;
+
+ case CMD_TARGET_OBJ_CYCLE_BACK:
+ case CMD_TARGET_OBJ_CYCLE_FORWARD:
+ dir = (key_command == CMD_TARGET_OBJ_CYCLE_BACK) ? -1 : 1;
+ if (find_square_wrapper( moves.tx, moves.ty, objfind_pos, dir,
+ find_object, 0, true,
+ Options.target_los_first
+ ? (dir == 1? LOS_FLIPVH : LOS_FLIPHV)
+ : LOS_ANY))
+ {
+ moves.tx = objfind_pos[0];
+ moves.ty = objfind_pos[1];
+ }
+ else
+ {
+ flush_input_buffer(FLUSH_ON_FAILURE);
+ need_redraw = false;
+ }
+ break;
+
+ case CMD_TARGET_CYCLE_FORWARD:
+ case CMD_TARGET_CYCLE_BACK:
+ dir = (key_command == CMD_TARGET_CYCLE_BACK) ? -1 : 1;
+ if (find_square_wrapper( moves.tx, moves.ty, monsfind_pos, dir,
+ find_monster, mode, Options.target_wrap ))
+ {
+ moves.tx = monsfind_pos[0];
+ moves.ty = monsfind_pos[1];
+ }
+ else
+ {
+ flush_input_buffer(FLUSH_ON_FAILURE);
+ need_redraw = false;
+ }
break;
- case ESCAPE:
+ case CMD_TARGET_CANCEL:
+ loop_done = true;
moves.isCancel = true;
- return;
-
+ break;
+
+ case CMD_TARGET_DESCRIBE:
+ // Maybe we can skip this check...but it can't hurt
+ if (!in_bounds(moves.tx, moves.ty))
+ break;
+ mid = mgrd[moves.tx][moves.ty];
+ if (mid == NON_MONSTER)
+ {
+ // XXX we can put in code for describing terrain here
+ need_redraw = false;
+ break;
+ }
+
+#if (!DEBUG_DIAGNOSTICS)
+ if (!player_monster_visible( &menv[mid] ))
+ {
+ need_redraw = false;
+ break;
+ }
+#endif
+ describe_monsters(menv[mid].type, mid);
+ redraw_screen();
+ mesclr(true);
+ break;
default:
+ need_redraw = false;
break;
}
- }
-
- // at this point, we know exactly the input - validate
- if (!(targ_chosen || dir_chosen) || (targ_chosen && restrict == DIR_DIR))
- {
- mpr("What an unusual direction.");
- return;
- }
-
- // special case: they typed a dir key, but they're in target-only mode
- if (dir_chosen && restrict == DIR_TARGET)
- {
- mpr(aim_prompt);
- look_around( moves, false, keyin, mode );
- return;
- }
-
- if (targ_chosen)
- {
- if (dir < 2)
- {
- mpr(aim_prompt);
- moves.prev_target = dir;
- look_around( moves, false, -1, mode );
- if (moves.prev_target != -1) // -1 means they pressed 'p'
- return;
- }
-
- // chose to aim at previous target. do we have one?
- if (you.prev_targ == MHITNOT || you.prev_targ == MHITYOU)
+
+ if ( loop_done == true )
{
- mpr("You haven't got a target.");
- return;
+ if ( moves.isTarget && !see_grid(moves.tx, moves.ty) )
+ {
+ mpr("Sorry, you can't target what you can't see.");
+ need_redraw = false;
+ }
+ // Ask for confirmation if we're quitting for some odd reason
+ else if ( moves.isValid || moves.isCancel ||
+ yesno("Are you sure you want to fizzle?") )
+ {
+ break;
+ }
}
- // we have a valid previous target (maybe)
- struct monsters *montarget = &menv[you.prev_targ];
-
- if (!mons_near(montarget) || !player_monster_visible( montarget ))
+ // Tried to step out of bounds
+ if ( !in_bounds(moves.tx, moves.ty) )
{
- mpr("You can't see that creature any more.");
- return;
+ moves.tx = old_tx;
+ moves.ty = old_ty;
+ need_redraw = true; // not sure this is necessary
}
- else
+
+ if ( need_redraw )
{
- moves.isValid = true;
- moves.isTarget = true;
- moves.tx = montarget->x;
- moves.ty = montarget->y;
+ // XXX : put in beam redrawing code here
+ mesclr(true);
+ describe_cell(moves.tx, moves.ty);
}
- return;
}
- // at this point, we have a direction, and direction is allowed.
- moves.isValid = true;
- moves.isTarget = false;
- moves.dx = xcomp[dir];
- moves.dy = ycomp[dir];
- if (xcomp[dir] == 0 && ycomp[dir] == 0)
- moves.isMe = true;
-
- // now the tricky bit - extend the target x,y out to map edge.
- int mx, my;
- mx = my = 0;
-
- if (moves.dx > 0)
- mx = (GXM - 1) - you.x_pos;
- if (moves.dx < 0)
- mx = you.x_pos;
-
- if (moves.dy > 0)
- my = (GYM - 1) - you.y_pos;
- if (moves.dy < 0)
- my = you.y_pos;
-
- if (!(mx == 0 || my == 0))
- {
- if (mx < my)
- my = mx;
- else
- mx = my;
- }
- moves.tx = you.x_pos + moves.dx * mx;
- moves.ty = you.y_pos + moves.dy * my;
-}
+ moves.isMe = (moves.tx == you.x_pos && moves.ty == you.y_pos);
-/* safe version of direction */
-void direction( struct dist &moves, int restrict, int mode,
- bool confirm_fizzle )
-{
- while ( 1 )
- {
- direction2( moves, restrict, mode );
- if ( moves.isMe && Options.confirm_self_target == true &&
- mode != TARG_FRIEND )
- {
- if ( yesno("Really target yourself? ", false, 'n') )
- return;
- else
- mpr("Choose a better target.", MSGCH_PROMPT);
- }
- else if ( confirm_fizzle && !moves.isValid && Options.fizzlecheck_on )
- {
- if ( yesno("Really fizzle? ", false, 'n') )
- return;
- else
- mpr("Try again.", MSGCH_PROMPT);
- }
- else
- {
- return;
- }
- }
}
-
// Attempts to describe a square that's not in line-of-sight. If
// there's a stash on the square, announces the top item and number
// of items, otherwise, if there's a stair that's in the travel
@@ -870,10 +1001,13 @@ bool in_los_bounds(int x, int y)
//
//---------------------------------------------------------------
static char find_square( unsigned char xps, unsigned char yps,
- FixedVector<char, 2> &mfp, char direction,
- bool (*find_targ)( int x, int y, int mode ),
- int mode, bool wrap, int los )
+ FixedVector<char, 2> &mfp, char direction,
+ bool (*find_targ)( int x, int y, int mode ),
+ int mode, bool wrap, int los )
{
+ // the day will come when [unsigned] chars will be consigned to
+ // the fires of Gehenna. Not quite yet, though.
+
int temp_xps = xps;
int temp_yps = yps;
char x_change = 0;
@@ -892,8 +1026,8 @@ static char find_square( unsigned char xps, unsigned char yps,
{
// We've been told to flip between visible/hidden, so we
// need to find what we're currently on.
- bool vis = (env.show[xps - 8][yps]
- || (xps == VIEW_CX && yps == VIEW_CY));
+ const bool vis = (env.show[xps - 8][yps]
+ || (xps == VIEW_CX && yps == VIEW_CY));
if (wrap && (vis != (los == LOS_FLIPVH)) == (direction == 1))
{
@@ -1074,6 +1208,19 @@ static char find_square( unsigned char xps, unsigned char yps,
next_los(direction, los, wrap)));
}
+// XXX Unbelievably hacky. And to think that my goal was to clean up the code.
+static char find_square_wrapper( int tx, int ty,
+ FixedVector<char, 2> &mfp, char direction,
+ bool (*find_targ)( int x, int y, int mode ),
+ int mode, bool wrap, int los )
+{
+ unsigned char r = find_square(grid2viewX(tx), grid2viewY(ty),
+ mfp, direction, find_targ, mode, wrap, los);
+ mfp[0] = view2gridX(mfp[0]);
+ mfp[1] = view2gridY(mfp[1]);
+ return r;
+}
+
static void describe_feature(int mx, int my, bool oos)
{
if (oos && !is_terrain_seen(mx, my))
@@ -1088,6 +1235,8 @@ static void describe_feature(int mx, int my, bool oos)
}
}
+
+
// Returns a vector of features matching the given pattern.
std::vector<dungeon_feature_type> features_by_desc(const text_pattern &pattern)
{