summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/net.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/net.c')
-rw-r--r--apps/plugins/puzzles/src/net.c231
1 files changed, 148 insertions, 83 deletions
diff --git a/apps/plugins/puzzles/src/net.c b/apps/plugins/puzzles/src/net.c
index d3032b6fe2..3200253ef9 100644
--- a/apps/plugins/puzzles/src/net.c
+++ b/apps/plugins/puzzles/src/net.c
@@ -7,7 +7,12 @@
7#include <string.h> 7#include <string.h>
8#include <assert.h> 8#include <assert.h>
9#include <ctype.h> 9#include <ctype.h>
10#include <math.h> 10#include <limits.h>
11#ifdef NO_TGMATH_H
12# include <math.h>
13#else
14# include <tgmath.h>
15#endif
11 16
12#include "puzzles.h" 17#include "puzzles.h"
13#include "tree234.h" 18#include "tree234.h"
@@ -249,10 +254,7 @@ static char *encode_params(const game_params *params, bool full)
249 if (params->wrapping) 254 if (params->wrapping)
250 ret[len++] = 'w'; 255 ret[len++] = 'w';
251 if (full && params->barrier_probability) 256 if (full && params->barrier_probability)
252 { 257 len += sprintf(ret+len, "b%g", params->barrier_probability);
253 len += sprintf(ret+len, "b");
254 len += ftoa(ret + len, params->barrier_probability);
255 }
256 if (full && !params->unique) 258 if (full && !params->unique)
257 ret[len++] = 'a'; 259 ret[len++] = 'a';
258 assert(len < lenof(ret)); 260 assert(len < lenof(ret));
@@ -284,7 +286,7 @@ static config_item *game_configure(const game_params *params)
284 286
285 ret[3].name = "Barrier probability"; 287 ret[3].name = "Barrier probability";
286 ret[3].type = C_STRING; 288 ret[3].type = C_STRING;
287 ftoa(buf, params->barrier_probability); 289 sprintf(buf, "%g", params->barrier_probability);
288 ret[3].u.string.sval = dupstr(buf); 290 ret[3].u.string.sval = dupstr(buf);
289 291
290 ret[4].name = "Ensure unique solution"; 292 ret[4].name = "Ensure unique solution";
@@ -316,6 +318,8 @@ static const char *validate_params(const game_params *params, bool full)
316 return "Width and height must both be greater than zero"; 318 return "Width and height must both be greater than zero";
317 if (params->width <= 1 && params->height <= 1) 319 if (params->width <= 1 && params->height <= 1)
318 return "At least one of width and height must be greater than one"; 320 return "At least one of width and height must be greater than one";
321 if (params->width > INT_MAX / params->height)
322 return "Width times height must not be unreasonably large";
319 if (params->barrier_probability < 0) 323 if (params->barrier_probability < 0)
320 return "Barrier probability may not be negative"; 324 return "Barrier probability may not be negative";
321 if (params->barrier_probability > 1) 325 if (params->barrier_probability > 1)
@@ -458,7 +462,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
458 unsigned char *tilestate; 462 unsigned char *tilestate;
459 unsigned char *edgestate; 463 unsigned char *edgestate;
460 int *deadends; 464 int *deadends;
461 int *equivalence; 465 DSF *equivalence;
462 struct todo *todo; 466 struct todo *todo;
463 int i, j, x, y; 467 int i, j, x, y;
464 int area; 468 int area;
@@ -543,7 +547,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
543 * classes) by finding the representative of each tile and 547 * classes) by finding the representative of each tile and
544 * setting equivalence[one]=the_other. 548 * setting equivalence[one]=the_other.
545 */ 549 */
546 equivalence = snew_dsf(w * h); 550 equivalence = dsf_new(w * h);
547 551
548 /* 552 /*
549 * On a non-wrapping grid, we instantly know that all the edges 553 * On a non-wrapping grid, we instantly know that all the edges
@@ -828,7 +832,7 @@ static int net_solver(int w, int h, unsigned char *tiles,
828 sfree(tilestate); 832 sfree(tilestate);
829 sfree(edgestate); 833 sfree(edgestate);
830 sfree(deadends); 834 sfree(deadends);
831 sfree(equivalence); 835 dsf_free(equivalence);
832 836
833 return j; 837 return j;
834} 838}
@@ -1131,7 +1135,8 @@ static void perturb(int w, int h, unsigned char *tiles, bool wrapping,
1131 1135
1132static int *compute_loops_inner(int w, int h, bool wrapping, 1136static int *compute_loops_inner(int w, int h, bool wrapping,
1133 const unsigned char *tiles, 1137 const unsigned char *tiles,
1134 const unsigned char *barriers); 1138 const unsigned char *barriers,
1139 bool include_unlocked_squares);
1135 1140
1136static char *new_game_desc(const game_params *params, random_state *rs, 1141static char *new_game_desc(const game_params *params, random_state *rs,
1137 char **aux, bool interactive) 1142 char **aux, bool interactive)
@@ -1460,7 +1465,8 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1460 */ 1465 */
1461 prev_loopsquares = w*h+1; 1466 prev_loopsquares = w*h+1;
1462 while (1) { 1467 while (1) {
1463 loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL); 1468 loops = compute_loops_inner(w, h, params->wrapping, tiles, NULL,
1469 true);
1464 this_loopsquares = 0; 1470 this_loopsquares = 0;
1465 for (i = 0; i < w*h; i++) { 1471 for (i = 0; i < w*h; i++) {
1466 if (loops[i]) { 1472 if (loops[i]) {
@@ -1848,16 +1854,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
1848 return ret; 1854 return ret;
1849} 1855}
1850 1856
1851static bool game_can_format_as_text_now(const game_params *params)
1852{
1853 return true;
1854}
1855
1856static char *game_text_format(const game_state *state)
1857{
1858 return NULL;
1859}
1860
1861/* ---------------------------------------------------------------------- 1857/* ----------------------------------------------------------------------
1862 * Utility routine. 1858 * Utility routine.
1863 */ 1859 */
@@ -1878,6 +1874,8 @@ static unsigned char *compute_active(const game_state *state, int cx, int cy)
1878 active = snewn(state->width * state->height, unsigned char); 1874 active = snewn(state->width * state->height, unsigned char);
1879 memset(active, 0, state->width * state->height); 1875 memset(active, 0, state->width * state->height);
1880 1876
1877 assert(0 <= cx && cx < state->width);
1878 assert(0 <= cy && cy < state->height);
1881 /* 1879 /*
1882 * We only store (x,y) pairs in todo, but it's easier to reuse 1880 * We only store (x,y) pairs in todo, but it's easier to reuse
1883 * xyd_cmp and just store direction 0 every time. 1881 * xyd_cmp and just store direction 0 every time.
@@ -1923,6 +1921,7 @@ struct net_neighbour_ctx {
1923 int w, h; 1921 int w, h;
1924 const unsigned char *tiles, *barriers; 1922 const unsigned char *tiles, *barriers;
1925 int i, n, neighbours[4]; 1923 int i, n, neighbours[4];
1924 bool include_unlocked_squares;
1926}; 1925};
1927static int net_neighbour(int vertex, void *vctx) 1926static int net_neighbour(int vertex, void *vctx)
1928{ 1927{
@@ -1943,6 +1942,9 @@ static int net_neighbour(int vertex, void *vctx)
1943 continue; 1942 continue;
1944 OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h); 1943 OFFSETWH(x1, y1, x, y, dir, ctx->w, ctx->h);
1945 v1 = y1 * ctx->w + x1; 1944 v1 = y1 * ctx->w + x1;
1945 if (!ctx->include_unlocked_squares &&
1946 !(tile & ctx->tiles[v1] & LOCKED))
1947 continue;
1946 if (ctx->tiles[v1] & F(dir)) 1948 if (ctx->tiles[v1] & F(dir))
1947 ctx->neighbours[ctx->n++] = v1; 1949 ctx->neighbours[ctx->n++] = v1;
1948 } 1950 }
@@ -1956,32 +1958,39 @@ static int net_neighbour(int vertex, void *vctx)
1956 1958
1957static int *compute_loops_inner(int w, int h, bool wrapping, 1959static int *compute_loops_inner(int w, int h, bool wrapping,
1958 const unsigned char *tiles, 1960 const unsigned char *tiles,
1959 const unsigned char *barriers) 1961 const unsigned char *barriers,
1962 bool include_unlocked_squares)
1960{ 1963{
1961 struct net_neighbour_ctx ctx; 1964 struct net_neighbour_ctx ctx;
1962 struct findloopstate *fls; 1965 struct findloopstate *fls;
1963 int *loops; 1966 int *loops;
1964 int x, y; 1967 int x, y, v;
1965 1968
1966 fls = findloop_new_state(w*h); 1969 fls = findloop_new_state(w*h);
1967 ctx.w = w; 1970 ctx.w = w;
1968 ctx.h = h; 1971 ctx.h = h;
1969 ctx.tiles = tiles; 1972 ctx.tiles = tiles;
1970 ctx.barriers = barriers; 1973 ctx.barriers = barriers;
1974 ctx.include_unlocked_squares = include_unlocked_squares;
1971 findloop_run(fls, w*h, net_neighbour, &ctx); 1975 findloop_run(fls, w*h, net_neighbour, &ctx);
1972 1976
1973 loops = snewn(w*h, int); 1977 loops = snewn(w*h, int);
1974 1978
1975 for (y = 0; y < h; y++) { 1979 for (y = 0; y < h; y++) {
1976 for (x = 0; x < w; x++) { 1980 for (x = 0; x < w; x++) {
1977 int x1, y1, dir; 1981 int x1, y1, v1, dir;
1978 int flags = 0; 1982 int flags = 0;
1979 1983
1984 v = y * w + x;
1980 for (dir = 1; dir < 0x10; dir <<= 1) { 1985 for (dir = 1; dir < 0x10; dir <<= 1) {
1981 if ((tiles[y*w+x] & dir) && 1986 if ((tiles[v] & dir) &&
1982 !(barriers && (barriers[y*w+x] & dir))) { 1987 !(barriers && (barriers[y*w+x] & dir))) {
1983 OFFSETWH(x1, y1, x, y, dir, w, h); 1988 OFFSETWH(x1, y1, x, y, dir, w, h);
1984 if ((tiles[y1*w+x1] & F(dir)) && 1989 v1 = y1 * w + x1;
1990 if (!include_unlocked_squares &&
1991 !(tiles[v] & tiles[v1] & LOCKED))
1992 continue;
1993 if ((tiles[v1] & F(dir)) &&
1985 findloop_is_loop_edge(fls, y*w+x, y1*w+x1)) 1994 findloop_is_loop_edge(fls, y*w+x, y1*w+x1))
1986 flags |= ERR(dir); 1995 flags |= ERR(dir);
1987 } 1996 }
@@ -1994,10 +2003,12 @@ static int *compute_loops_inner(int w, int h, bool wrapping,
1994 return loops; 2003 return loops;
1995} 2004}
1996 2005
1997static int *compute_loops(const game_state *state) 2006static int *compute_loops(const game_state *state,
2007 bool include_unlocked_squares)
1998{ 2008{
1999 return compute_loops_inner(state->width, state->height, state->wrapping, 2009 return compute_loops_inner(state->width, state->height, state->wrapping,
2000 state->tiles, state->imm->barriers); 2010 state->tiles, state->imm->barriers,
2011 include_unlocked_squares);
2001} 2012}
2002 2013
2003struct game_ui { 2014struct game_ui {
@@ -2010,6 +2021,8 @@ struct game_ui {
2010 int dragtilex, dragtiley, dragstartx, dragstarty; 2021 int dragtilex, dragtiley, dragstartx, dragstarty;
2011 bool dragged; 2022 bool dragged;
2012#endif 2023#endif
2024
2025 bool unlocked_loops;
2013}; 2026};
2014 2027
2015static game_ui *new_ui(const game_state *state) 2028static game_ui *new_ui(const game_state *state)
@@ -2017,20 +2030,31 @@ static game_ui *new_ui(const game_state *state)
2017 void *seed; 2030 void *seed;
2018 int seedsize; 2031 int seedsize;
2019 game_ui *ui = snew(game_ui); 2032 game_ui *ui = snew(game_ui);
2020 ui->org_x = ui->org_y = 0; 2033
2021 ui->cur_x = ui->cx = state->width / 2; 2034 ui->unlocked_loops = true;
2022 ui->cur_y = ui->cy = state->height / 2; 2035
2023 ui->cur_visible = false; 2036 if (state) {
2024 get_random_seed(&seed, &seedsize); 2037 ui->org_x = ui->org_y = 0;
2025 ui->rs = random_new(seed, seedsize); 2038 ui->cur_x = ui->cx = state->width / 2;
2026 sfree(seed); 2039 ui->cur_y = ui->cy = state->height / 2;
2040 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2041 get_random_seed(&seed, &seedsize);
2042 ui->rs = random_new(seed, seedsize);
2043 sfree(seed);
2044#ifdef USE_DRAGGING
2045 ui->dragstartx = ui->dragstarty = ui->dragtilex = ui->dragtiley = -1;
2046#endif
2047 } else {
2048 ui->rs = NULL;
2049 }
2027 2050
2028 return ui; 2051 return ui;
2029} 2052}
2030 2053
2031static void free_ui(game_ui *ui) 2054static void free_ui(game_ui *ui)
2032{ 2055{
2033 random_free(ui->rs); 2056 if (ui->rs)
2057 random_free(ui->rs);
2034 sfree(ui); 2058 sfree(ui);
2035} 2059}
2036 2060
@@ -2045,10 +2069,45 @@ static char *encode_ui(const game_ui *ui)
2045 return dupstr(buf); 2069 return dupstr(buf);
2046} 2070}
2047 2071
2048static void decode_ui(game_ui *ui, const char *encoding) 2072static void decode_ui(game_ui *ui, const char *encoding,
2073 const game_state *state)
2049{ 2074{
2050 sscanf(encoding, "O%d,%d;C%d,%d", 2075 int org_x, org_y, cx, cy;
2051 &ui->org_x, &ui->org_y, &ui->cx, &ui->cy); 2076
2077 if (sscanf(encoding, "O%d,%d;C%d,%d", &org_x, &org_y, &cx, &cy) == 4) {
2078 if (0 <= org_x && org_x < state->width &&
2079 0 <= org_y && org_y < state->height) {
2080 ui->org_x = org_x;
2081 ui->org_y = org_y;
2082 }
2083 if (0 <= cx && cx < state->width &&
2084 0 <= cy && cy < state->height) {
2085 ui->cx = cx;
2086 ui->cy = cy;
2087 }
2088 }
2089}
2090
2091static config_item *get_prefs(game_ui *ui)
2092{
2093 config_item *ret;
2094
2095 ret = snewn(2, config_item);
2096
2097 ret[0].name = "Highlight loops involving unlocked squares";
2098 ret[0].kw = "unlocked-loops";
2099 ret[0].type = C_BOOLEAN;
2100 ret[0].u.boolean.bval = ui->unlocked_loops;
2101
2102 ret[1].name = NULL;
2103 ret[1].type = C_END;
2104
2105 return ret;
2106}
2107
2108static void set_prefs(game_ui *ui, const config_item *cfg)
2109{
2110 ui->unlocked_loops = cfg[0].u.boolean.bval;
2052} 2111}
2053 2112
2054static void game_changed_state(game_ui *ui, const game_state *oldstate, 2113static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2056,8 +2115,19 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
2056{ 2115{
2057} 2116}
2058 2117
2118static const char *current_key_label(const game_ui *ui,
2119 const game_state *state, int button)
2120{
2121 if (tile(state, ui->cur_x, ui->cur_y) & LOCKED) {
2122 if (button == CURSOR_SELECT2) return "Unlock";
2123 } else {
2124 if (button == CURSOR_SELECT) return "Rotate";
2125 if (button == CURSOR_SELECT2) return "Lock";
2126 }
2127 return "";
2128}
2129
2059struct game_drawstate { 2130struct game_drawstate {
2060 bool started;
2061 int width, height; 2131 int width, height;
2062 int tilesize; 2132 int tilesize;
2063 unsigned long *visible, *to_draw; 2133 unsigned long *visible, *to_draw;
@@ -2078,7 +2148,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2078 MOVE_ORIGIN, MOVE_SOURCE, MOVE_ORIGIN_AND_SOURCE, MOVE_CURSOR 2148 MOVE_ORIGIN, MOVE_SOURCE, MOVE_ORIGIN_AND_SOURCE, MOVE_CURSOR
2079 } action; 2149 } action;
2080 2150
2081 button &= ~MOD_MASK; 2151 button = STRIP_BUTTON_MODIFIERS(button);
2082 nullret = NULL; 2152 nullret = NULL;
2083 action = NONE; 2153 action = NONE;
2084 2154
@@ -2094,7 +2164,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2094 2164
2095 if (ui->cur_visible) { 2165 if (ui->cur_visible) {
2096 ui->cur_visible = false; 2166 ui->cur_visible = false;
2097 nullret = UI_UPDATE; 2167 nullret = MOVE_UI_UPDATE;
2098 } 2168 }
2099 2169
2100 /* 2170 /*
@@ -2102,12 +2172,22 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2102 */ 2172 */
2103 x -= WINDOW_OFFSET + LINE_THICK; 2173 x -= WINDOW_OFFSET + LINE_THICK;
2104 y -= WINDOW_OFFSET + LINE_THICK; 2174 y -= WINDOW_OFFSET + LINE_THICK;
2105 if (x < 0 || y < 0)
2106 return nullret;
2107 tx = x / TILE_SIZE; 2175 tx = x / TILE_SIZE;
2108 ty = y / TILE_SIZE; 2176 ty = y / TILE_SIZE;
2109 if (tx >= state->width || ty >= state->height) 2177 if (x < 0 || y < 0 || tx >= state->width || ty >= state->height) {
2178#ifdef USE_DRAGGING
2179 if (IS_MOUSE_DOWN(button)) {
2180 ui->dragstartx = ui->dragstarty = ui->dragtilex = ui->dragtiley = -1;
2181 return nullret;
2182 }
2183 /*
2184 * else: Despite the mouse moving off the grid, let drags and releases
2185 * continue to manipulate the tile they started from.
2186 */
2187#else
2110 return nullret; 2188 return nullret;
2189#endif
2190 }
2111 /* Transform from physical to game coords */ 2191 /* Transform from physical to game coords */
2112 tx = (tx + ui->org_x) % state->width; 2192 tx = (tx + ui->org_x) % state->width;
2113 ty = (ty + ui->org_y) % state->height; 2193 ty = (ty + ui->org_y) % state->height;
@@ -2145,6 +2225,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2145 || button == RIGHT_DRAG 2225 || button == RIGHT_DRAG
2146#endif 2226#endif
2147 ) { 2227 ) {
2228 if (ui->dragtilex < 0)
2229 return nullret;
2230
2148 /* 2231 /*
2149 * Find the new drag point and see if it necessitates a 2232 * Find the new drag point and see if it necessitates a
2150 * rotation. 2233 * rotation.
@@ -2198,7 +2281,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2198 || button == RIGHT_RELEASE 2281 || button == RIGHT_RELEASE
2199#endif 2282#endif
2200 ) { 2283 ) {
2201 if (!ui->dragged) { 2284 if (!ui->dragged && ui->dragtilex >= 0) {
2202 /* 2285 /*
2203 * There was a click but no perceptible drag: 2286 * There was a click but no perceptible drag:
2204 * revert to single-click behaviour. 2287 * revert to single-click behaviour.
@@ -2334,7 +2417,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2334 OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state); 2417 OFFSET(ui->cur_x, ui->cur_y, ui->cur_x, ui->cur_y, dir, state);
2335 ui->cur_visible = true; 2418 ui->cur_visible = true;
2336 } 2419 }
2337 return UI_UPDATE; 2420 return MOVE_UI_UPDATE;
2338 } else { 2421 } else {
2339 return NULL; 2422 return NULL;
2340 } 2423 }
@@ -2444,7 +2527,6 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2444 game_drawstate *ds = snew(game_drawstate); 2527 game_drawstate *ds = snew(game_drawstate);
2445 int i, ncells; 2528 int i, ncells;
2446 2529
2447 ds->started = false;
2448 ds->width = state->width; 2530 ds->width = state->width;
2449 ds->height = state->height; 2531 ds->height = state->height;
2450 ncells = (state->width+2) * (state->height+2); 2532 ncells = (state->width+2) * (state->height+2);
@@ -2464,11 +2546,12 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
2464static void game_free_drawstate(drawing *dr, game_drawstate *ds) 2546static void game_free_drawstate(drawing *dr, game_drawstate *ds)
2465{ 2547{
2466 sfree(ds->visible); 2548 sfree(ds->visible);
2549 sfree(ds->to_draw);
2467 sfree(ds); 2550 sfree(ds);
2468} 2551}
2469 2552
2470static void game_compute_size(const game_params *params, int tilesize, 2553static void game_compute_size(const game_params *params, int tilesize,
2471 int *x, int *y) 2554 const game_ui *ui, int *x, int *y)
2472{ 2555{
2473 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2556 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2474 struct { int tilesize; } ads, *ds = &ads; 2557 struct { int tilesize; } ads, *ds = &ads;
@@ -2605,8 +2688,8 @@ static void draw_wires(drawing *dr, int cx, int cy, int radius,
2605 2688
2606 for (i = 0; i < npoints; i++) { 2689 for (i = 0; i < npoints; i++) {
2607 rotated_coords(&xf, &yf, matrix, cx, cy, fpoints[2*i], fpoints[2*i+1]); 2690 rotated_coords(&xf, &yf, matrix, cx, cy, fpoints[2*i], fpoints[2*i+1]);
2608 points[2*i] = 0.5 + xf; 2691 points[2*i] = 0.5F + xf;
2609 points[2*i+1] = 0.5 + yf; 2692 points[2*i+1] = 0.5F + yf;
2610 } 2693 }
2611 2694
2612 draw_polygon(dr, points, npoints, colour, colour); 2695 draw_polygon(dr, points, npoints, colour, colour);
@@ -2746,8 +2829,8 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y,
2746 * rotated by an arbitrary angle about that centre point. 2829 * rotated by an arbitrary angle about that centre point.
2747 */ 2830 */
2748 if (tile & TILE_ROTATING) { 2831 if (tile & TILE_ROTATING) {
2749 matrix[0] = (float)cos(angle * PI / 180.0); 2832 matrix[0] = (float)cos(angle * (float)PI / 180.0F);
2750 matrix[2] = (float)sin(angle * PI / 180.0); 2833 matrix[2] = (float)sin(angle * (float)PI / 180.0F);
2751 } else { 2834 } else {
2752 matrix[0] = 1.0F; 2835 matrix[0] = 1.0F;
2753 matrix[2] = 0.0F; 2836 matrix[2] = 0.0F;
@@ -2786,8 +2869,8 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int x, int y,
2786 float x, y; 2869 float x, y;
2787 rotated_coords(&x, &y, matrix, cx, cy, 2870 rotated_coords(&x, &y, matrix, cx, cy,
2788 boxr * points[i], boxr * points[i+1]); 2871 boxr * points[i], boxr * points[i+1]);
2789 points[i] = x + 0.5; 2872 points[i] = x + 0.5F;
2790 points[i+1] = y + 0.5; 2873 points[i+1] = y + 0.5F;
2791 } 2874 }
2792 2875
2793 draw_polygon(dr, points, 4, col, COL_WIRE); 2876 draw_polygon(dr, points, 4, col, COL_WIRE);
@@ -2841,23 +2924,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2841 int *loops; 2924 int *loops;
2842 float angle = 0.0; 2925 float angle = 0.0;
2843 2926
2844 /*
2845 * Clear the screen on our first call.
2846 */
2847 if (!ds->started) {
2848 int w, h;
2849 game_params params;
2850
2851 ds->started = true;
2852
2853 params.width = ds->width;
2854 params.height = ds->height;
2855 game_compute_size(&params, TILE_SIZE, &w, &h);
2856
2857 draw_rect(dr, 0, 0, w, h, COL_BACKGROUND);
2858 draw_update(dr, 0, 0, w, h);
2859 }
2860
2861 tx = ty = -1; 2927 tx = ty = -1;
2862 last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir : 2928 last_rotate_dir = dir==-1 ? oldstate->last_rotate_dir :
2863 state->last_rotate_dir; 2929 state->last_rotate_dir;
@@ -2888,7 +2954,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2888 * of barriers. 2954 * of barriers.
2889 */ 2955 */
2890 active = compute_active(state, ui->cx, ui->cy); 2956 active = compute_active(state, ui->cx, ui->cy);
2891 loops = compute_loops(state); 2957 loops = compute_loops(state, ui->unlocked_loops);
2892 2958
2893 for (dy = -1; dy < ds->height+1; dy++) { 2959 for (dy = -1; dy < ds->height+1; dy++) {
2894 for (dx = -1; dx < ds->width+1; dx++) { 2960 for (dx = -1; dx < ds->width+1; dx++) {
@@ -3109,19 +3175,15 @@ static int game_status(const game_state *state)
3109 return state->completed ? +1 : 0; 3175 return state->completed ? +1 : 0;
3110} 3176}
3111 3177
3112static bool game_timing_state(const game_state *state, game_ui *ui) 3178static void game_print_size(const game_params *params, const game_ui *ui,
3113{ 3179 float *x, float *y)
3114 return true;
3115}
3116
3117static void game_print_size(const game_params *params, float *x, float *y)
3118{ 3180{
3119 int pw, ph; 3181 int pw, ph;
3120 3182
3121 /* 3183 /*
3122 * I'll use 8mm squares by default. 3184 * I'll use 8mm squares by default.
3123 */ 3185 */
3124 game_compute_size(params, 800, &pw, &ph); 3186 game_compute_size(params, 800, ui, &pw, &ph);
3125 *x = pw / 100.0F; 3187 *x = pw / 100.0F;
3126 *y = ph / 100.0F; 3188 *y = ph / 100.0F;
3127} 3189}
@@ -3172,7 +3234,8 @@ static void draw_diagram(drawing *dr, game_drawstate *ds, int x, int y,
3172 } 3234 }
3173} 3235}
3174 3236
3175static void game_print(drawing *dr, const game_state *state, int tilesize) 3237static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3238 int tilesize)
3176{ 3239{
3177 int w = state->width, h = state->height; 3240 int w = state->width, h = state->height;
3178 int ink = print_mono_colour(dr, 0); 3241 int ink = print_mono_colour(dr, 0);
@@ -3269,13 +3332,15 @@ const struct game thegame = {
3269 dup_game, 3332 dup_game,
3270 free_game, 3333 free_game,
3271 true, solve_game, 3334 true, solve_game,
3272 false, game_can_format_as_text_now, game_text_format, 3335 false, NULL, NULL, /* can_format_as_text_now, text_format */
3336 get_prefs, set_prefs,
3273 new_ui, 3337 new_ui,
3274 free_ui, 3338 free_ui,
3275 encode_ui, 3339 encode_ui,
3276 decode_ui, 3340 decode_ui,
3277 NULL, /* game_request_keys */ 3341 NULL, /* game_request_keys */
3278 game_changed_state, 3342 game_changed_state,
3343 current_key_label,
3279 interpret_move, 3344 interpret_move,
3280 execute_move, 3345 execute_move,
3281 PREFERRED_TILE_SIZE, game_compute_size, game_set_size, 3346 PREFERRED_TILE_SIZE, game_compute_size, game_set_size,
@@ -3289,6 +3354,6 @@ const struct game thegame = {
3289 game_status, 3354 game_status,
3290 true, false, game_print_size, game_print, 3355 true, false, game_print_size, game_print,
3291 true, /* wants_statusbar */ 3356 true, /* wants_statusbar */
3292 false, game_timing_state, 3357 false, NULL, /* timing_state */
3293 0, /* flags */ 3358 0, /* flags */
3294}; 3359};