From 09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c Mon Sep 17 00:00:00 2001 From: Franklin Wei Date: Mon, 22 Jul 2024 21:43:25 -0400 Subject: 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 --- apps/plugins/puzzles/src/lightup.c | 137 +++++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 42 deletions(-) (limited to 'apps/plugins/puzzles/src/lightup.c') diff --git a/apps/plugins/puzzles/src/lightup.c b/apps/plugins/puzzles/src/lightup.c index ab4be9ec87..e779663e01 100644 --- a/apps/plugins/puzzles/src/lightup.c +++ b/apps/plugins/puzzles/src/lightup.c @@ -47,7 +47,12 @@ #include #include #include -#include +#include +#ifdef NO_TGMATH_H +# include +#else +# include +#endif #include "puzzles.h" @@ -58,7 +63,7 @@ */ #if defined STANDALONE_SOLVER #define SOLVER_DIAGNOSTICS -int verbose = 0; +static int verbose = 0; #undef debug #define debug(x) printf x #elif defined SOLVER_DIAGNOSTICS @@ -346,6 +351,8 @@ static const char *validate_params(const game_params *params, bool full) { if (params->w < 2 || params->h < 2) return "Width and height must be at least 2"; + if (params->w > INT_MAX / params->h) + return "Width times height must not be unreasonably large"; if (full) { if (params->blackpc < 5 || params->blackpc > 100) return "Percentage of black squares must be between 5% and 100%"; @@ -353,6 +360,8 @@ static const char *validate_params(const game_params *params, bool full) if (params->symm == SYMM_ROT4) return "4-fold symmetry is only available with square grids"; } + if ((params->symm == SYMM_ROT4 || params->symm == SYMM_REF4) && params->w < 3 && params->h < 3) + return "Width or height must be at least 3 for 4-way symmetry"; if (params->symm < 0 || params->symm >= SYMM_MAX) return "Unknown symmetry type"; if (params->difficulty < 0 || params->difficulty > DIFFCOUNT) @@ -411,6 +420,8 @@ static void debug_state(game_state *state) int x, y; char c = '?'; + (void)c; /* placate -Wunused-but-set-variable if debug() does nothing */ + for (y = 0; y < state->h; y++) { for (x = 0; x < state->w; x++) { c = '.'; @@ -1822,30 +1833,65 @@ static char *game_text_format(const game_state *state) struct game_ui { int cur_x, cur_y; bool cur_visible; + + /* + * User preference: when a square contains both a black blob for + * 'user is convinced this isn't a light' and a yellow highlight + * for 'this square is lit by a light', both of which rule out it + * being a light, should we still bother to show the blob? + */ + bool draw_blobs_when_lit; }; +static void legacy_prefs_override(struct game_ui *ui_out) +{ + static bool initialised = false; + static int draw_blobs_when_lit = -1; + + if (!initialised) { + initialised = true; + draw_blobs_when_lit = getenv_bool("LIGHTUP_LIT_BLOBS", -1); + } + + if (draw_blobs_when_lit != -1) + ui_out->draw_blobs_when_lit = draw_blobs_when_lit; +} + static game_ui *new_ui(const game_state *state) { game_ui *ui = snew(game_ui); ui->cur_x = ui->cur_y = 0; - ui->cur_visible = false; + ui->cur_visible = getenv_bool("PUZZLES_SHOW_CURSOR", false); + ui->draw_blobs_when_lit = true; + legacy_prefs_override(ui); return ui; } -static void free_ui(game_ui *ui) +static config_item *get_prefs(game_ui *ui) { - sfree(ui); + config_item *ret; + + ret = snewn(2, config_item); + + ret[0].name = "Draw non-light marks even when lit"; + ret[0].kw = "show-lit-blobs"; + ret[0].type = C_BOOLEAN; + ret[0].u.boolean.bval = ui->draw_blobs_when_lit; + + ret[1].name = NULL; + ret[1].type = C_END; + + return ret; } -static char *encode_ui(const game_ui *ui) +static void set_prefs(game_ui *ui, const config_item *cfg) { - /* nothing to encode. */ - return NULL; + ui->draw_blobs_when_lit = cfg[0].u.boolean.bval; } -static void decode_ui(game_ui *ui, const char *encoding) +static void free_ui(game_ui *ui) { - /* nothing to decode. */ + sfree(ui); } static void game_changed_state(game_ui *ui, const game_state *oldstate, @@ -1855,6 +1901,26 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate, ui->cur_visible = false; } +static const char *current_key_label(const game_ui *ui, + const game_state *state, int button) +{ + int cx = ui->cur_x, cy = ui->cur_y; + unsigned int flags = GRID(state, flags, cx, cy); + + if (!ui->cur_visible) return ""; + if (button == CURSOR_SELECT) { + if (flags & (F_BLACK | F_IMPOSSIBLE)) return ""; + if (flags & F_LIGHT) return "Clear"; + return "Light"; + } + if (button == CURSOR_SELECT2) { + if (flags & (F_BLACK | F_LIGHT)) return ""; + if (flags & F_IMPOSSIBLE) return "Clear"; + return "Mark"; + } + return ""; +} + #define DF_BLACK 1 /* black square */ #define DF_NUMBERED 2 /* black square with number */ #define DF_LIT 4 /* display (white) square lit up */ @@ -1888,7 +1954,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, enum { NONE, FLIP_LIGHT, FLIP_IMPOSSIBLE } action = NONE; int cx = -1, cy = -1; unsigned int flags; - char buf[80], *nullret = UI_UPDATE, *empty = UI_UPDATE, c; + char buf[80], *nullret = MOVE_NO_EFFECT, *empty = MOVE_UI_UPDATE, c; if (button == LEFT_BUTTON || button == RIGHT_BUTTON) { if (ui->cur_visible) @@ -1898,8 +1964,7 @@ static char *interpret_move(const game_state *state, game_ui *ui, cy = FROMCOORD(y); action = (button == LEFT_BUTTON) ? FLIP_LIGHT : FLIP_IMPOSSIBLE; } else if (IS_CURSOR_SELECT(button) || - button == 'i' || button == 'I' || - button == ' ' || button == '\r' || button == '\n') { + button == 'i' || button == 'I') { if (ui->cur_visible) { /* Only allow cursor-effect operations if the cursor is visible * (otherwise you have no idea which square it might be affecting) */ @@ -1910,11 +1975,10 @@ static char *interpret_move(const game_state *state, game_ui *ui, } ui->cur_visible = true; } else if (IS_CURSOR_MOVE(button)) { - move_cursor(button, &ui->cur_x, &ui->cur_y, state->w, state->h, false); - ui->cur_visible = true; - nullret = empty; + nullret = move_cursor(button, &ui->cur_x, &ui->cur_y, + state->w, state->h, false, &ui->cur_visible); } else - return NULL; + return MOVE_UNUSED; switch (action) { case FLIP_LIGHT: @@ -2002,7 +2066,7 @@ badmove: /* XXX entirely cloned from fifteen.c; separate out? */ static void game_compute_size(const game_params *params, int tilesize, - int *x, int *y) + const game_ui *ui, int *x, int *y) { /* Ick: fake up `ds->tilesize' for macro expansion purposes */ struct { int tilesize; } ads, *ds = &ads; @@ -2111,7 +2175,7 @@ static unsigned int tile_flags(game_drawstate *ds, const game_state *state, return ret; } -static void tile_redraw(drawing *dr, game_drawstate *ds, +static void tile_redraw(drawing *dr, game_drawstate *ds, const game_ui *ui, const game_state *state, int x, int y) { unsigned int ds_flags = GRID(ds, flags, x, y); @@ -2141,13 +2205,7 @@ static void tile_redraw(drawing *dr, game_drawstate *ds, draw_circle(dr, dx + TILE_SIZE/2, dy + TILE_SIZE/2, TILE_RADIUS, lcol, COL_BLACK); } else if ((ds_flags & DF_IMPOSSIBLE)) { - static int draw_blobs_when_lit = -1; - if (draw_blobs_when_lit < 0) { - char *env = getenv("LIGHTUP_LIT_BLOBS"); - draw_blobs_when_lit = (!env || (env[0] == 'y' || - env[0] == 'Y')); - } - if (!(ds_flags & DF_LIT) || draw_blobs_when_lit) { + if (!(ds_flags & DF_LIT) || ui->draw_blobs_when_lit) { int rlen = TILE_SIZE / 4; draw_rect(dr, dx + TILE_SIZE/2 - rlen/2, dy + TILE_SIZE/2 - rlen/2, @@ -2176,10 +2234,6 @@ static void game_redraw(drawing *dr, game_drawstate *ds, if (flashtime) flashing = (int)(flashtime * 3 / FLASH_TIME) != 1; if (!ds->started) { - draw_rect(dr, 0, 0, - TILE_SIZE * ds->w + 2 * BORDER, - TILE_SIZE * ds->h + 2 * BORDER, COL_BACKGROUND); - draw_rect_outline(dr, COORD(0)-1, COORD(0)-1, TILE_SIZE * ds->w + 2, TILE_SIZE * ds->h + 2, @@ -2196,7 +2250,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, unsigned int ds_flags = tile_flags(ds, state, ui, x, y, flashing); if (ds_flags != GRID(ds, flags, x, y)) { GRID(ds, flags, x, y) = ds_flags; - tile_redraw(dr, ds, state, x, y); + tile_redraw(dr, ds, ui, state, x, y); } } } @@ -2235,24 +2289,21 @@ static int game_status(const game_state *state) return state->completed ? +1 : 0; } -static bool game_timing_state(const game_state *state, game_ui *ui) -{ - return true; -} - -static void game_print_size(const game_params *params, float *x, float *y) +static void game_print_size(const game_params *params, const game_ui *ui, + float *x, float *y) { int pw, ph; /* * I'll use 6mm squares by default. */ - game_compute_size(params, 600, &pw, &ph); + game_compute_size(params, 600, ui, &pw, &ph); *x = pw / 100.0F; *y = ph / 100.0F; } -static void game_print(drawing *dr, const game_state *state, int tilesize) +static void game_print(drawing *dr, const game_state *state, const game_ui *ui, + int tilesize) { int w = state->w, h = state->h; int ink = print_mono_colour(dr, 0); @@ -2323,12 +2374,14 @@ const struct game thegame = { free_game, true, solve_game, true, game_can_format_as_text_now, game_text_format, + get_prefs, set_prefs, new_ui, free_ui, - encode_ui, - decode_ui, + NULL, /* encode_ui */ + NULL, /* decode_ui */ NULL, /* game_request_keys */ game_changed_state, + current_key_label, interpret_move, execute_move, PREFERRED_TILE_SIZE, game_compute_size, game_set_size, @@ -2342,7 +2395,7 @@ const struct game thegame = { game_status, true, false, game_print_size, game_print, false, /* wants_statusbar */ - false, game_timing_state, + false, NULL, /* timing_state */ 0, /* flags */ }; -- cgit v1.2.3