Subtle UI change to Mines. Although I mostly find the unified left-
[sgt/puzzles] / midend.c
index df661b5..691c643 100644 (file)
--- a/midend.c
+++ b/midend.c
@@ -78,7 +78,7 @@ struct midend_data {
 
     int pressed_mouse_button;
 
-    int winwidth, winheight;
+    int tilesize, winwidth, winheight;
 };
 
 #define ensure(me) do { \
@@ -121,7 +121,7 @@ midend_data *midend_new(frontend *fe, const game *ourgame)
     me->laststatus = NULL;
     me->timing = FALSE;
     me->elapsed = 0.0F;
-    me->winwidth = me->winheight = 0;
+    me->tilesize = me->winwidth = me->winheight = 0;
 
     sfree(randseed);
 
@@ -169,11 +169,63 @@ void midend_free(midend_data *me)
     sfree(me);
 }
 
+static void midend_size_new_drawstate(midend_data *me)
+{
+    /*
+     * Don't even bother, if we haven't worked out our tile size
+     * anyway yet.
+     */
+    if (me->tilesize > 0) {
+       me->ourgame->compute_size(me->params, me->tilesize,
+                                 &me->winwidth, &me->winheight);
+       me->ourgame->set_size(me->drawstate, me->params, me->tilesize);
+    }
+}
+
 void midend_size(midend_data *me, int *x, int *y, int expand)
 {
-    me->ourgame->size(me->params, me->drawstate, x, y, expand);
-    me->winwidth = *x;
-    me->winheight = *y;
+    int min, max;
+    int rx, ry;
+
+    /*
+     * Find the tile size that best fits within the given space. If
+     * `expand' is TRUE, we must actually find the _largest_ such
+     * tile size; otherwise, we bound above at the game's preferred
+     * tile size.
+     */
+    if (expand) {
+       max = 1;
+       do {
+           max *= 2;
+           me->ourgame->compute_size(me->params, max, &rx, &ry);
+       } while (rx <= *x && ry <= *y);
+    } else
+       max = me->ourgame->preferred_tilesize + 1;
+    min = 1;
+
+    /*
+     * Now binary-search between min and max. We're looking for a
+     * boundary rather than a value: the point at which tile sizes
+     * stop fitting within the given dimensions. Thus, we stop when
+     * max and min differ by exactly 1.
+     */
+    while (max - min > 1) {
+       int mid = (max + min) / 2;
+       me->ourgame->compute_size(me->params, mid, &rx, &ry);
+       if (rx <= *x && ry <= *y)
+           min = mid;
+       else
+           max = mid;
+    }
+
+    /*
+     * Now `min' is a valid size, and `max' isn't. So use `min'.
+     */
+
+    me->tilesize = min;
+    midend_size_new_drawstate(me);
+    *x = me->winwidth;
+    *y = me->winheight;
 }
 
 void midend_set_params(midend_data *me, game_params *params)
@@ -192,12 +244,6 @@ static void midend_set_timer(midend_data *me)
        deactivate_timer(me->frontend);
 }
 
-static void midend_size_new_drawstate(midend_data *me)
-{
-    me->ourgame->size(me->params, me->drawstate, &me->winwidth, &me->winheight,
-                      TRUE);
-}
-
 void midend_force_redraw(midend_data *me)
 {
     if (me->drawstate)
@@ -335,7 +381,7 @@ static void midend_finish_move(midend_data *me)
 
 void midend_stop_anim(midend_data *me)
 {
-    if (me->oldstate || me->anim_time) {
+    if (me->oldstate || me->anim_time != 0) {
        midend_finish_move(me);
         midend_redraw(me);
     }
@@ -743,7 +789,7 @@ int midend_num_presets(midend_data *me)
                 preset = me->ourgame->default_params();
                 me->ourgame->decode_params(preset, val);
 
-               if (me->ourgame->validate_params(preset)) {
+               if (me->ourgame->validate_params(preset, TRUE)) {
                    /* Drop this one from the list. */
                    me->ourgame->free_params(preset);
                    continue;
@@ -909,7 +955,7 @@ static char *midend_game_id_int(midend_data *me, char *id, int defmode)
     if (par) {
         newcurparams = me->ourgame->dup_params(me->params);
         me->ourgame->decode_params(newcurparams, par);
-        error = me->ourgame->validate_params(newcurparams);
+        error = me->ourgame->validate_params(newcurparams, desc == NULL);
         if (error) {
             me->ourgame->free_params(newcurparams);
             return error;
@@ -1000,7 +1046,7 @@ char *midend_set_config(midend_data *me, int which, config_item *cfg)
     switch (which) {
       case CFG_SETTINGS:
        params = me->ourgame->custom_params(cfg);
-       error = me->ourgame->validate_params(params);
+       error = me->ourgame->validate_params(params, TRUE);
 
        if (error) {
            me->ourgame->free_params(params);
@@ -1304,6 +1350,7 @@ char *midend_deserialise(midend_data *me,
         if (key[8] != ':') {
             if (started)
                 ret = "Data was incorrectly formatted for a saved game file";
+           goto cleanup;
         }
         len = strcspn(key, ": ");
         assert(len <= 8);
@@ -1434,16 +1481,24 @@ char *midend_deserialise(midend_data *me,
 
     params = me->ourgame->default_params();
     me->ourgame->decode_params(params, parstr);
-    if (me->ourgame->validate_params(params)) {
+    if (me->ourgame->validate_params(params, TRUE)) {
         ret = "Long-term parameters in save file are invalid";
         goto cleanup;
     }
     cparams = me->ourgame->default_params();
     me->ourgame->decode_params(cparams, cparstr);
-    if (me->ourgame->validate_params(cparams)) {
+    if (me->ourgame->validate_params(cparams, FALSE)) {
         ret = "Short-term parameters in save file are invalid";
         goto cleanup;
     }
+    if (seed && me->ourgame->validate_params(cparams, TRUE)) {
+        /*
+         * The seed's no use with this version, but we can perfectly
+         * well use the rest of the data.
+         */
+        sfree(seed);
+        seed = NULL;
+    }
     if (!desc) {
         ret = "Game description in save file is missing";
         goto cleanup;