X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/821ab2c68e12d85d6bb2ed8b0d48c846a65d06a0..888050f2206455bfe5f1470dd38e19b6cfc69b65:/midend.c diff --git a/midend.c b/midend.c index 1be8ca9..d0bc950 100644 --- a/midend.c +++ b/midend.c @@ -80,7 +80,7 @@ struct midend { int pressed_mouse_button; - int tilesize, winwidth, winheight; + int preferred_tilesize, tilesize, winwidth, winheight; }; #define ensure(me) do { \ @@ -102,7 +102,7 @@ midend *midend_new(frontend *fe, const game *ourgame, me->frontend = fe; me->ourgame = ourgame; - me->random = random_init(randseed, randseedsize); + me->random = random_new(randseed, randseedsize); me->nstates = me->statesize = me->statepos = 0; me->states = NULL; me->params = ourgame->default_params(); @@ -126,10 +126,30 @@ midend *midend_new(frontend *fe, const game *ourgame, me->elapsed = 0.0F; me->tilesize = me->winwidth = me->winheight = 0; if (drapi) - me->drawing = drawing_init(drapi, drhandle); + me->drawing = drawing_new(drapi, me, drhandle); else me->drawing = NULL; + me->preferred_tilesize = ourgame->preferred_tilesize; + { + /* + * Allow an environment-based override for the default tile + * size by defining a variable along the lines of + * `NET_TILESIZE=15'. + */ + + char buf[80], *e; + int j, k, ts; + + sprintf(buf, "%s_TILESIZE", me->ourgame->name); + for (j = k = 0; buf[j]; j++) + if (!isspace((unsigned char)buf[j])) + buf[k++] = toupper((unsigned char)buf[j]); + buf[k] = '\0'; + if ((e = getenv(buf)) != NULL && sscanf(e, "%d", &ts) == 1 && ts > 0) + me->preferred_tilesize = ts; + } + sfree(randseed); return me; @@ -198,6 +218,17 @@ void midend_size(midend *me, int *x, int *y, int expand) int rx, ry; /* + * We can't set the size on the same drawstate twice. So if + * we've already sized one drawstate, we must throw it away and + * create a new one. + */ + if (me->drawstate && me->tilesize > 0) { + me->ourgame->free_drawstate(me->drawing, me->drawstate); + me->drawstate = me->ourgame->new_drawstate(me->drawing, + me->states[0].state); + } + + /* * 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 @@ -210,7 +241,7 @@ void midend_size(midend *me, int *x, int *y, int expand) me->ourgame->compute_size(me->params, max, &rx, &ry); } while (rx <= *x && ry <= *y); } else - max = me->ourgame->preferred_tilesize + 1; + max = me->preferred_tilesize + 1; min = 1; /* @@ -233,6 +264,8 @@ void midend_size(midend *me, int *x, int *y, int expand) */ me->tilesize = min; + if (expand) + me->preferred_tilesize = me->tilesize; midend_size_new_drawstate(me); *x = me->winwidth; *y = me->winheight; @@ -311,7 +344,7 @@ void midend_new_game(midend *me) sfree(me->aux_info); me->aux_info = NULL; - rs = random_init(me->seedstr, strlen(me->seedstr)); + rs = random_new(me->seedstr, strlen(me->seedstr)); /* * If this midend has been instantiated without providing a * drawing API, it is non-interactive. This means that it's @@ -325,8 +358,24 @@ void midend_new_game(midend *me) } ensure(me); + + /* + * It might seem a bit odd that we're using me->params to + * create the initial game state, rather than me->curparams + * which is better tailored to this specific game and which we + * always know. + * + * It's supposed to be an invariant in the midend that + * me->params and me->curparams differ in no aspect that is + * important after generation (i.e. after new_desc()). By + * deliberately passing the _less_ specific of these two + * parameter sets, we provoke play-time misbehaviour in the + * case where a game has failed to encode a play-time parameter + * in the non-full version of encode_params(). + */ me->states[me->nstates].state = me->ourgame->new_game(me, me->params, me->desc); + me->states[me->nstates].movestr = NULL; me->states[me->nstates].movetype = NEWGAME; me->nstates++; @@ -503,6 +552,7 @@ static int midend_really_process_key(midend *me, int x, int y, int button) * state has been updated and a redraw is called for. */ midend_redraw(me); + midend_set_timer(me); goto done; } else if (s) { midend_stop_anim(me); @@ -531,7 +581,7 @@ static int midend_really_process_key(midend *me, int x, int y, int button) * See if this move requires an animation. */ if (special(type) && !(type == SOLVE && - (me->ourgame->mouse_priorities & SOLVE_ANIMATES))) { + (me->ourgame->flags & SOLVE_ANIMATES))) { anim_time = 0; } else { anim_time = me->ourgame->anim_length(oldstate, @@ -643,7 +693,7 @@ int midend_process_key(midend *me, int x, int y, int button) * If the new button has lower priority than the old one, * don't bother doing this. */ - if (me->ourgame->mouse_priorities & + if (me->ourgame->flags & BUTTON_BEATS(me->pressed_mouse_button, button)) return ret; /* just ignore it */ @@ -692,8 +742,21 @@ void midend_redraw(midend *me) } } +/* + * Nasty hacky function used to implement the --redo option in + * gtk.c. Only used for generating the puzzles' icons. + */ +void midend_freeze_timer(midend *me, float tprop) +{ + me->anim_pos = me->anim_time * tprop; + midend_redraw(me); + deactivate_timer(me->frontend); +} + void midend_timer(midend *me, float tplus) { + int need_redraw = (me->anim_time > 0 || me->flash_time > 0); + me->anim_pos += tplus; if (me->anim_pos >= me->anim_time || me->anim_time == 0 || !me->oldstate) { @@ -706,7 +769,8 @@ void midend_timer(midend *me, float tplus) me->flash_pos = me->flash_time = 0; } - midend_redraw(me); + if (need_redraw) + midend_redraw(me); if (me->timing) { float oldelapsed = me->elapsed; @@ -720,20 +784,9 @@ void midend_timer(midend *me, float tplus) float *midend_colours(midend *me, int *ncolours) { - game_state *state = NULL; float *ret; - if (me->nstates == 0) { - char *aux = NULL; - char *desc = me->ourgame->new_desc(me->params, me->random, - &aux, TRUE); - state = me->ourgame->new_game(me, me->params, desc); - sfree(desc); - sfree(aux); - } else - state = me->states[0].state; - - ret = me->ourgame->colours(me->frontend, state, ncolours); + ret = me->ourgame->colours(me->frontend, ncolours); { int i; @@ -763,9 +816,6 @@ float *midend_colours(midend *me, int *ncolours) } } - if (me->nstates == 0) - me->ourgame->free_game(state); - return ret; } @@ -858,7 +908,7 @@ void midend_fetch_preset(midend *me, int n, int midend_wants_statusbar(midend *me) { - return me->ourgame->wants_statusbar(); + return me->ourgame->wants_statusbar; } void midend_supersede_game_desc(midend *me, char *desc, char *privdesc) @@ -1136,12 +1186,15 @@ char *midend_solve(midend *me) if (me->statepos < 1) return "No game set up to solve"; /* _shouldn't_ happen! */ - msg = "Solve operation failed"; /* game _should_ overwrite on error */ + msg = NULL; movestr = me->ourgame->solve(me->states[0].state, me->states[me->statepos-1].state, me->aux_info, &msg); - if (!movestr) + if (!movestr) { + if (!msg) + msg = "Solve operation failed"; /* _shouldn't_ happen, but can */ return msg; + } s = me->ourgame->execute_move(me->states[me->statepos-1].state, movestr); assert(s); @@ -1149,8 +1202,11 @@ char *midend_solve(midend *me) * Now enter the solved state as the next move. */ midend_stop_anim(me); - while (me->nstates > me->statepos) + while (me->nstates > me->statepos) { me->ourgame->free_game(me->states[--me->nstates].state); + if (me->states[me->nstates].movestr) + sfree(me->states[me->nstates].movestr); + } ensure(me); me->states[me->nstates].state = s; me->states[me->nstates].movestr = movestr; @@ -1161,7 +1217,7 @@ char *midend_solve(midend *me) me->states[me->statepos-2].state, me->states[me->statepos-1].state); me->dir = +1; - if (me->ourgame->mouse_priorities & SOLVE_ANIMATES) { + if (me->ourgame->flags & SOLVE_ANIMATES) { me->oldstate = me->ourgame->dup_game(me->states[me->statepos-2].state); me->anim_time = me->ourgame->anim_length(me->states[me->statepos-2].state,