chiark / gitweb /
Fix completion checking in Killer Solo.
[sgt-puzzles.git] / untangle.c
index 3d0918aa3a3e18dfcdec7c072d4bb0370ed652b0..49366b16b7999f7bd8c735315c13bd4700aef9a0 100644 (file)
 
 /*
  * TODO:
- * 
- *  - Any way we can speed up redraws on GTK? Uck.
- * 
+ *
+ *  - This puzzle, perhaps uniquely among the collection, could use
+ *    support for non-aspect-ratio-preserving resizes. This would
+ *    require some sort of fairly large redesign, unfortunately (since
+ *    it would invalidate the basic assumption that puzzles' size
+ *    requirements are adequately expressed by a single scalar tile
+ *    size), and probably complicate the rest of the puzzles' API as a
+ *    result. So I'm not sure I really want to do it.
+ *
  *  - It would be nice if we could somehow auto-detect a real `long
  *    long' type on the host platform and use it in place of my
  *    hand-hacked int64s. It'd be faster and more reliable.
@@ -39,6 +45,7 @@
 #define SOLVEANIM_TIME 0.50F
 
 enum {
+    COL_SYSBACKGROUND,
     COL_BACKGROUND,
     COL_LINE,
 #ifdef SHOW_CROSSINGS
@@ -147,7 +154,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 */
@@ -159,7 +166,7 @@ static void decode_params(game_params *params, char const *string)
     params->n = atoi(string);
 }
 
-static char *encode_params(game_params *params, int full)
+static char *encode_params(const game_params *params, int full)
 {
     char buf[80];
 
@@ -168,7 +175,7 @@ static char *encode_params(game_params *params, int full)
     return dupstr(buf);
 }
 
-static config_item *game_configure(game_params *params)
+static config_item *game_configure(const game_params *params)
 {
     config_item *ret;
     char buf[80];
@@ -189,7 +196,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);
 
@@ -198,7 +205,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->n < 4)
         return "Number of points must be at least four";
@@ -484,7 +491,7 @@ static void make_circle(point *pts, int n, int w)
     }
 }
 
-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)
 {
     int n = params->n, i;
@@ -727,7 +734,7 @@ 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 a, b;
 
@@ -796,7 +803,8 @@ static void mark_crossings(game_state *state)
        state->completed = TRUE;
 }
 
-static game_state *new_game(midend *me, game_params *params, char *desc)
+static game_state *new_game(midend *me, const game_params *params,
+                            const char *desc)
 {
     int n = params->n;
     game_state *state = snew(game_state);
@@ -835,7 +843,7 @@ static game_state *new_game(midend *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)
 {
     int n = state->params.n;
     game_state *ret = snew(game_state);
@@ -872,8 +880,8 @@ 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)
 {
     int n = state->params.n;
     int matrix[4];
@@ -1000,8 +1008,8 @@ static char *solve_game(game_state *state, game_state *currstate,
         pts[i].d = 2;
         ox *= pts[i].d;
         oy *= pts[i].d;
-        pts[i].x = ox + 0.5;
-        pts[i].y = oy + 0.5;
+        pts[i].x = (long)(ox + 0.5F);
+        pts[i].y = (long)(oy + 0.5F);
 
         extra = sprintf(buf, ";P%d:%ld,%ld/%ld", i,
                         pts[i].x, pts[i].y, pts[i].d);
@@ -1018,7 +1026,12 @@ static char *solve_game(game_state *state, game_state *currstate,
     return ret;
 }
 
-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)
 {
     return NULL;
 }
@@ -1031,7 +1044,7 @@ struct game_ui {
     float anim_length;
 };
 
-static game_ui *new_ui(game_state *state)
+static game_ui *new_ui(const game_state *state)
 {
     game_ui *ui = snew(game_ui);
     ui->dragpoint = -1;
@@ -1044,17 +1057,17 @@ 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 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)
 {
     ui->dragpoint = -1;
     ui->just_moved = ui->just_dragged;
@@ -1067,12 +1080,13 @@ struct game_drawstate {
     long *x, *y;
 };
 
-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 n = state->params.n;
 
-    if (button == LEFT_BUTTON) {
+    if (IS_MOUSE_DOWN(button)) {
        int i, best;
         long bestd;
 
@@ -1106,12 +1120,12 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
            return "";
        }
 
-    } else if (button == LEFT_DRAG && ui->dragpoint >= 0) {
+    } else if (IS_MOUSE_DRAG(button) && ui->dragpoint >= 0) {
        ui->newpoint.x = x;
        ui->newpoint.y = y;
        ui->newpoint.d = ds->tilesize;
        return "";
-    } else if (button == LEFT_RELEASE && ui->dragpoint >= 0) {
+    } else if (IS_MOUSE_RELEASE(button) && ui->dragpoint >= 0) {
        int p = ui->dragpoint;
        char buf[80];
 
@@ -1140,7 +1154,7 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
     return NULL;
 }
 
-static game_state *execute_move(game_state *state, char *move)
+static game_state *execute_move(const game_state *state, const char *move)
 {
     int n = state->params.n;
     int p, k;
@@ -1179,23 +1193,31 @@ static game_state *execute_move(game_state *state, char *move)
  * Drawing routines.
  */
 
-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)
 {
     *x = *y = COORDLIMIT(params->n) * tilesize;
 }
 
 static void game_set_size(drawing *dr, game_drawstate *ds,
-                         game_params *params, int tilesize)
+                          const game_params *params, int tilesize)
 {
     ds->tilesize = tilesize;
 }
 
-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);
 
-    frontend_default_colour(fe, &ret[COL_BACKGROUND * 3]);
+    /*
+     * COL_BACKGROUND is what we use as the normal background colour.
+     * Unusually, though, it isn't colour #0: COL_SYSBACKGROUND, a bit
+     * darker, takes that place. This means that if the user resizes
+     * an Untangle window so as to change its aspect ratio, the
+     * still-square playable area will be distinguished from the dead
+     * space around it.
+     */
+    game_mkhighlight(fe, ret, COL_BACKGROUND, -1, COL_SYSBACKGROUND);
 
     ret[COL_LINE * 3 + 0] = 0.0F;
     ret[COL_LINE * 3 + 1] = 0.0F;
@@ -1235,7 +1257,7 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours)
     return ret;
 }
 
-static game_drawstate *game_new_drawstate(drawing *dr, 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;
@@ -1263,15 +1285,16 @@ static point mix(point a, point b, float distance)
     point ret;
 
     ret.d = a.d * b.d;
-    ret.x = a.x * b.d + distance * (b.x * a.d - a.x * b.d);
-    ret.y = a.y * b.d + distance * (b.y * a.d - a.y * b.d);
+    ret.x = (long)(a.x * b.d + distance * (b.x * a.d - a.x * b.d));
+    ret.y = (long)(a.y * b.d + distance * (b.y * a.d - a.y * b.d));
 
     return ret;
 }
 
-static void game_redraw(drawing *dr, 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 w, h;
     edge *e;
@@ -1386,8 +1409,8 @@ static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate,
     draw_update(dr, 0, 0, w, h);
 }
 
-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)
 {
     if (ui->just_moved)
        return 0.0F;
@@ -1398,8 +1421,8 @@ static float game_anim_length(game_state *oldstate, game_state *newstate,
     return ui->anim_length;
 }
 
-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->completed && newstate->completed &&
        !oldstate->cheated && !newstate->cheated)
@@ -1407,21 +1430,21 @@ 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 FALSE;
+    return state->completed ? +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(game_params *params, float *x, float *y)
+static void game_print_size(const game_params *params, float *x, float *y)
 {
 }
 
-static void game_print(drawing *dr, game_state *state, int tilesize)
+static void game_print(drawing *dr, const game_state *state, int tilesize)
 {
 }
 
@@ -1430,7 +1453,7 @@ static void game_print(drawing *dr, game_state *state, int tilesize)
 #endif
 
 const struct game thegame = {
-    "Untangle", "games.untangle",
+    "Untangle", "games.untangle", "untangle",
     default_params,
     game_fetch_preset,
     decode_params,
@@ -1445,7 +1468,7 @@ const struct game thegame = {
     dup_game,
     free_game,
     TRUE, solve_game,
-    FALSE, game_text_format,
+    FALSE, game_can_format_as_text_now, game_text_format,
     new_ui,
     free_ui,
     encode_ui,
@@ -1460,8 +1483,9 @@ const struct game thegame = {
     game_redraw,
     game_anim_length,
     game_flash_length,
+    game_status,
     FALSE, FALSE, game_print_size, game_print,
-    game_wants_statusbar,
+    FALSE,                            /* wants_statusbar */
     FALSE, game_timing_state,
     SOLVE_ANIMATES,                   /* flags */
 };