shithub: puzzles

Download patch

ref: 056465cb03a9753020014529531b348e231898ba
parent: 67d55dc5f4c6a59f974a6e68417f6bf9009af48a
author: Simon Tatham <anakin@pobox.com>
date: Mon Jan 11 13:41:29 EST 2010

The 3-D graphics in Towers need a corresponding change on the input
side: instead of locating a mouse click in whichever base grid
square contained the click location, we should check to see if a
tower protrudes on to that location from a neighbouring square. That
way, a click should reliably activate the tower that was actually
drawn under the mouse pointer.

[originally from svn r8826]

--- a/towers.c
+++ b/towers.c
@@ -1148,6 +1148,10 @@
 #define COORD(x) ((x)*TILESIZE + BORDER)
 #define FROMCOORD(x) (((x)+(TILESIZE-BORDER)) / TILESIZE - 1)
 
+/* These always return positive values, though y offsets are actually -ve */
+#define X_3D_DISP(height, w) ((height) * TILESIZE / (8 * (w)))
+#define Y_3D_DISP(height, w) ((height) * TILESIZE / (4 * (w)))
+
 #define FLASH_TIME 0.4F
 
 #define DF_PENCIL_SHIFT 16
@@ -1264,6 +1268,40 @@
     tx = FROMCOORD(x);
     ty = FROMCOORD(y);
 
+    if (ds->three_d) {
+	/*
+	 * In 3D mode, just locating the mouse click in the natural
+	 * square grid may not be sufficient to tell which tower the
+	 * user clicked on. Investigate the _tops_ of the nearby
+	 * towers to see if a click on one grid square was actually
+	 * a click on a tower protruding into that region from
+	 * another.
+	 */
+	int dx, dy;
+	for (dy = 0; dy <= 1; dy++)
+	    for (dx = 0; dx >= -1; dx--) {
+		int cx = tx + dx, cy = ty + dy;
+		if (cx >= 0 && cx < w && cy >= 0 && cy < w) {
+		    int height = state->grid[cy*w+cx];
+		    int bx = COORD(cx), by = COORD(cy);
+		    int ox = bx + X_3D_DISP(height, w);
+		    int oy = by - Y_3D_DISP(height, w);
+		    if (/* on top face? */
+			(x - ox >= 0 && x - ox < TILESIZE &&
+			 y - oy >= 0 && y - oy < TILESIZE) ||
+			/* in triangle between top-left corners? */
+			(ox > bx && x >= bx && x <= ox &&
+			 (by-y) * (ox-bx) <= (by-oy) * (x-bx)) ||
+			/* in triangle between bottom-right corners? */
+			(ox > bx && x >= bx+TILESIZE && x <= ox+TILESIZE &&
+			 (by-y+TILESIZE)*(ox-bx) >= (by-oy)*(x-bx-TILESIZE))) {
+			tx = cx;
+			ty = cy;
+		    }
+		}
+	    }
+    }
+
     if (tx >= 0 && tx < w && ty >= 0 && ty < w) {
         if (button == LEFT_BUTTON) {
 	    if (tx == ui->hx && ty == ui->hy &&
@@ -1495,8 +1533,8 @@
     /* draw tower */
     if (ds->three_d && (tile & DF_PLAYAREA) && (tile & DF_DIGIT_MASK)) {
 	int coords[8];
-	int xoff = (tile & DF_DIGIT_MASK) * TILESIZE / (8 * w);
-	int yoff = (tile & DF_DIGIT_MASK) * TILESIZE / (4 * w);
+	int xoff = X_3D_DISP(tile & DF_DIGIT_MASK, w);
+	int yoff = Y_3D_DISP(tile & DF_DIGIT_MASK, w);
 
 	/* left face of tower */
 	coords[0] = tx;
@@ -1584,10 +1622,10 @@
 	     * to put the pencil marks.
 	     */
 	    /* Start with the whole square, minus space for impinging towers */
-	    pl = tx + TILESIZE/8;
+	    pl = tx + (ds->three_d ? X_3D_DISP(w,w) : 0);
 	    pr = tx + TILESIZE;
 	    pt = ty;
-	    pb = ty + TILESIZE - TILESIZE/4;
+	    pb = ty + TILESIZE - (ds->three_d ? Y_3D_DISP(w,w) : 0);
 
 	    /*
 	     * We arrange our pencil marks in a grid layout, with