int pressed_mouse_button;
- int winwidth, winheight;
+ int tilesize, winwidth, winheight;
};
#define ensure(me) do { \
me->laststatus = NULL;
me->timing = FALSE;
me->elapsed = 0.0F;
- me->winwidth = me->winheight = 0;
+ me->tilesize = me->winwidth = me->winheight = 0;
sfree(randseed);
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)
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)
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);
}
me->ourgame->dup_game(me->states[me->statepos - 1].state);
int special = FALSE, gotspecial = FALSE, ret = 1;
float anim_time;
+ game_state *s;
+ char *movestr;
+
+ movestr =
+ me->ourgame->interpret_move(me->states[me->statepos-1].state,
+ me->ui, me->drawstate, x, y, button);
- if (button == 'n' || button == 'N' || button == '\x0E') {
- midend_stop_anim(me);
- midend_new_game(me);
- midend_redraw(me);
- goto done; /* never animate */
- } else if (button == 'u' || button == 'u' ||
- button == '\x1A' || button == '\x1F') {
- midend_stop_anim(me);
- special = special(me->states[me->statepos-1].movetype);
- gotspecial = TRUE;
- if (!midend_undo(me))
+ if (!movestr) {
+ if (button == 'n' || button == 'N' || button == '\x0E') {
+ midend_stop_anim(me);
+ midend_new_game(me);
+ midend_redraw(me);
+ goto done; /* never animate */
+ } else if (button == 'u' || button == 'u' ||
+ button == '\x1A' || button == '\x1F') {
+ midend_stop_anim(me);
+ special = special(me->states[me->statepos-1].movetype);
+ gotspecial = TRUE;
+ if (!midend_undo(me))
+ goto done;
+ } else if (button == 'r' || button == 'R' ||
+ button == '\x12' || button == '\x19') {
+ midend_stop_anim(me);
+ if (!midend_redo(me))
+ goto done;
+ } else if (button == 'q' || button == 'Q' || button == '\x11') {
+ ret = 0;
+ goto done;
+ } else
goto done;
- } else if (button == 'r' || button == 'R' ||
- button == '\x12' || button == '\x19') {
- midend_stop_anim(me);
- if (!midend_redo(me))
- goto done;
- } else if (button == 'q' || button == 'Q' || button == '\x11') {
- ret = 0;
- goto done;
} else {
- game_state *s;
- char *movestr;
-
- movestr =
- me->ourgame->interpret_move(me->states[me->statepos-1].state,
- me->ui, me->drawstate, x, y, button);
- if (!movestr)
- s = NULL;
- else if (!*movestr)
+ if (!*movestr)
s = me->states[me->statepos-1].state;
else {
s = me->ourgame->execute_move(me->states[me->statepos-1].state,
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;
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;
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);
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;