summaryrefslogtreecommitdiff
path: root/apps/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins')
-rw-r--r--apps/plugins/puzzles/SOURCES.games2
-rw-r--r--apps/plugins/puzzles/untangle.c155
2 files changed, 151 insertions, 6 deletions
diff --git a/apps/plugins/puzzles/SOURCES.games b/apps/plugins/puzzles/SOURCES.games
index 26f74e4005..b16cf0f70d 100644
--- a/apps/plugins/puzzles/SOURCES.games
+++ b/apps/plugins/puzzles/SOURCES.games
@@ -38,7 +38,7 @@ twiddle.c
38/*undead.c*/ 38/*undead.c*/
39/*unequal.c*/ 39/*unequal.c*/
40unruly.c 40unruly.c
41/*untangle.c*/ 41untangle.c
42 42
43/* disabled for now */ 43/* disabled for now */
44/*unfinished/group.c*/ 44/*unfinished/group.c*/
diff --git a/apps/plugins/puzzles/untangle.c b/apps/plugins/puzzles/untangle.c
index 67da03d8c0..839013809b 100644
--- a/apps/plugins/puzzles/untangle.c
+++ b/apps/plugins/puzzles/untangle.c
@@ -39,6 +39,7 @@
39#define CIRCLE_RADIUS 6 39#define CIRCLE_RADIUS 6
40#define DRAG_THRESHOLD (CIRCLE_RADIUS * 2) 40#define DRAG_THRESHOLD (CIRCLE_RADIUS * 2)
41#define PREFERRED_TILESIZE 64 41#define PREFERRED_TILESIZE 64
42#define CURSOR_GRANULARITY 5
42 43
43#define FLASH_TIME 0.30F 44#define FLASH_TIME 0.30F
44#define ANIM_TIME 0.13F 45#define ANIM_TIME 0.13F
@@ -54,6 +55,7 @@ enum {
54 COL_OUTLINE, 55 COL_OUTLINE,
55 COL_POINT, 56 COL_POINT,
56 COL_DRAGPOINT, 57 COL_DRAGPOINT,
58 COL_CURSORPOINT,
57 COL_NEIGHBOUR, 59 COL_NEIGHBOUR,
58 COL_FLASH1, 60 COL_FLASH1,
59 COL_FLASH2, 61 COL_FLASH2,
@@ -1038,6 +1040,11 @@ static char *game_text_format(const game_state *state)
1038 1040
1039struct game_ui { 1041struct game_ui {
1040 int dragpoint; /* point being dragged; -1 if none */ 1042 int dragpoint; /* point being dragged; -1 if none */
1043
1044 int cursorpoint; /* point being highlighted, but
1045 * not dragged by the cursor,
1046 * again -1 if none */
1047
1041 point newpoint; /* where it's been dragged to so far */ 1048 point newpoint; /* where it's been dragged to so far */
1042 int just_dragged; /* reset in game_changed_state */ 1049 int just_dragged; /* reset in game_changed_state */
1043 int just_moved; /* _set_ in game_changed_state */ 1050 int just_moved; /* _set_ in game_changed_state */
@@ -1048,6 +1055,7 @@ static game_ui *new_ui(const game_state *state)
1048{ 1055{
1049 game_ui *ui = snew(game_ui); 1056 game_ui *ui = snew(game_ui);
1050 ui->dragpoint = -1; 1057 ui->dragpoint = -1;
1058 ui->cursorpoint = -1;
1051 ui->just_moved = ui->just_dragged = FALSE; 1059 ui->just_moved = ui->just_dragged = FALSE;
1052 return ui; 1060 return ui;
1053} 1061}
@@ -1076,7 +1084,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
1076 1084
1077struct game_drawstate { 1085struct game_drawstate {
1078 long tilesize; 1086 long tilesize;
1079 int bg, dragpoint; 1087 int bg, dragpoint, cursorpoint;
1080 long *x, *y; 1088 long *x, *y;
1081}; 1089};
1082 1090
@@ -1150,6 +1158,135 @@ static char *interpret_move(const game_state *state, game_ui *ui,
1150 ui->just_dragged = TRUE; 1158 ui->just_dragged = TRUE;
1151 return dupstr(buf); 1159 return dupstr(buf);
1152 } 1160 }
1161 else if(IS_CURSOR_MOVE(button))
1162 {
1163 if(ui->dragpoint < 0)
1164 {
1165 if(ui->cursorpoint < 0)
1166 {
1167 ui->cursorpoint = 0;
1168 return "";
1169 }
1170
1171 /* We're selecting a point here. */
1172 /* Search all the points and find the closest one (2-D) in
1173 * the given direction. */
1174 int i, best;
1175 long bestd;
1176
1177 /*
1178 * Begin drag. We drag the vertex _nearest_ to the pointer,
1179 * just in case one is nearly on top of another and we want
1180 * to drag the latter. However, we drag nothing at all if
1181 * the nearest vertex is outside DRAG_THRESHOLD.
1182 */
1183 best = -1;
1184 bestd = 0;
1185
1186 for (i = 0; i < n; i++) {
1187 if(i == ui->cursorpoint)
1188 continue;
1189
1190 long px = state->pts[i].x * ds->tilesize / state->pts[i].d;
1191 long py = state->pts[i].y * ds->tilesize / state->pts[i].d;
1192 long dx = px - state->pts[ui->cursorpoint].x * ds->tilesize / state->pts[ui->cursorpoint].d;
1193 long dy = py - state->pts[ui->cursorpoint].y * ds->tilesize / state->pts[ui->cursorpoint].d;
1194 long d = dx*dx + dy*dy;
1195
1196 /* Figure out if this point falls into a 90 degree
1197 * range extending from the current point */
1198
1199 float angle = atan2(-dy, dx); /* adjust for raster coordinates */
1200
1201 /* offset to [0..2*PI] */
1202 if(angle < 0)
1203 angle += 2*PI;
1204
1205 int right_direction = FALSE;
1206
1207 if((button == CURSOR_UP && (1*PI/4 <= angle && angle <= 3*PI/4)) ||
1208 (button == CURSOR_LEFT && (3*PI/4 <= angle && angle <= 5*PI/4)) ||
1209 (button == CURSOR_DOWN && (5*PI/4 <= angle && angle <= 7*PI/4)) ||
1210 (button == CURSOR_RIGHT && (angle >= 7*PI/4 || angle <= 1*PI/4)))
1211 right_direction = TRUE;
1212
1213 if ((best == -1 || bestd > d) && right_direction) {
1214 best = i;
1215 bestd = d;
1216 }
1217 }
1218
1219 if(best >= 0)
1220 {
1221 ui->cursorpoint = best;
1222 return "";
1223 }
1224 }
1225 else if(ui->dragpoint >= 0)
1226 {
1227 /* dragging */
1228 switch(button)
1229 {
1230 case CURSOR_UP:
1231 ui->newpoint.y -= ds->tilesize / CURSOR_GRANULARITY;
1232 return "";
1233 case CURSOR_DOWN:
1234 ui->newpoint.y += ds->tilesize / CURSOR_GRANULARITY;
1235 return "";
1236 case CURSOR_LEFT:
1237 ui->newpoint.x -= ds->tilesize / CURSOR_GRANULARITY;
1238 return "";
1239 case CURSOR_RIGHT:
1240 ui->newpoint.x += ds->tilesize / CURSOR_GRANULARITY;
1241 return "";
1242 default:
1243 break;
1244 }
1245 }
1246 }
1247 else if(IS_CURSOR_SELECT(button))
1248 {
1249 if(ui->dragpoint < 0 && ui->cursorpoint >= 0)
1250 {
1251 /* begin drag */
1252 ui->dragpoint = ui->cursorpoint;
1253 ui->cursorpoint = -1;
1254 ui->newpoint.x = state->pts[ui->dragpoint].x * ds->tilesize / state->pts[ui->dragpoint].d;
1255 ui->newpoint.y = state->pts[ui->dragpoint].y * ds->tilesize / state->pts[ui->dragpoint].d;
1256 ui->newpoint.d = ds->tilesize;
1257 return "";
1258 }
1259 else if(ui->dragpoint >= 0)
1260 {
1261 /* end drag */
1262 int p = ui->dragpoint;
1263 char buf[80];
1264
1265 ui->cursorpoint = ui->dragpoint;
1266 ui->dragpoint = -1; /* terminate drag, no matter what */
1267
1268 /*
1269 * First, see if we're within range. The user can cancel a
1270 * drag by dragging the point right off the window.
1271 */
1272 if (ui->newpoint.x < 0 ||
1273 ui->newpoint.x >= (long)state->w*ui->newpoint.d ||
1274 ui->newpoint.y < 0 ||
1275 ui->newpoint.y >= (long)state->h*ui->newpoint.d)
1276 return "";
1277
1278 /*
1279 * We aren't cancelling the drag. Construct a move string
1280 * indicating where this point is going to.
1281 */
1282 sprintf(buf, "P%d:%ld,%ld/%ld", p,
1283 ui->newpoint.x, ui->newpoint.y, ui->newpoint.d);
1284 ui->just_dragged = TRUE;
1285 return dupstr(buf);
1286 }
1287 else if(ui->cursorpoint < 0)
1288 ui->cursorpoint = 0;
1289 }
1153 1290
1154 return NULL; 1291 return NULL;
1155} 1292}
@@ -1241,6 +1378,10 @@ static float *game_colours(frontend *fe, int *ncolours)
1241 ret[COL_DRAGPOINT * 3 + 1] = 1.0F; 1378 ret[COL_DRAGPOINT * 3 + 1] = 1.0F;
1242 ret[COL_DRAGPOINT * 3 + 2] = 1.0F; 1379 ret[COL_DRAGPOINT * 3 + 2] = 1.0F;
1243 1380
1381 ret[COL_CURSORPOINT * 3 + 0] = 0.5F;
1382 ret[COL_CURSORPOINT * 3 + 1] = 0.5F;
1383 ret[COL_CURSORPOINT * 3 + 2] = 0.5F;
1384
1244 ret[COL_NEIGHBOUR * 3 + 0] = 1.0F; 1385 ret[COL_NEIGHBOUR * 3 + 0] = 1.0F;
1245 ret[COL_NEIGHBOUR * 3 + 1] = 0.0F; 1386 ret[COL_NEIGHBOUR * 3 + 1] = 0.0F;
1246 ret[COL_NEIGHBOUR * 3 + 2] = 0.0F; 1387 ret[COL_NEIGHBOUR * 3 + 2] = 0.0F;
@@ -1269,6 +1410,7 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1269 ds->x[i] = ds->y[i] = -1; 1410 ds->x[i] = ds->y[i] = -1;
1270 ds->bg = -1; 1411 ds->bg = -1;
1271 ds->dragpoint = -1; 1412 ds->dragpoint = -1;
1413 ds->cursorpoint = -1;
1272 1414
1273 return ds; 1415 return ds;
1274} 1416}
@@ -1345,7 +1487,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1345 ds->y[i] = y; 1487 ds->y[i] = y;
1346 } 1488 }
1347 1489
1348 if (ds->bg == bg && ds->dragpoint == ui->dragpoint && !points_moved) 1490 if (ds->bg == bg && ds->dragpoint == ui->dragpoint && ds->cursorpoint == ui->cursorpoint && !points_moved)
1349 return; /* nothing to do */ 1491 return; /* nothing to do */
1350 1492
1351 ds->dragpoint = ui->dragpoint; 1493 ds->dragpoint = ui->dragpoint;
@@ -1373,15 +1515,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1373 * When dragging, we should not only vary the colours, but 1515 * When dragging, we should not only vary the colours, but
1374 * leave the point being dragged until last. 1516 * leave the point being dragged until last.
1375 */ 1517 */
1376 for (j = 0; j < 3; j++) { 1518 for (j = 0; j < 4; j++) {
1377 int thisc = (j == 0 ? COL_POINT : 1519 int thisc = (j == 0 ? COL_POINT :
1378 j == 1 ? COL_NEIGHBOUR : COL_DRAGPOINT); 1520 (j == 1 ? COL_NEIGHBOUR :
1521 j == 2 ? COL_CURSORPOINT : COL_DRAGPOINT));
1379 for (i = 0; i < state->params.n; i++) { 1522 for (i = 0; i < state->params.n; i++) {
1380 int c; 1523 int c;
1381 1524
1382 if (ui->dragpoint == i) { 1525 if (ui->dragpoint == i) {
1383 c = COL_DRAGPOINT; 1526 c = COL_DRAGPOINT;
1384 } else if (ui->dragpoint >= 0 && 1527 } else if(ui->cursorpoint == i) {
1528 c = COL_CURSORPOINT;
1529 } else if (ui->dragpoint >= 0 &&
1385 isedge(state->graph->edges, ui->dragpoint, i)) { 1530 isedge(state->graph->edges, ui->dragpoint, i)) {
1386 c = COL_NEIGHBOUR; 1531 c = COL_NEIGHBOUR;
1387 } else { 1532 } else {