ref: caee305b47bd93eda98ba40d98de7aa180a470c7
parent: 4a3c26ff14bcfff841f1a014059a357b3263983a
author: Simon Tatham <anakin@pobox.com>
date: Tue May 31 07:43:51 EDT 2005
Mouse-based interface for Cube: you left-click anywhere on the grid and it moves the polyhedron in the general direction of the mouse pointer. (I had this in my initial throwaway Python implementation of this game, but never reimplemented it in this version. It's harder with triangles, but not too much harder.) Since the logical-to-physical coordinate mapping in Cube is dynamically computed, this has involved an interface change which touches all puzzles: make_move() is now passed a pointer to the game_drawstate, which it may of course completely ignore if it wishes. [originally from svn r5877]
--- 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 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 @@
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 @@
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;
/*
@@ -1286,10 +1356,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)
--- a/fifteen.c
+++ b/fifteen.c
@@ -450,9 +450,8 @@
{
}
-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;
--- a/midend.c
+++ b/midend.c
@@ -325,7 +325,7 @@
} 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) {
/*
--- a/mines.c
+++ b/mines.c
@@ -2229,8 +2229,8 @@
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;
--- a/net.c
+++ b/net.c
@@ -1798,8 +1798,7 @@
* 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;
--- a/netslide.c
+++ b/netslide.c
@@ -1051,7 +1051,7 @@
}
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;
--- a/nullgame.c
+++ b/nullgame.c
@@ -142,8 +142,8 @@
{
}
-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;
}
--- a/pattern.c
+++ b/pattern.c
@@ -764,9 +764,8 @@
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;
--- a/puzzles.h
+++ b/puzzles.h
@@ -227,8 +227,8 @@
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);
--- a/rect.c
+++ b/rect.c
@@ -2178,9 +2178,8 @@
}
}
-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;
--- a/sixteen.c
+++ b/sixteen.c
@@ -577,9 +577,8 @@
{
}
-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;
--- a/solo.c
+++ b/solo.c
@@ -1821,8 +1821,8 @@
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;
--- a/twiddle.c
+++ b/twiddle.c
@@ -618,8 +618,8 @@
{
}
-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;