summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/map.c
diff options
context:
space:
mode:
Diffstat (limited to 'apps/plugins/puzzles/src/map.c')
-rw-r--r--apps/plugins/puzzles/src/map.c260
1 files changed, 168 insertions, 92 deletions
diff --git a/apps/plugins/puzzles/src/map.c b/apps/plugins/puzzles/src/map.c
index 9df2d22b52..2ef156e72a 100644
--- a/apps/plugins/puzzles/src/map.c
+++ b/apps/plugins/puzzles/src/map.c
@@ -14,7 +14,12 @@
14#include <string.h> 14#include <string.h>
15#include <assert.h> 15#include <assert.h>
16#include <ctype.h> 16#include <ctype.h>
17#include <math.h> 17#include <limits.h>
18#ifdef NO_TGMATH_H
19# include <math.h>
20#else
21# include <tgmath.h>
22#endif
18 23
19#include "puzzles.h" 24#include "puzzles.h"
20 25
@@ -25,7 +30,7 @@
25 */ 30 */
26#if defined STANDALONE_SOLVER 31#if defined STANDALONE_SOLVER
27#define SOLVER_DIAGNOSTICS 32#define SOLVER_DIAGNOSTICS
28bool verbose = false; 33static bool verbose = false;
29#elif defined SOLVER_DIAGNOSTICS 34#elif defined SOLVER_DIAGNOSTICS
30#define verbose true 35#define verbose true
31#endif 36#endif
@@ -41,12 +46,6 @@ bool verbose = false;
41#define SIX (FOUR+2) 46#define SIX (FOUR+2)
42 47
43/* 48/*
44 * Ghastly run-time configuration option, just for Gareth (again).
45 */
46static int flash_type = -1;
47static float flash_length;
48
49/*
50 * Difficulty levels. I do some macro ickery here to ensure that my 49 * Difficulty levels. I do some macro ickery here to ensure that my
51 * enum and the various forms of my name list always match up. 50 * enum and the various forms of my name list always match up.
52 */ 51 */
@@ -180,7 +179,9 @@ static void decode_params(game_params *params, char const *string)
180 params->n = atoi(p); 179 params->n = atoi(p);
181 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++; 180 while (*p && (*p == '.' || isdigit((unsigned char)*p))) p++;
182 } else { 181 } else {
183 params->n = params->w * params->h / 8; 182 if (params->h > 0 && params->w > 0 &&
183 params->w <= INT_MAX / params->h)
184 params->n = params->w * params->h / 8;
184 } 185 }
185 if (*p == 'd') { 186 if (*p == 'd') {
186 int i; 187 int i;
@@ -252,6 +253,8 @@ static const char *validate_params(const game_params *params, bool full)
252{ 253{
253 if (params->w < 2 || params->h < 2) 254 if (params->w < 2 || params->h < 2)
254 return "Width and height must be at least two"; 255 return "Width and height must be at least two";
256 if (params->w > INT_MAX / 2 / params->h)
257 return "Width times height must not be unreasonably large";
255 if (params->n < 5) 258 if (params->n < 5)
256 return "Must have at least five regions"; 259 return "Must have at least five regions";
257 if (params->n > params->w * params->h) 260 if (params->n > params->w * params->h)
@@ -1659,6 +1662,10 @@ static char *new_game_desc(const game_params *params, random_state *rs,
1659 } 1662 }
1660 } 1663 }
1661 1664
1665 if (retlen + 10 >= retsize) {
1666 retsize = retlen + 256;
1667 ret = sresize(ret, retsize, char);
1668 }
1662 ret[retlen++] = 'a'-1 + run; 1669 ret[retlen++] = 'a'-1 + run;
1663 ret[retlen++] = ','; 1670 ret[retlen++] = ',';
1664 1671
@@ -1711,8 +1718,8 @@ static const char *parse_edge_list(const game_params *params,
1711 int i, k, pos; 1718 int i, k, pos;
1712 bool state; 1719 bool state;
1713 const char *p = *desc; 1720 const char *p = *desc;
1714 1721 const char *err = NULL;
1715 dsf_init(map+wh, wh); 1722 DSF *dsf = dsf_new(wh);
1716 1723
1717 pos = -1; 1724 pos = -1;
1718 state = false; 1725 state = false;
@@ -1723,8 +1730,10 @@ static const char *parse_edge_list(const game_params *params,
1723 * pairs of squares whenever the edge list shows a non-edge). 1730 * pairs of squares whenever the edge list shows a non-edge).
1724 */ 1731 */
1725 while (*p && *p != ',') { 1732 while (*p && *p != ',') {
1726 if (*p < 'a' || *p > 'z') 1733 if (*p < 'a' || *p > 'z') {
1727 return "Unexpected character in edge list"; 1734 err = "Unexpected character in edge list";
1735 goto out;
1736 }
1728 if (*p == 'z') 1737 if (*p == 'z')
1729 k = 25; 1738 k = 25;
1730 else 1739 else
@@ -1747,10 +1756,12 @@ static const char *parse_edge_list(const game_params *params,
1747 y = (pos - w*(h-1)) % h; 1756 y = (pos - w*(h-1)) % h;
1748 dx = 1; 1757 dx = 1;
1749 dy = 0; 1758 dy = 0;
1750 } else 1759 } else {
1751 return "Too much data in edge list"; 1760 err = "Too much data in edge list";
1761 goto out;
1762 }
1752 if (!state) 1763 if (!state)
1753 dsf_merge(map+wh, y*w+x, (y+dy)*w+(x+dx)); 1764 dsf_merge(dsf, y*w+x, (y+dy)*w+(x+dx));
1754 1765
1755 pos++; 1766 pos++;
1756 } 1767 }
@@ -1759,8 +1770,10 @@ static const char *parse_edge_list(const game_params *params,
1759 p++; 1770 p++;
1760 } 1771 }
1761 assert(pos <= 2*wh-w-h); 1772 assert(pos <= 2*wh-w-h);
1762 if (pos < 2*wh-w-h) 1773 if (pos < 2*wh-w-h) {
1763 return "Too little data in edge list"; 1774 err = "Too little data in edge list";
1775 goto out;
1776 }
1764 1777
1765 /* 1778 /*
1766 * Now go through again and allocate region numbers. 1779 * Now go through again and allocate region numbers.
@@ -1769,17 +1782,22 @@ static const char *parse_edge_list(const game_params *params,
1769 for (i = 0; i < wh; i++) 1782 for (i = 0; i < wh; i++)
1770 map[i] = -1; 1783 map[i] = -1;
1771 for (i = 0; i < wh; i++) { 1784 for (i = 0; i < wh; i++) {
1772 k = dsf_canonify(map+wh, i); 1785 k = dsf_canonify(dsf, i);
1773 if (map[k] < 0) 1786 if (map[k] < 0)
1774 map[k] = pos++; 1787 map[k] = pos++;
1775 map[i] = map[k]; 1788 map[i] = map[k];
1776 } 1789 }
1777 if (pos != n) 1790 if (pos != n) {
1778 return "Edge list defines the wrong number of regions"; 1791 err = "Edge list defines the wrong number of regions";
1792 goto out;
1793 }
1779 1794
1780 *desc = p; 1795 *desc = p;
1796 err = NULL; /* no error */
1781 1797
1782 return NULL; 1798 out:
1799 dsf_free(dsf);
1800 return err;
1783} 1801}
1784 1802
1785static const char *validate_desc(const game_params *params, const char *desc) 1803static const char *validate_desc(const game_params *params, const char *desc)
@@ -1789,7 +1807,7 @@ static const char *validate_desc(const game_params *params, const char *desc)
1789 int *map; 1807 int *map;
1790 const char *ret; 1808 const char *ret;
1791 1809
1792 map = snewn(2*wh, int); 1810 map = snewn(wh, int);
1793 ret = parse_edge_list(params, &desc, map); 1811 ret = parse_edge_list(params, &desc, map);
1794 sfree(map); 1812 sfree(map);
1795 if (ret) 1813 if (ret)
@@ -2252,16 +2270,6 @@ static char *solve_game(const game_state *state, const game_state *currstate,
2252 return dupstr(aux); 2270 return dupstr(aux);
2253} 2271}
2254 2272
2255static bool game_can_format_as_text_now(const game_params *params)
2256{
2257 return true;
2258}
2259
2260static char *game_text_format(const game_state *state)
2261{
2262 return NULL;
2263}
2264
2265struct game_ui { 2273struct game_ui {
2266 /* 2274 /*
2267 * drag_colour: 2275 * drag_colour:
@@ -2275,11 +2283,41 @@ struct game_ui {
2275 int drag_pencil; 2283 int drag_pencil;
2276 int dragx, dragy; 2284 int dragx, dragy;
2277 bool show_numbers; 2285 bool show_numbers;
2286 bool large_stipples;
2278 2287
2279 int cur_x, cur_y, cur_lastmove; 2288 int cur_x, cur_y, cur_lastmove;
2280 bool cur_visible, cur_moved; 2289 bool cur_visible, cur_moved;
2290
2291 /*
2292 * User preference to enable alternative versions of the
2293 * completion flash. Some users have found the colour-cycling
2294 * default version to be a bit eye-twisting.
2295 */
2296 enum {
2297 FLASH_CYCLIC, /* cycle the four colours of the map */
2298 FLASH_EACH_TO_WHITE, /* turn each colour white in turn */
2299 FLASH_ALL_TO_WHITE /* flash the whole map to white in one go */
2300 } flash_type;
2281}; 2301};
2282 2302
2303static void legacy_prefs_override(struct game_ui *ui_out)
2304{
2305 static bool initialised = false;
2306 static int flash_type = -1;
2307
2308 if (!initialised) {
2309 char *env;
2310
2311 initialised = true;
2312
2313 if ((env = getenv("MAP_ALTERNATIVE_FLASH")) != NULL)
2314 flash_type = FLASH_EACH_TO_WHITE;
2315 }
2316
2317 if (flash_type != -1)
2318 ui_out->flash_type = flash_type;
2319}
2320
2283static game_ui *new_ui(const game_state *state) 2321static game_ui *new_ui(const game_state *state)
2284{ 2322{
2285 game_ui *ui = snew(game_ui); 2323 game_ui *ui = snew(game_ui);
@@ -2288,24 +2326,56 @@ static game_ui *new_ui(const game_state *state)
2288 ui->drag_pencil = 0; 2326 ui->drag_pencil = 0;
2289 ui->show_numbers = false; 2327 ui->show_numbers = false;
2290 ui->cur_x = ui->cur_y = 0; 2328 ui->cur_x = ui->cur_y = 0;
2291 ui->cur_visible = false; 2329 ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false);
2292 ui->cur_moved = false; 2330 ui->cur_moved = false;
2293 ui->cur_lastmove = 0; 2331 ui->cur_lastmove = 0;
2332 ui->flash_type = FLASH_CYCLIC;
2333 ui->large_stipples = false;
2334 legacy_prefs_override(ui);
2294 return ui; 2335 return ui;
2295} 2336}
2296 2337
2297static void free_ui(game_ui *ui) 2338static config_item *get_prefs(game_ui *ui)
2298{ 2339{
2299 sfree(ui); 2340 config_item *ret;
2341
2342 ret = snewn(4, config_item);
2343
2344 ret[0].name = "Victory flash effect";
2345 ret[0].kw = "flash-type";
2346 ret[0].type = C_CHOICES;
2347 ret[0].u.choices.choicenames = ":Cyclic:Each to white:All to white";
2348 ret[0].u.choices.choicekws = ":cyclic:each-white:all-white";
2349 ret[0].u.choices.selected = ui->flash_type;
2350
2351 ret[1].name = "Number regions";
2352 ret[1].kw = "show-numbers";
2353 ret[1].type = C_BOOLEAN;
2354 ret[1].u.boolean.bval = ui->show_numbers;
2355
2356 ret[2].name = "Display style for stipple marks";
2357 ret[2].kw = "stipple-style";
2358 ret[2].type = C_CHOICES;
2359 ret[2].u.choices.choicenames = ":Small:Large";
2360 ret[2].u.choices.choicekws = ":small:large";
2361 ret[2].u.choices.selected = ui->large_stipples;
2362
2363 ret[3].name = NULL;
2364 ret[3].type = C_END;
2365
2366 return ret;
2300} 2367}
2301 2368
2302static char *encode_ui(const game_ui *ui) 2369static void set_prefs(game_ui *ui, const config_item *cfg)
2303{ 2370{
2304 return NULL; 2371 ui->flash_type = cfg[0].u.choices.selected;
2372 ui->show_numbers = cfg[1].u.boolean.bval;
2373 ui->large_stipples = cfg[2].u.choices.selected;
2305} 2374}
2306 2375
2307static void decode_ui(game_ui *ui, const char *encoding) 2376static void free_ui(game_ui *ui)
2308{ 2377{
2378 sfree(ui);
2309} 2379}
2310 2380
2311static void game_changed_state(game_ui *ui, const game_state *oldstate, 2381static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2388,6 +2458,26 @@ static int region_from_ui_cursor(const game_state *state, const game_ui *ui)
2388 EPSILON_Y(ui->cur_lastmove)); 2458 EPSILON_Y(ui->cur_lastmove));
2389} 2459}
2390 2460
2461static const char *current_key_label(const game_ui *ui,
2462 const game_state *state, int button)
2463{
2464 int r;
2465
2466 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
2467 if (ui->drag_colour == -2) return "Pick";
2468 r = region_from_ui_cursor(state, ui);
2469 if (state->map->immutable[r]) return "Cancel";
2470 if (!ui->cur_moved) return ui->drag_pencil ? "Cancel" : "Clear";
2471 if (button == CURSOR_SELECT2) {
2472 if (state->colouring[r] >= 0) return "Cancel";
2473 if (ui->drag_colour >= 0) return "Stipple";
2474 }
2475 if (ui->drag_pencil) return "Stipple";
2476 return ui->drag_colour >= 0 ? "Fill" : "Clear";
2477 }
2478 return "";
2479}
2480
2391static char *interpret_move(const game_state *state, game_ui *ui, 2481static char *interpret_move(const game_state *state, game_ui *ui,
2392 const game_drawstate *ds, 2482 const game_drawstate *ds,
2393 int x, int y, int button) 2483 int x, int y, int button)
@@ -2401,21 +2491,21 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2401 */ 2491 */
2402 if (button == 'l' || button == 'L') { 2492 if (button == 'l' || button == 'L') {
2403 ui->show_numbers = !ui->show_numbers; 2493 ui->show_numbers = !ui->show_numbers;
2404 return UI_UPDATE; 2494 return MOVE_UI_UPDATE;
2405 } 2495 }
2406 2496
2407 if (IS_CURSOR_MOVE(button)) { 2497 if (IS_CURSOR_MOVE(button)) {
2408 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h, 2498 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h,
2409 false); 2499 false, NULL);
2410 ui->cur_visible = true; 2500 ui->cur_visible = true;
2411 ui->cur_moved = true; 2501 ui->cur_moved = true;
2412 ui->cur_lastmove = button; 2502 ui->cur_lastmove = button;
2413 return UI_UPDATE; 2503 return MOVE_UI_UPDATE;
2414 } 2504 }
2415 if (IS_CURSOR_SELECT(button)) { 2505 if (IS_CURSOR_SELECT(button)) {
2416 if (!ui->cur_visible) { 2506 if (!ui->cur_visible) {
2417 ui->cur_visible = true; 2507 ui->cur_visible = true;
2418 return UI_UPDATE; 2508 return MOVE_UI_UPDATE;
2419 } 2509 }
2420 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */ 2510 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */
2421 int r = region_from_ui_cursor(state, ui); 2511 int r = region_from_ui_cursor(state, ui);
@@ -2427,7 +2517,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2427 ui->drag_pencil = 0; 2517 ui->drag_pencil = 0;
2428 } 2518 }
2429 ui->cur_moved = false; 2519 ui->cur_moved = false;
2430 return UI_UPDATE; 2520 return MOVE_UI_UPDATE;
2431 } else { /* currently cursor-dragging; drop the colour in the new region. */ 2521 } else { /* currently cursor-dragging; drop the colour in the new region. */
2432 alt_button = (button == CURSOR_SELECT2); 2522 alt_button = (button == CURSOR_SELECT2);
2433 /* Double-select removes current colour. */ 2523 /* Double-select removes current colour. */
@@ -2452,14 +2542,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2452 ui->dragx = x; 2542 ui->dragx = x;
2453 ui->dragy = y; 2543 ui->dragy = y;
2454 ui->cur_visible = false; 2544 ui->cur_visible = false;
2455 return UI_UPDATE; 2545 return MOVE_UI_UPDATE;
2456 } 2546 }
2457 2547
2458 if ((button == LEFT_DRAG || button == RIGHT_DRAG) && 2548 if ((button == LEFT_DRAG || button == RIGHT_DRAG) &&
2459 ui->drag_colour > -2) { 2549 ui->drag_colour > -2) {
2460 ui->dragx = x; 2550 ui->dragx = x;
2461 ui->dragy = y; 2551 ui->dragy = y;
2462 return UI_UPDATE; 2552 return MOVE_UI_UPDATE;
2463 } 2553 }
2464 2554
2465 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) && 2555 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) &&
@@ -2484,18 +2574,18 @@ drag_dropped:
2484 ui->drag_colour = -2; 2574 ui->drag_colour = -2;
2485 2575
2486 if (r < 0) 2576 if (r < 0)
2487 return UI_UPDATE; /* drag into border; do nothing else */ 2577 return MOVE_UI_UPDATE; /* drag into border; do nothing else */
2488 2578
2489 if (state->map->immutable[r]) 2579 if (state->map->immutable[r])
2490 return UI_UPDATE; /* can't change this region */ 2580 return MOVE_UI_UPDATE; /* can't change this region */
2491 2581
2492 if (state->colouring[r] == c && state->pencil[r] == p) 2582 if (state->colouring[r] == c && state->pencil[r] == p)
2493 return UI_UPDATE; /* don't _need_ to change this region */ 2583 return MOVE_UI_UPDATE; /* don't _need_ to change this region */
2494 2584
2495 if (alt_button) { 2585 if (alt_button) {
2496 if (state->colouring[r] >= 0) { 2586 if (state->colouring[r] >= 0) {
2497 /* Can't pencil on a coloured region */ 2587 /* Can't pencil on a coloured region */
2498 return UI_UPDATE; 2588 return MOVE_UI_UPDATE;
2499 } else if (c >= 0) { 2589 } else if (c >= 0) {
2500 /* Right-dragging from colour to blank toggles one pencil */ 2590 /* Right-dragging from colour to blank toggles one pencil */
2501 p = state->pencil[r] ^ (1 << c); 2591 p = state->pencil[r] ^ (1 << c);
@@ -2605,7 +2695,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2605 */ 2695 */
2606 2696
2607static void game_compute_size(const game_params *params, int tilesize, 2697static void game_compute_size(const game_params *params, int tilesize,
2608 int *x, int *y) 2698 const game_ui *ui, int *x, int *y)
2609{ 2699{
2610 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2700 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2611 struct { int tilesize; } ads, *ds = &ads; 2701 struct { int tilesize; } ads, *ds = &ads;
@@ -2729,7 +2819,7 @@ static void draw_error(drawing *dr, game_drawstate *ds, int x, int y)
2729 2819
2730static void draw_square(drawing *dr, game_drawstate *ds, 2820static void draw_square(drawing *dr, game_drawstate *ds,
2731 const game_params *params, struct map *map, 2821 const game_params *params, struct map *map,
2732 int x, int y, unsigned long v) 2822 int x, int y, unsigned long v, bool large_stipples)
2733{ 2823{
2734 int w = params->w, h = params->h, wh = w*h; 2824 int w = params->w, h = params->h, wh = w*h;
2735 int tv, bv, xo, yo, i, j, oldj; 2825 int tv, bv, xo, yo, i, j, oldj;
@@ -2802,7 +2892,8 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2802 2892
2803 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5, 2893 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5,
2804 COORD(y) + (yo+1)*TILESIZE/5, 2894 COORD(y) + (yo+1)*TILESIZE/5,
2805 TILESIZE/4, COL_0 + c, COL_0 + c); 2895 large_stipples ? TILESIZE/4 : TILESIZE/7,
2896 COL_0 + c, COL_0 + c);
2806 } 2897 }
2807 2898
2808 /* 2899 /*
@@ -2857,6 +2948,11 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2857 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); 2948 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2858} 2949}
2859 2950
2951static float flash_length(const game_ui *ui)
2952{
2953 return (ui->flash_type == FLASH_EACH_TO_WHITE ? 0.50F : 0.30F);
2954}
2955
2860static void game_redraw(drawing *dr, game_drawstate *ds, 2956static void game_redraw(drawing *dr, game_drawstate *ds,
2861 const game_state *oldstate, const game_state *state, 2957 const game_state *oldstate, const game_state *state,
2862 int dir, const game_ui *ui, 2958 int dir, const game_ui *ui,
@@ -2872,29 +2968,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2872 ds->drag_visible = false; 2968 ds->drag_visible = false;
2873 } 2969 }
2874 2970
2875 /*
2876 * The initial contents of the window are not guaranteed and
2877 * can vary with front ends. To be on the safe side, all games
2878 * should start by drawing a big background-colour rectangle
2879 * covering the whole window.
2880 */
2881 if (!ds->started) { 2971 if (!ds->started) {
2882 int ww, wh;
2883
2884 game_compute_size(&state->p, TILESIZE, &ww, &wh);
2885 draw_rect(dr, 0, 0, ww, wh, COL_BACKGROUND);
2886 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1, 2972 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1,
2887 COL_GRID); 2973 COL_GRID);
2888 2974 draw_update(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1);
2889 draw_update(dr, 0, 0, ww, wh);
2890 ds->started = true; 2975 ds->started = true;
2891 } 2976 }
2892 2977
2893 if (flashtime) { 2978 if (flashtime) {
2894 if (flash_type == 1) 2979 if (ui->flash_type == FLASH_EACH_TO_WHITE)
2895 flash = (int)(flashtime * FOUR / flash_length); 2980 flash = (int)(flashtime * FOUR / flash_length(ui));
2896 else 2981 else
2897 flash = 1 + (int)(flashtime * THREE / flash_length); 2982 flash = 1 + (int)(flashtime * THREE / flash_length(ui));
2898 } else 2983 } else
2899 flash = -1; 2984 flash = -1;
2900 2985
@@ -2913,12 +2998,12 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2913 bv = FOUR; 2998 bv = FOUR;
2914 2999
2915 if (flash >= 0) { 3000 if (flash >= 0) {
2916 if (flash_type == 1) { 3001 if (ui->flash_type == FLASH_EACH_TO_WHITE) {
2917 if (tv == flash) 3002 if (tv == flash)
2918 tv = FOUR; 3003 tv = FOUR;
2919 if (bv == flash) 3004 if (bv == flash)
2920 bv = FOUR; 3005 bv = FOUR;
2921 } else if (flash_type == 2) { 3006 } else if (ui->flash_type == FLASH_ALL_TO_WHITE) {
2922 if (flash % 2) 3007 if (flash % 2)
2923 tv = bv = FOUR; 3008 tv = bv = FOUR;
2924 } else { 3009 } else {
@@ -2990,7 +3075,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2990 for (x = 0; x < w; x++) { 3075 for (x = 0; x < w; x++) {
2991 unsigned long v = ds->todraw[y*w+x]; 3076 unsigned long v = ds->todraw[y*w+x];
2992 if (ds->drawn[y*w+x] != v) { 3077 if (ds->drawn[y*w+x] != v) {
2993 draw_square(dr, ds, &state->p, state->map, x, y, v); 3078 draw_square(dr, ds, &state->p, state->map, x, y, v, ui->large_stipples);
2994 ds->drawn[y*w+x] = v; 3079 ds->drawn[y*w+x] = v;
2995 } 3080 }
2996 } 3081 }
@@ -3048,15 +3133,7 @@ static float game_flash_length(const game_state *oldstate,
3048{ 3133{
3049 if (!oldstate->completed && newstate->completed && 3134 if (!oldstate->completed && newstate->completed &&
3050 !oldstate->cheated && !newstate->cheated) { 3135 !oldstate->cheated && !newstate->cheated) {
3051 if (flash_type < 0) { 3136 return flash_length(ui);
3052 char *env = getenv("MAP_ALTERNATIVE_FLASH");
3053 if (env)
3054 flash_type = atoi(env);
3055 else
3056 flash_type = 0;
3057 flash_length = (flash_type == 1 ? 0.50F : 0.30F);
3058 }
3059 return flash_length;
3060 } else 3137 } else
3061 return 0.0F; 3138 return 0.0F;
3062} 3139}
@@ -3079,12 +3156,8 @@ static int game_status(const game_state *state)
3079 return state->completed ? +1 : 0; 3156 return state->completed ? +1 : 0;
3080} 3157}
3081 3158
3082static bool game_timing_state(const game_state *state, game_ui *ui) 3159static void game_print_size(const game_params *params, const game_ui *ui,
3083{ 3160 float *x, float *y)
3084 return true;
3085}
3086
3087static void game_print_size(const game_params *params, float *x, float *y)
3088{ 3161{
3089 int pw, ph; 3162 int pw, ph;
3090 3163
@@ -3093,12 +3166,13 @@ static void game_print_size(const game_params *params, float *x, float *y)
3093 * compute this size is to compute the pixel puzzle size at a 3166 * compute this size is to compute the pixel puzzle size at a
3094 * given tile size and then scale. 3167 * given tile size and then scale.
3095 */ 3168 */
3096 game_compute_size(params, 400, &pw, &ph); 3169 game_compute_size(params, 400, ui, &pw, &ph);
3097 *x = pw / 100.0F; 3170 *x = pw / 100.0F;
3098 *y = ph / 100.0F; 3171 *y = ph / 100.0F;
3099} 3172}
3100 3173
3101static void game_print(drawing *dr, const game_state *state, int tilesize) 3174static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3175 int tilesize)
3102{ 3176{
3103 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n; 3177 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
3104 int ink, c[FOUR], i; 3178 int ink, c[FOUR], i;
@@ -3257,13 +3331,15 @@ const struct game thegame = {
3257 dup_game, 3331 dup_game,
3258 free_game, 3332 free_game,
3259 true, solve_game, 3333 true, solve_game,
3260 false, game_can_format_as_text_now, game_text_format, 3334 false, NULL, NULL, /* can_format_as_text_now, text_format */
3335 get_prefs, set_prefs,
3261 new_ui, 3336 new_ui,
3262 free_ui, 3337 free_ui,
3263 encode_ui, 3338 NULL, /* encode_ui */
3264 decode_ui, 3339 NULL, /* decode_ui */
3265 NULL, /* game_request_keys */ 3340 NULL, /* game_request_keys */
3266 game_changed_state, 3341 game_changed_state,
3342 current_key_label,
3267 interpret_move, 3343 interpret_move,
3268 execute_move, 3344 execute_move,
3269 20, game_compute_size, game_set_size, 3345 20, game_compute_size, game_set_size,
@@ -3277,7 +3353,7 @@ const struct game thegame = {
3277 game_status, 3353 game_status,
3278 true, true, game_print_size, game_print, 3354 true, true, game_print_size, game_print,
3279 false, /* wants_statusbar */ 3355 false, /* wants_statusbar */
3280 false, game_timing_state, 3356 false, NULL, /* timing_state */
3281 0, /* flags */ 3357 0, /* flags */
3282}; 3358};
3283 3359