summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/map.c
diff options
context:
space:
mode:
authorFranklin Wei <franklin@rockbox.org>2024-07-22 21:43:25 -0400
committerFranklin Wei <franklin@rockbox.org>2024-07-22 21:44:08 -0400
commit09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c (patch)
tree182bd4efb2dc8ca4fcb369d8cccab0c0f290d054 /apps/plugins/puzzles/src/map.c
parentc72030f98c953a82ed6f5c7132ad000c3d5f4a16 (diff)
downloadrockbox-09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c.tar.gz
rockbox-09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c.zip
puzzles: resync with upstream
This brings the puzzles source in sync with Simon's branch, commit fd304c5 (from March 2024), with some added Rockbox-specific compatibility changes: https://www.franklinwei.com/git/puzzles/commit/?h=rockbox-devel&id=516830d9d76bdfe64fe5ccf2a9b59c33f5c7c078 There are quite a lot of backend changes, including a new "Mosaic" puzzle. In addition, some new frontend changes were necessary: - New "Preferences" menu to access the user preferences system. - Enabled spacebar input for several games. Change-Id: I94c7df674089c92f32d5f07025f6a1059068af1e
Diffstat (limited to 'apps/plugins/puzzles/src/map.c')
-rw-r--r--apps/plugins/puzzles/src/map.c259
1 files changed, 167 insertions, 92 deletions
diff --git a/apps/plugins/puzzles/src/map.c b/apps/plugins/puzzles/src/map.c
index 9df2d22b52..9cea0d4647 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,55 @@ 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 legacy_prefs_override(ui);
2294 return ui; 2334 return ui;
2295} 2335}
2296 2336
2297static void free_ui(game_ui *ui) 2337static config_item *get_prefs(game_ui *ui)
2298{ 2338{
2299 sfree(ui); 2339 config_item *ret;
2340
2341 ret = snewn(4, config_item);
2342
2343 ret[0].name = "Victory flash effect";
2344 ret[0].kw = "flash-type";
2345 ret[0].type = C_CHOICES;
2346 ret[0].u.choices.choicenames = ":Cyclic:Each to white:All to white";
2347 ret[0].u.choices.choicekws = ":cyclic:each-white:all-white";
2348 ret[0].u.choices.selected = ui->flash_type;
2349
2350 ret[1].name = "Number regions";
2351 ret[1].kw = "show-numbers";
2352 ret[1].type = C_BOOLEAN;
2353 ret[1].u.boolean.bval = ui->show_numbers;
2354
2355 ret[2].name = "Display style for stipple marks";
2356 ret[2].kw = "stipple-style";
2357 ret[2].type = C_CHOICES;
2358 ret[2].u.choices.choicenames = ":Small:Large";
2359 ret[2].u.choices.choicekws = ":small:large";
2360 ret[2].u.choices.selected = ui->large_stipples;
2361
2362 ret[3].name = NULL;
2363 ret[3].type = C_END;
2364
2365 return ret;
2300} 2366}
2301 2367
2302static char *encode_ui(const game_ui *ui) 2368static void set_prefs(game_ui *ui, const config_item *cfg)
2303{ 2369{
2304 return NULL; 2370 ui->flash_type = cfg[0].u.choices.selected;
2371 ui->show_numbers = cfg[1].u.boolean.bval;
2372 ui->large_stipples = cfg[2].u.choices.selected;
2305} 2373}
2306 2374
2307static void decode_ui(game_ui *ui, const char *encoding) 2375static void free_ui(game_ui *ui)
2308{ 2376{
2377 sfree(ui);
2309} 2378}
2310 2379
2311static void game_changed_state(game_ui *ui, const game_state *oldstate, 2380static void game_changed_state(game_ui *ui, const game_state *oldstate,
@@ -2388,6 +2457,26 @@ static int region_from_ui_cursor(const game_state *state, const game_ui *ui)
2388 EPSILON_Y(ui->cur_lastmove)); 2457 EPSILON_Y(ui->cur_lastmove));
2389} 2458}
2390 2459
2460static const char *current_key_label(const game_ui *ui,
2461 const game_state *state, int button)
2462{
2463 int r;
2464
2465 if (IS_CURSOR_SELECT(button) && ui->cur_visible) {
2466 if (ui->drag_colour == -2) return "Pick";
2467 r = region_from_ui_cursor(state, ui);
2468 if (state->map->immutable[r]) return "Cancel";
2469 if (!ui->cur_moved) return ui->drag_pencil ? "Cancel" : "Clear";
2470 if (button == CURSOR_SELECT2) {
2471 if (state->colouring[r] >= 0) return "Cancel";
2472 if (ui->drag_colour >= 0) return "Stipple";
2473 }
2474 if (ui->drag_pencil) return "Stipple";
2475 return ui->drag_colour >= 0 ? "Fill" : "Clear";
2476 }
2477 return "";
2478}
2479
2391static char *interpret_move(const game_state *state, game_ui *ui, 2480static char *interpret_move(const game_state *state, game_ui *ui,
2392 const game_drawstate *ds, 2481 const game_drawstate *ds,
2393 int x, int y, int button) 2482 int x, int y, int button)
@@ -2401,21 +2490,21 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2401 */ 2490 */
2402 if (button == 'l' || button == 'L') { 2491 if (button == 'l' || button == 'L') {
2403 ui->show_numbers = !ui->show_numbers; 2492 ui->show_numbers = !ui->show_numbers;
2404 return UI_UPDATE; 2493 return MOVE_UI_UPDATE;
2405 } 2494 }
2406 2495
2407 if (IS_CURSOR_MOVE(button)) { 2496 if (IS_CURSOR_MOVE(button)) {
2408 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h, 2497 move_cursor(button, &ui->cur_x, &ui->cur_y, state->p.w, state->p.h,
2409 false); 2498 false, NULL);
2410 ui->cur_visible = true; 2499 ui->cur_visible = true;
2411 ui->cur_moved = true; 2500 ui->cur_moved = true;
2412 ui->cur_lastmove = button; 2501 ui->cur_lastmove = button;
2413 return UI_UPDATE; 2502 return MOVE_UI_UPDATE;
2414 } 2503 }
2415 if (IS_CURSOR_SELECT(button)) { 2504 if (IS_CURSOR_SELECT(button)) {
2416 if (!ui->cur_visible) { 2505 if (!ui->cur_visible) {
2417 ui->cur_visible = true; 2506 ui->cur_visible = true;
2418 return UI_UPDATE; 2507 return MOVE_UI_UPDATE;
2419 } 2508 }
2420 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */ 2509 if (ui->drag_colour == -2) { /* not currently cursor-dragging, start. */
2421 int r = region_from_ui_cursor(state, ui); 2510 int r = region_from_ui_cursor(state, ui);
@@ -2427,7 +2516,7 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2427 ui->drag_pencil = 0; 2516 ui->drag_pencil = 0;
2428 } 2517 }
2429 ui->cur_moved = false; 2518 ui->cur_moved = false;
2430 return UI_UPDATE; 2519 return MOVE_UI_UPDATE;
2431 } else { /* currently cursor-dragging; drop the colour in the new region. */ 2520 } else { /* currently cursor-dragging; drop the colour in the new region. */
2432 alt_button = (button == CURSOR_SELECT2); 2521 alt_button = (button == CURSOR_SELECT2);
2433 /* Double-select removes current colour. */ 2522 /* Double-select removes current colour. */
@@ -2452,14 +2541,14 @@ static char *interpret_move(const game_state *state, game_ui *ui,
2452 ui->dragx = x; 2541 ui->dragx = x;
2453 ui->dragy = y; 2542 ui->dragy = y;
2454 ui->cur_visible = false; 2543 ui->cur_visible = false;
2455 return UI_UPDATE; 2544 return MOVE_UI_UPDATE;
2456 } 2545 }
2457 2546
2458 if ((button == LEFT_DRAG || button == RIGHT_DRAG) && 2547 if ((button == LEFT_DRAG || button == RIGHT_DRAG) &&
2459 ui->drag_colour > -2) { 2548 ui->drag_colour > -2) {
2460 ui->dragx = x; 2549 ui->dragx = x;
2461 ui->dragy = y; 2550 ui->dragy = y;
2462 return UI_UPDATE; 2551 return MOVE_UI_UPDATE;
2463 } 2552 }
2464 2553
2465 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) && 2554 if ((button == LEFT_RELEASE || button == RIGHT_RELEASE) &&
@@ -2484,18 +2573,18 @@ drag_dropped:
2484 ui->drag_colour = -2; 2573 ui->drag_colour = -2;
2485 2574
2486 if (r < 0) 2575 if (r < 0)
2487 return UI_UPDATE; /* drag into border; do nothing else */ 2576 return MOVE_UI_UPDATE; /* drag into border; do nothing else */
2488 2577
2489 if (state->map->immutable[r]) 2578 if (state->map->immutable[r])
2490 return UI_UPDATE; /* can't change this region */ 2579 return MOVE_UI_UPDATE; /* can't change this region */
2491 2580
2492 if (state->colouring[r] == c && state->pencil[r] == p) 2581 if (state->colouring[r] == c && state->pencil[r] == p)
2493 return UI_UPDATE; /* don't _need_ to change this region */ 2582 return MOVE_UI_UPDATE; /* don't _need_ to change this region */
2494 2583
2495 if (alt_button) { 2584 if (alt_button) {
2496 if (state->colouring[r] >= 0) { 2585 if (state->colouring[r] >= 0) {
2497 /* Can't pencil on a coloured region */ 2586 /* Can't pencil on a coloured region */
2498 return UI_UPDATE; 2587 return MOVE_UI_UPDATE;
2499 } else if (c >= 0) { 2588 } else if (c >= 0) {
2500 /* Right-dragging from colour to blank toggles one pencil */ 2589 /* Right-dragging from colour to blank toggles one pencil */
2501 p = state->pencil[r] ^ (1 << c); 2590 p = state->pencil[r] ^ (1 << c);
@@ -2605,7 +2694,7 @@ static game_state *execute_move(const game_state *state, const char *move)
2605 */ 2694 */
2606 2695
2607static void game_compute_size(const game_params *params, int tilesize, 2696static void game_compute_size(const game_params *params, int tilesize,
2608 int *x, int *y) 2697 const game_ui *ui, int *x, int *y)
2609{ 2698{
2610 /* Ick: fake up `ds->tilesize' for macro expansion purposes */ 2699 /* Ick: fake up `ds->tilesize' for macro expansion purposes */
2611 struct { int tilesize; } ads, *ds = &ads; 2700 struct { int tilesize; } ads, *ds = &ads;
@@ -2729,7 +2818,7 @@ static void draw_error(drawing *dr, game_drawstate *ds, int x, int y)
2729 2818
2730static void draw_square(drawing *dr, game_drawstate *ds, 2819static void draw_square(drawing *dr, game_drawstate *ds,
2731 const game_params *params, struct map *map, 2820 const game_params *params, struct map *map,
2732 int x, int y, unsigned long v) 2821 int x, int y, unsigned long v, bool large_stipples)
2733{ 2822{
2734 int w = params->w, h = params->h, wh = w*h; 2823 int w = params->w, h = params->h, wh = w*h;
2735 int tv, bv, xo, yo, i, j, oldj; 2824 int tv, bv, xo, yo, i, j, oldj;
@@ -2802,7 +2891,8 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2802 2891
2803 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5, 2892 draw_circle(dr, COORD(x) + (xo+1)*TILESIZE/5,
2804 COORD(y) + (yo+1)*TILESIZE/5, 2893 COORD(y) + (yo+1)*TILESIZE/5,
2805 TILESIZE/4, COL_0 + c, COL_0 + c); 2894 large_stipples ? TILESIZE/4 : TILESIZE/7,
2895 COL_0 + c, COL_0 + c);
2806 } 2896 }
2807 2897
2808 /* 2898 /*
@@ -2857,6 +2947,11 @@ static void draw_square(drawing *dr, game_drawstate *ds,
2857 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE); 2947 draw_update(dr, COORD(x), COORD(y), TILESIZE, TILESIZE);
2858} 2948}
2859 2949
2950static float flash_length(const game_ui *ui)
2951{
2952 return (ui->flash_type == FLASH_EACH_TO_WHITE ? 0.50F : 0.30F);
2953}
2954
2860static void game_redraw(drawing *dr, game_drawstate *ds, 2955static void game_redraw(drawing *dr, game_drawstate *ds,
2861 const game_state *oldstate, const game_state *state, 2956 const game_state *oldstate, const game_state *state,
2862 int dir, const game_ui *ui, 2957 int dir, const game_ui *ui,
@@ -2872,29 +2967,18 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2872 ds->drag_visible = false; 2967 ds->drag_visible = false;
2873 } 2968 }
2874 2969
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) { 2970 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, 2971 draw_rect(dr, COORD(0), COORD(0), w*TILESIZE+1, h*TILESIZE+1,
2887 COL_GRID); 2972 COL_GRID);
2888 2973 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; 2974 ds->started = true;
2891 } 2975 }
2892 2976
2893 if (flashtime) { 2977 if (flashtime) {
2894 if (flash_type == 1) 2978 if (ui->flash_type == FLASH_EACH_TO_WHITE)
2895 flash = (int)(flashtime * FOUR / flash_length); 2979 flash = (int)(flashtime * FOUR / flash_length(ui));
2896 else 2980 else
2897 flash = 1 + (int)(flashtime * THREE / flash_length); 2981 flash = 1 + (int)(flashtime * THREE / flash_length(ui));
2898 } else 2982 } else
2899 flash = -1; 2983 flash = -1;
2900 2984
@@ -2913,12 +2997,12 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2913 bv = FOUR; 2997 bv = FOUR;
2914 2998
2915 if (flash >= 0) { 2999 if (flash >= 0) {
2916 if (flash_type == 1) { 3000 if (ui->flash_type == FLASH_EACH_TO_WHITE) {
2917 if (tv == flash) 3001 if (tv == flash)
2918 tv = FOUR; 3002 tv = FOUR;
2919 if (bv == flash) 3003 if (bv == flash)
2920 bv = FOUR; 3004 bv = FOUR;
2921 } else if (flash_type == 2) { 3005 } else if (ui->flash_type == FLASH_ALL_TO_WHITE) {
2922 if (flash % 2) 3006 if (flash % 2)
2923 tv = bv = FOUR; 3007 tv = bv = FOUR;
2924 } else { 3008 } else {
@@ -2990,7 +3074,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
2990 for (x = 0; x < w; x++) { 3074 for (x = 0; x < w; x++) {
2991 unsigned long v = ds->todraw[y*w+x]; 3075 unsigned long v = ds->todraw[y*w+x];
2992 if (ds->drawn[y*w+x] != v) { 3076 if (ds->drawn[y*w+x] != v) {
2993 draw_square(dr, ds, &state->p, state->map, x, y, v); 3077 draw_square(dr, ds, &state->p, state->map, x, y, v, ui->large_stipples);
2994 ds->drawn[y*w+x] = v; 3078 ds->drawn[y*w+x] = v;
2995 } 3079 }
2996 } 3080 }
@@ -3048,15 +3132,7 @@ static float game_flash_length(const game_state *oldstate,
3048{ 3132{
3049 if (!oldstate->completed && newstate->completed && 3133 if (!oldstate->completed && newstate->completed &&
3050 !oldstate->cheated && !newstate->cheated) { 3134 !oldstate->cheated && !newstate->cheated) {
3051 if (flash_type < 0) { 3135 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 3136 } else
3061 return 0.0F; 3137 return 0.0F;
3062} 3138}
@@ -3079,12 +3155,8 @@ static int game_status(const game_state *state)
3079 return state->completed ? +1 : 0; 3155 return state->completed ? +1 : 0;
3080} 3156}
3081 3157
3082static bool game_timing_state(const game_state *state, game_ui *ui) 3158static void game_print_size(const game_params *params, const game_ui *ui,
3083{ 3159 float *x, float *y)
3084 return true;
3085}
3086
3087static void game_print_size(const game_params *params, float *x, float *y)
3088{ 3160{
3089 int pw, ph; 3161 int pw, ph;
3090 3162
@@ -3093,12 +3165,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 3165 * compute this size is to compute the pixel puzzle size at a
3094 * given tile size and then scale. 3166 * given tile size and then scale.
3095 */ 3167 */
3096 game_compute_size(params, 400, &pw, &ph); 3168 game_compute_size(params, 400, ui, &pw, &ph);
3097 *x = pw / 100.0F; 3169 *x = pw / 100.0F;
3098 *y = ph / 100.0F; 3170 *y = ph / 100.0F;
3099} 3171}
3100 3172
3101static void game_print(drawing *dr, const game_state *state, int tilesize) 3173static void game_print(drawing *dr, const game_state *state, const game_ui *ui,
3174 int tilesize)
3102{ 3175{
3103 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n; 3176 int w = state->p.w, h = state->p.h, wh = w*h, n = state->p.n;
3104 int ink, c[FOUR], i; 3177 int ink, c[FOUR], i;
@@ -3257,13 +3330,15 @@ const struct game thegame = {
3257 dup_game, 3330 dup_game,
3258 free_game, 3331 free_game,
3259 true, solve_game, 3332 true, solve_game,
3260 false, game_can_format_as_text_now, game_text_format, 3333 false, NULL, NULL, /* can_format_as_text_now, text_format */
3334 get_prefs, set_prefs,
3261 new_ui, 3335 new_ui,
3262 free_ui, 3336 free_ui,
3263 encode_ui, 3337 NULL, /* encode_ui */
3264 decode_ui, 3338 NULL, /* decode_ui */
3265 NULL, /* game_request_keys */ 3339 NULL, /* game_request_keys */
3266 game_changed_state, 3340 game_changed_state,
3341 current_key_label,
3267 interpret_move, 3342 interpret_move,
3268 execute_move, 3343 execute_move,
3269 20, game_compute_size, game_set_size, 3344 20, game_compute_size, game_set_size,
@@ -3277,7 +3352,7 @@ const struct game thegame = {
3277 game_status, 3352 game_status,
3278 true, true, game_print_size, game_print, 3353 true, true, game_print_size, game_print,
3279 false, /* wants_statusbar */ 3354 false, /* wants_statusbar */
3280 false, game_timing_state, 3355 false, NULL, /* timing_state */
3281 0, /* flags */ 3356 0, /* flags */
3282}; 3357};
3283 3358