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();
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;
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
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
}
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++;
* 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);
* 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,
* 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 */
}
}
+/*
+ * 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) {
me->flash_pos = me->flash_time = 0;
}
- midend_redraw(me);
+ if (need_redraw)
+ midend_redraw(me);
if (me->timing) {
float oldelapsed = me->elapsed;
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;
}
}
- if (me->nstates == 0)
- me->ourgame->free_game(state);
-
return ret;
}
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)
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);
* 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;
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,