chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / samegame.c
index 2331799862695c608256a61feaeb5eb5881f6a45..8e428bb47df136366924096f1f69ed5f270fa7bf 100644 (file)
@@ -121,7 +121,7 @@ struct game_params {
     TILE(gs,x2,y2) = t;                   \
 } while (0)
 
-static int npoints(game_params *params, int nsel)
+static int npoints(const game_params *params, int nsel)
 {
     int sdiff = nsel - params->scoresub;
     return (sdiff > 0) ? sdiff * sdiff : 0;
@@ -181,7 +181,7 @@ static void free_params(game_params *params)
     sfree(params);
 }
 
-static game_params *dup_params(game_params *params)
+static game_params *dup_params(const game_params *params)
 {
     game_params *ret = snew(game_params);
     *ret = *params;                   /* structure copy */
@@ -221,7 +221,7 @@ static void decode_params(game_params *params, char const *string)
     }
 }
 
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
 {
     char ret[80];
 
@@ -231,7 +231,7 @@ static char *encode_params(game_params *params, int full)
     return dupstr(ret);
 }
 
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
 {
     config_item *ret;
     char buf[80];
@@ -274,7 +274,7 @@ static config_item *game_configure(game_params *params)
     return ret;
 }
 
-static game_params *custom_params(config_item *cfg)
+static game_params *custom_params(const config_item *cfg)
 {
     game_params *ret = snew(game_params);
 
@@ -287,7 +287,7 @@ static game_params *custom_params(config_item *cfg)
     return ret;
 }
 
-static char *validate_params(game_params *params, int full)
+static char *validate_params(const game_params *params, int full)
 {
     if (params->w < 1 || params->h < 1)
        return "Width and height must both be positive";
@@ -917,7 +917,7 @@ static void gen_grid_random(int w, int h, int nc, int *grid, random_state *rs)
     }
 }
 
-static char *new_game_desc(game_params *params, random_state *rs,
+static char *new_game_desc(const game_params *params, random_state *rs,
                           char **aux, int interactive)
 {
     char *ret;
@@ -948,13 +948,13 @@ static char *new_game_desc(game_params *params, random_state *rs,
     return ret;
 }
 
-static char *validate_desc(game_params *params, char *desc)
+static char *validate_desc(const game_params *params, const char *desc)
 {
     int area = params->w * params->h, i;
-    char *p = desc;
+    const char *p = desc;
 
     for (i = 0; i < area; i++) {
-       char *q = p;
+       const char *q = p;
        int n;
 
        if (!isdigit((unsigned char)*p))
@@ -975,10 +975,11 @@ static char *validate_desc(game_params *params, char *desc)
     return NULL;
 }
 
-static game_state *new_game(midend_data *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, const game_params *params,
+                            const char *desc)
 {
     game_state *state = snew(game_state);
-    char *p = desc;
+    const char *p = desc;
     int i;
 
     state->params = *params; /* struct copy */
@@ -998,7 +999,7 @@ static game_state *new_game(midend_data *me, game_params *params, char *desc)
     return state;
 }
 
-static game_state *dup_game(game_state *state)
+static game_state *dup_game(const game_state *state)
 {
     game_state *ret = snew(game_state);
 
@@ -1016,13 +1017,18 @@ static void free_game(game_state *state)
     sfree(state);
 }
 
-static char *solve_game(game_state *state, game_state *currstate,
-                       char *aux, char **error)
+static char *solve_game(const game_state *state, const game_state *currstate,
+                        const char *aux, char **error)
 {
     return NULL;
 }
 
-static char *game_text_format(game_state *state)
+static int game_can_format_as_text_now(const game_params *params)
+{
+    return TRUE;
+}
+
+static char *game_text_format(const game_state *state)
 {
     char *ret, *p;
     int x, y, maxlen;
@@ -1052,7 +1058,7 @@ struct game_ui {
     int xsel, ysel, displaysel;
 };
 
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
 {
     game_ui *ui = snew(game_ui);
 
@@ -1072,16 +1078,16 @@ static void free_ui(game_ui *ui)
     sfree(ui);
 }
 
-static char *encode_ui(game_ui *ui)
+static char *encode_ui(const game_ui *ui)
 {
     return NULL;
 }
 
-static void decode_ui(game_ui *ui, char *encoding)
+static void decode_ui(game_ui *ui, const char *encoding)
 {
 }
 
-static void sel_clear(game_ui *ui, game_state *state)
+static void sel_clear(game_ui *ui, const game_state *state)
 {
     int i;
 
@@ -1091,8 +1097,8 @@ static void sel_clear(game_ui *ui, game_state *state)
 }
 
 
-static void game_changed_state(game_ui *ui, game_state *oldstate,
-                               game_state *newstate)
+static void game_changed_state(game_ui *ui, const game_state *oldstate,
+                               const game_state *newstate)
 {
     sel_clear(ui, newstate);
 
@@ -1105,7 +1111,7 @@ static void game_changed_state(game_ui *ui, game_state *oldstate,
        ui->displaysel = 0;
 }
 
-static char *sel_movedesc(game_ui *ui, game_state *state)
+static char *sel_movedesc(game_ui *ui, const game_state *state)
 {
     int i;
     char *ret, *sep, buf[80];
@@ -1121,7 +1127,7 @@ static char *sel_movedesc(game_ui *ui, game_state *state)
        if (ui->tiles[i] & TILE_SELECTED) {
            sprintf(buf, "%s%d", sep, i);
            sep = ",";
-           if (retlen + strlen(buf) >= retsize) {
+           if (retlen + (int)strlen(buf) >= retsize) {
                retsize = retlen + strlen(buf) + 256;
                ret = sresize(ret, retsize, char);
            }
@@ -1138,7 +1144,7 @@ static char *sel_movedesc(game_ui *ui, game_state *state)
     return sresize(ret, retlen, char);
 }
 
-static void sel_expand(game_ui *ui, game_state *state, int tx, int ty)
+static void sel_expand(game_ui *ui, const game_state *state, int tx, int ty)
 {
     int ns = 1, nadded, x, y, c;
 
@@ -1262,8 +1268,9 @@ struct game_drawstate {
     int *tiles; /* contains colour and SELECTED. */
 };
 
-static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
-                           int x, int y, int button)
+static char *interpret_move(const game_state *state, game_ui *ui,
+                            const game_drawstate *ds,
+                            int x, int y, int button)
 {
     int tx, ty;
     char *ret = "";
@@ -1272,8 +1279,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
 
     if (button == RIGHT_BUTTON || button == LEFT_BUTTON) {
        tx = FROMCOORD(x); ty= FROMCOORD(y);
-    } else if (button == CURSOR_UP || button == CURSOR_DOWN ||
-              button == CURSOR_LEFT || button == CURSOR_RIGHT) {
+    } else if (IS_CURSOR_MOVE(button)) {
        int dx = 0, dy = 0;
        ui->displaysel = 1;
        dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0);
@@ -1281,8 +1287,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
        ui->xsel = (ui->xsel + state->params.w + dx) % state->params.w;
        ui->ysel = (ui->ysel + state->params.h + dy) % state->params.h;
        return ret;
-    } else if (button == CURSOR_SELECT || button == ' ' || button == '\r' ||
-              button == '\n') {
+    } else if (IS_CURSOR_SELECT(button)) {
        ui->displaysel = 1;
        tx = ui->xsel;
        ty = ui->ysel;
@@ -1294,7 +1299,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
     if (COL(state, tx, ty) == 0) return NULL;
 
     if (ISSEL(ui,tx,ty)) {
-       if (button == RIGHT_BUTTON)
+       if (button == RIGHT_BUTTON || button == CURSOR_SELECT2)
            sel_clear(ui, state);
        else
            ret = sel_movedesc(ui, state);
@@ -1306,7 +1311,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
     return ret;
 }
 
-static game_state *execute_move(game_state *from, char *move)
+static game_state *execute_move(const game_state *from, const char *move)
 {
     int i, n;
     game_state *ret;
@@ -1344,25 +1349,25 @@ static game_state *execute_move(game_state *from, char *move)
  * Drawing routines.
  */
 
-static void game_set_size(game_drawstate *ds, game_params *params,
-                         int tilesize)
+static void game_set_size(drawing *dr, game_drawstate *ds,
+                          const game_params *params, int tilesize)
 {
     ds->tilegap = 2;
     ds->tileinner = tilesize - ds->tilegap;
 }
 
-static void game_compute_size(game_params *params, int tilesize,
-                             int *x, int *y)
+static void game_compute_size(const game_params *params, int tilesize,
+                              int *x, int *y)
 {
     /* Ick: fake up tile size variables for macro expansion purposes */
     game_drawstate ads, *ds = &ads;
-    game_set_size(ds, params, tilesize);
+    game_set_size(NULL, ds, params, tilesize);
 
     *x = TILE_SIZE * params->w + 2 * BORDER - TILE_GAP;
     *y = TILE_SIZE * params->h + 2 * BORDER - TILE_GAP;
 }
 
-static float *game_colours(frontend *fe, game_state *state, int *ncolours)
+static float *game_colours(frontend *fe, int *ncolours)
 {
     float *ret = snewn(3 * NCOLOURS, float);
 
@@ -1416,15 +1421,15 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours)
     ret[COL_HIGHLIGHT * 3 + 1] = 1.0F;
     ret[COL_HIGHLIGHT * 3 + 2] = 1.0F;
 
-    ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0 / 3.0;
-    ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0 / 3.0;
-    ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0 / 3.0;
+    ret[COL_LOWLIGHT * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] * 2.0F / 3.0F;
+    ret[COL_LOWLIGHT * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] * 2.0F / 3.0F;
+    ret[COL_LOWLIGHT * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] * 2.0F / 3.0F;
 
     *ncolours = NCOLOURS;
     return ret;
 }
 
-static game_drawstate *game_new_drawstate(game_state *state)
+static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
 {
     struct game_drawstate *ds = snew(struct game_drawstate);
     int i;
@@ -1439,7 +1444,7 @@ static game_drawstate *game_new_drawstate(game_state *state)
     return ds;
 }
 
-static void game_free_drawstate(game_drawstate *ds)
+static void game_free_drawstate(drawing *dr, game_drawstate *ds)
 {
     sfree(ds->tiles);
     sfree(ds);
@@ -1451,7 +1456,7 @@ static void game_free_drawstate(game_drawstate *ds)
  * both then we fill the teeny tiny square in the corner as well.
  */
 
-static void tile_redraw(frontend *fe, game_drawstate *ds,
+static void tile_redraw(drawing *dr, game_drawstate *ds,
                        int x, int y, int dright, int dbelow,
                         int tile, int bgcolour)
 {
@@ -1468,35 +1473,36 @@ static void tile_redraw(frontend *fe, game_drawstate *ds,
            outer = inner = col;
        }
     }
-    draw_rect(fe, COORD(x), COORD(y), TILE_INNER, TILE_INNER, outer);
-    draw_rect(fe, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4,
+    draw_rect(dr, COORD(x), COORD(y), TILE_INNER, TILE_INNER, outer);
+    draw_rect(dr, COORD(x)+TILE_INNER/4, COORD(y)+TILE_INNER/4,
              TILE_INNER/2, TILE_INNER/2, inner);
 
     if (dright)
-       draw_rect(fe, COORD(x)+TILE_INNER, COORD(y), TILE_GAP, TILE_INNER,
+       draw_rect(dr, COORD(x)+TILE_INNER, COORD(y), TILE_GAP, TILE_INNER,
                  (tile & TILE_JOINRIGHT) ? outer : bgcolour);
     if (dbelow)
-       draw_rect(fe, COORD(x), COORD(y)+TILE_INNER, TILE_INNER, TILE_GAP,
+       draw_rect(dr, COORD(x), COORD(y)+TILE_INNER, TILE_INNER, TILE_GAP,
                  (tile & TILE_JOINDOWN) ? outer : bgcolour);
     if (dright && dbelow)
-       draw_rect(fe, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, TILE_GAP, TILE_GAP,
+       draw_rect(dr, COORD(x)+TILE_INNER, COORD(y)+TILE_INNER, TILE_GAP, TILE_GAP,
                  (tile & TILE_JOINDIAG) ? outer : bgcolour);
 
     if (tile & TILE_HASSEL) {
        int sx = COORD(x)+2, sy = COORD(y)+2, ssz = TILE_INNER-5;
        int scol = (outer == COL_SEL) ? COL_LOWLIGHT : COL_HIGHLIGHT;
-       draw_line(fe, sx,     sy,     sx+ssz, sy,     scol);
-       draw_line(fe, sx+ssz, sy,     sx+ssz, sy+ssz, scol);
-       draw_line(fe, sx+ssz, sy+ssz, sx,     sy+ssz, scol);
-       draw_line(fe, sx,     sy+ssz, sx,     sy,     scol);
+       draw_line(dr, sx,     sy,     sx+ssz, sy,     scol);
+       draw_line(dr, sx+ssz, sy,     sx+ssz, sy+ssz, scol);
+       draw_line(dr, sx+ssz, sy+ssz, sx,     sy+ssz, scol);
+       draw_line(dr, sx,     sy+ssz, sx,     sy,     scol);
     }
 
-    draw_update(fe, COORD(x), COORD(y), TILE_SIZE, TILE_SIZE);
+    draw_update(dr, COORD(x), COORD(y), TILE_SIZE, TILE_SIZE);
 }
 
-static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
-                       game_state *state, int dir, game_ui *ui,
-                       float animtime, float flashtime)
+static void game_redraw(drawing *dr, game_drawstate *ds,
+                        const game_state *oldstate, const game_state *state,
+                        int dir, const game_ui *ui,
+                        float animtime, float flashtime)
 {
     int bgcolour, x, y;
 
@@ -1505,10 +1511,10 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
     if (!ds->started) {
        int coords[10];
 
-       draw_rect(fe, 0, 0,
+       draw_rect(dr, 0, 0,
                  TILE_SIZE * state->params.w + 2 * BORDER,
                  TILE_SIZE * state->params.h + 2 * BORDER, COL_BACKGROUND);
-       draw_update(fe, 0, 0,
+       draw_update(dr, 0, 0,
                    TILE_SIZE * state->params.w + 2 * BORDER,
                    TILE_SIZE * state->params.h + 2 * BORDER);
 
@@ -1525,11 +1531,11 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
        coords[9] = COORD(state->params.h) + HIGHLIGHT_WIDTH - 1 - TILE_GAP;
        coords[6] = coords[8] + TILE_SIZE;
        coords[7] = coords[9] - TILE_SIZE;
-       draw_polygon(fe, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
+       draw_polygon(dr, coords, 5, COL_HIGHLIGHT, COL_HIGHLIGHT);
 
        coords[1] = COORD(0) - HIGHLIGHT_WIDTH;
        coords[0] = COORD(0) - HIGHLIGHT_WIDTH;
-       draw_polygon(fe, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
+       draw_polygon(dr, coords, 5, COL_LOWLIGHT, COL_LOWLIGHT);
 
        ds->started = 1;
     }
@@ -1567,7 +1573,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
            if ((oldstate && COL(oldstate,x,y) != col) ||
                (ds->bgcolour != bgcolour) ||
                (tile != ds->tiles[i])) {
-               tile_redraw(fe, ds, x, y, dright, dbelow, tile, bgcolour);
+               tile_redraw(dr, ds, x, y, dright, dbelow, tile, bgcolour);
                ds->tiles[i] = tile;
            }
        }
@@ -1588,18 +1594,18 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
                    score, ui->nselected, npoints(&state->params, ui->nselected));
        else
            sprintf(status, "%s", score);
-       status_bar(fe, status);
+       status_bar(dr, status);
     }
 }
 
-static float game_anim_length(game_state *oldstate, game_state *newstate,
-                             int dir, game_ui *ui)
+static float game_anim_length(const game_state *oldstate,
+                              const game_state *newstate, int dir, game_ui *ui)
 {
     return 0.0F;
 }
 
-static float game_flash_length(game_state *oldstate, game_state *newstate,
-                              int dir, game_ui *ui)
+static float game_flash_length(const game_state *oldstate,
+                               const game_state *newstate, int dir, game_ui *ui)
 {
     if ((!oldstate->complete && newstate->complete) ||
         (!oldstate->impossible && newstate->impossible))
@@ -1608,22 +1614,34 @@ static float game_flash_length(game_state *oldstate, game_state *newstate,
        return 0.0F;
 }
 
-static int game_wants_statusbar(void)
+static int game_status(const game_state *state)
 {
-    return TRUE;
+    /*
+     * Dead-end situations are assumed to be rescuable by Undo, so we
+     * don't bother to identify them and return -1.
+     */
+    return state->complete ? +1 : 0;
 }
 
-static int game_timing_state(game_state *state, game_ui *ui)
+static int 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(drawing *dr, const game_state *state, int tilesize)
+{
+}
+
 #ifdef COMBINED
 #define thegame samegame
 #endif
 
 const struct game thegame = {
-    "Same Game", "games.samegame",
+    "Same Game", "games.samegame", "samegame",
     default_params,
     game_fetch_preset,
     decode_params,
@@ -1638,7 +1656,7 @@ const struct game thegame = {
     dup_game,
     free_game,
     FALSE, solve_game,
-    TRUE, game_text_format,
+    TRUE, game_can_format_as_text_now, game_text_format,
     new_ui,
     free_ui,
     encode_ui,
@@ -1653,7 +1671,9 @@ const struct game thegame = {
     game_redraw,
     game_anim_length,
     game_flash_length,
-    game_wants_statusbar,
+    game_status,
+    FALSE, FALSE, game_print_size, game_print,
+    TRUE,                             /* wants_statusbar */
     FALSE, game_timing_state,
-    0,                                /* mouse_priorities */
+    0,                                /* flags */
 };