diff --git a/cube.c b/cube.c index 2bce1bd..bf24960 100644 --- a/cube.c +++ b/cube.c @@ -11,6 +11,8 @@ #include "puzzles.h" +#define PI 3.14159265358979323846264338327950884197169399 + #define MAXVERTICES 20 #define MAXFACES 20 #define MAXORDER 4 @@ -1002,7 +1004,11 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, +struct game_drawstate { + int ox, oy; /* pixel position of float origin */ +}; + +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, int x, int y, int button) { int direction; @@ -1016,7 +1022,9 @@ static game_state *make_move(game_state *from, game_ui *ui, button = button & (~MOD_MASK | MOD_NUM_KEYPAD); /* - * All moves are made with the cursor keys or numeric keypad. + * Moves can be made with the cursor keys or numeric keypad, or + * alternatively you can left-click and the polyhedron will + * move in the general direction of the mouse pointer. */ if (button == CURSOR_UP || button == (MOD_NUM_KEYPAD | '8')) direction = UP; @@ -1034,7 +1042,69 @@ static game_state *make_move(game_state *from, game_ui *ui, direction = UP_RIGHT; else if (button == (MOD_NUM_KEYPAD | '3')) direction = DOWN_RIGHT; - else + else if (button == LEFT_BUTTON) { + /* + * Find the bearing of the click point from the current + * square's centre. + */ + int cx, cy; + double angle; + + cx = from->squares[from->current].x * GRID_SCALE + ds->ox; + cy = from->squares[from->current].y * GRID_SCALE + ds->oy; + + if (x == cx && y == cy) + return NULL; /* clicked in exact centre! */ + angle = atan2(y - cy, x - cx); + + /* + * There are three possibilities. + * + * - This square is a square, so we choose between UP, + * DOWN, LEFT and RIGHT by dividing the available angle + * at the 45-degree points. + * + * - This square is an up-pointing triangle, so we choose + * between DOWN, LEFT and RIGHT by dividing into + * 120-degree arcs. + * + * - This square is a down-pointing triangle, so we choose + * between UP, LEFT and RIGHT in the inverse manner. + * + * Don't forget that since our y-coordinates increase + * downwards, `angle' is measured _clockwise_ from the + * x-axis, not anticlockwise as most mathematicians would + * instinctively assume. + */ + if (from->squares[from->current].npoints == 4) { + /* Square. */ + if (fabs(angle) > 3*PI/4) + direction = LEFT; + else if (fabs(angle) < PI/4) + direction = RIGHT; + else if (angle > 0) + direction = DOWN; + else + direction = UP; + } else if (from->squares[from->current].directions[UP] == 0) { + /* Up-pointing triangle. */ + if (angle < -PI/2 || angle > 5*PI/6) + direction = LEFT; + else if (angle > PI/6) + direction = DOWN; + else + direction = RIGHT; + } else { + /* Down-pointing triangle. */ + assert(from->squares[from->current].directions[DOWN] == 0); + if (angle > PI/2 || angle < -5*PI/6) + direction = LEFT; + else if (angle < -PI/6) + direction = UP; + else + direction = RIGHT; + } + } else return NULL; /* @@ -1288,10 +1358,6 @@ struct bbox { float l, r, u, d; }; -struct game_drawstate { - int ox, oy; /* pixel position of float origin */ -}; - static void find_bbox_callback(void *ctx, struct grid_square *sq) { struct bbox *bb = (struct bbox *)ctx; diff --git a/fifteen.c b/fifteen.c index e7a41ef..49a3118 100644 --- a/fifteen.c +++ b/fifteen.c @@ -450,9 +450,8 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, - int x, int y, int button) -{ +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { int gx, gy, dx, dy, ux, uy, up, p; game_state *ret; diff --git a/midend.c b/midend.c index de20e14..1def041 100644 --- a/midend.c +++ b/midend.c @@ -325,7 +325,7 @@ static int midend_really_process_key(midend_data *me, int x, int y, int button) } else { game_state *s = me->ourgame->make_move(me->states[me->statepos-1].state, - me->ui, x, y, button); + me->ui, me->drawstate, x, y, button); if (s == me->states[me->statepos-1].state) { /* diff --git a/mines.c b/mines.c index 10ca76c..4006294 100644 --- a/mines.c +++ b/mines.c @@ -2229,8 +2229,8 @@ static void free_ui(game_ui *ui) sfree(ui); } -static game_state *make_move(game_state *from, game_ui *ui, int x, int y, - int button) +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { game_state *ret; int cx, cy; diff --git a/net.c b/net.c index a2204c0..447f4e3 100644 --- a/net.c +++ b/net.c @@ -1798,8 +1798,7 @@ static void free_ui(game_ui *ui) * Process a move. */ static game_state *make_move(game_state *state, game_ui *ui, - int x, int y, int button) -{ + game_drawstate *ds, int x, int y, int button) { game_state *ret, *nullret; int tx, ty, orig; int shift = button & MOD_SHFT, ctrl = button & MOD_CTRL; diff --git a/netslide.c b/netslide.c index 324946e..b81a816 100644 --- a/netslide.c +++ b/netslide.c @@ -1051,7 +1051,7 @@ static void slide_col(game_state *state, int dir, int col) } static game_state *make_move(game_state *state, game_ui *ui, - int x, int y, int button) + game_drawstate *ds, int x, int y, int button) { int cx, cy; int n, dx, dy; diff --git a/nullgame.c b/nullgame.c index 3ec6b75..56694de 100644 --- a/nullgame.c +++ b/nullgame.c @@ -142,8 +142,8 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, int x, int y, - int button) +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { return NULL; } diff --git a/pattern.c b/pattern.c index 419e4aa..4cd3669 100644 --- a/pattern.c +++ b/pattern.c @@ -764,9 +764,8 @@ static void free_ui(game_ui *ui) sfree(ui); } -static game_state *make_move(game_state *from, game_ui *ui, - int x, int y, int button) -{ +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { game_state *ret; button &= ~MOD_MASK; diff --git a/puzzles.h b/puzzles.h index bf441c6..de0f819 100644 --- a/puzzles.h +++ b/puzzles.h @@ -227,8 +227,8 @@ struct game { char *(*text_format)(game_state *state); game_ui *(*new_ui)(game_state *state); void (*free_ui)(game_ui *ui); - game_state *(*make_move)(game_state *from, game_ui *ui, int x, int y, - int button); + game_state *(*make_move)(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button); void (*size)(game_params *params, int *x, int *y); float *(*colours)(frontend *fe, game_state *state, int *ncolours); game_drawstate *(*new_drawstate)(game_state *state); diff --git a/rect.c b/rect.c index c1eaa2c..9e4204d 100644 --- a/rect.c +++ b/rect.c @@ -2178,9 +2178,8 @@ static void ui_draw_rect(game_state *state, game_ui *ui, } } -static game_state *make_move(game_state *from, game_ui *ui, - int x, int y, int button) -{ +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { int xc, yc; int startdrag = FALSE, enddrag = FALSE, active = FALSE; game_state *ret; diff --git a/sixteen.c b/sixteen.c index c6664c1..c202de1 100644 --- a/sixteen.c +++ b/sixteen.c @@ -577,9 +577,8 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, - int x, int y, int button) -{ +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { int cx, cy; int dx, dy, tx, ty, n; game_state *ret; diff --git a/solo.c b/solo.c index 168551c..f3afb02 100644 --- a/solo.c +++ b/solo.c @@ -1821,8 +1821,8 @@ static void free_ui(game_ui *ui) sfree(ui); } -static game_state *make_move(game_state *from, game_ui *ui, int x, int y, - int button) +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { int c = from->c, r = from->r, cr = c*r; int tx, ty; diff --git a/twiddle.c b/twiddle.c index f7bfd4a..273ce8c 100644 --- a/twiddle.c +++ b/twiddle.c @@ -618,8 +618,8 @@ static void free_ui(game_ui *ui) { } -static game_state *make_move(game_state *from, game_ui *ui, int x, int y, - int button) +static game_state *make_move(game_state *from, game_ui *ui, game_drawstate *ds, + int x, int y, int button) { int w = from->w, h = from->h, n = from->n, wh = w*h; game_state *ret;