summaryrefslogtreecommitdiffstats
path: root/crawl-ref/source/direct.cc
diff options
context:
space:
mode:
authorharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2007-01-24 22:32:09 +0000
committerharanp <haranp@c06c8d41-db1a-0410-9941-cceddc491573>2007-01-24 22:32:09 +0000
commite3e52a2f0833e09c63b5a3265d96c6d892dacd30 (patch)
tree8314b7f205e5d6884d6c3f5670a76a812abba8d4 /crawl-ref/source/direct.cc
parent09e86f4fcf0c84e610178c9b44afede9677f8abd (diff)
downloadcrawl-ref-e3e52a2f0833e09c63b5a3265d96c6d892dacd30.tar.gz
crawl-ref-e3e52a2f0833e09c63b5a3265d96c6d892dacd30.zip
Stage 1 of the direction() rewrite.
I am committing this even though it isn't complete yet, because: (a) it's good enough now that I like it better than the old version (b) feedback and testing is badly needed. Direction selection has been redone and is no longer modal. You now use the normal arrow or vi keys to move around. If you want to select a direction, as opposed to a specific target square, use the Shift- versions of the movement keys. This might not work with arrow keys on some systems; it's hard for me to check on my own system. Most of the other keys should work, but I'm not sure I've got them all. ';', '+', '-', '.', ' ' (== '.'), 't', 'f', 'p' all work. 'x' (from the main screen) still calls look_around(), not the new direction code, so you have some room to compare. The confirm_* options are now meaningless and will be removed shortly. git-svn-id: https://crawl-ref.svn.sourceforge.net/svnroot/crawl-ref/trunk@880 c06c8d41-db1a-0410-9941-cceddc491573
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)
{