shithub: puzzles

Download patch

ref: d396382abd7a00e64d45894d06cdeeb668b3808e
parent: 64e6afdeedcf3f22282524ebd36e3393736fed65
author: Simon Tatham <anakin@pobox.com>
date: Wed Apr 28 14:43:50 EDT 2004

Add a new game concept called a `flash'. This is a graphical effect
taking non-zero time, which is triggered by the making of a move and
is _not_ hurried to its conclusion by the start of the next move (so
the game redraw function is expected to be able to draw it in
parallel with continuing moves). The only thing that prematurely
terminates a flash is the start of a fresh flash. In particular,
this concept is used to display the completion flash in Net, because
at least _my_ playing instincts make me lock every piece I've
unambiguously placed, and hence the last turn move is instantly
followed by a lock move which was previously suppressing the
completion flash.

[originally from svn r4168]

--- a/cube.c
+++ b/cube.c
@@ -1206,7 +1206,7 @@
 }
 
 void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
-                 game_state *state, float animtime)
+                 game_state *state, float animtime, float flashtime)
 {
     int i, j;
     struct bbox bb = find_bbox(&state->params);
@@ -1354,4 +1354,9 @@
 float game_anim_length(game_state *oldstate, game_state *newstate)
 {
     return ROLLTIME;
+}
+
+float game_flash_length(game_state *oldstate, game_state *newstate)
+{
+    return 0.0F;
 }
--- a/midend.c
+++ b/midend.c
@@ -24,6 +24,7 @@
     game_drawstate *drawstate;
     game_state *oldstate;
     float anim_time, anim_pos;
+    float flash_time, flash_pos;
 };
 
 #define ensure(me) do { \
@@ -47,6 +48,8 @@
     me->presets = NULL;
     me->preset_names = NULL;
     me->npresets = me->presetsize = 0;
+    me->anim_time = me->anim_pos = 0.0F;
+    me->flash_time = me->flash_pos = 0.0F;
 
     return me;
 }
@@ -117,6 +120,31 @@
         return 0;
 }
 
+static void midend_finish_move(midend_data *me)
+{
+    float flashtime;
+
+    if (me->oldstate || me->statepos > 1) {
+	flashtime = game_flash_length(me->oldstate ? me->oldstate :
+				      me->states[me->statepos-2],
+				      me->states[me->statepos-1]);
+	if (flashtime > 0) {
+	    me->flash_pos = 0.0F;
+	    me->flash_time = flashtime;
+	}
+    }
+
+    if (me->oldstate)
+	free_game(me->oldstate);
+    me->oldstate = NULL;
+    me->anim_pos = me->anim_time = 0;
+
+    if (me->flash_time == 0 && me->anim_time == 0)
+	deactivate_timer(me->frontend);
+    else
+	activate_timer(me->frontend);
+}
+
 int midend_process_key(midend_data *me, int x, int y, int button)
 {
     game_state *oldstate = dup_game(me->states[me->statepos - 1]);
@@ -123,11 +151,7 @@
     float anim_time;
 
     if (me->oldstate || me->anim_time) {
-        if (me->oldstate)
-            free_game(me->oldstate);
-        me->oldstate = NULL;
-        me->anim_pos = me->anim_time = 0;
-        deactivate_timer(me->frontend);
+	midend_finish_move(me);
         midend_redraw(me);
     }
 
@@ -169,13 +193,12 @@
      */
     anim_time = game_anim_length(oldstate, me->states[me->statepos-1]);
 
+    me->oldstate = oldstate;
     if (anim_time > 0) {
-        me->oldstate = oldstate;
         me->anim_time = anim_time;
     } else {
-        free_game(oldstate);
-        me->oldstate = NULL;
         me->anim_time = 0.0;
+	midend_finish_move(me);
     }
     me->anim_pos = 0.0;
 
@@ -193,10 +216,11 @@
         if (me->oldstate && me->anim_time > 0 &&
             me->anim_pos < me->anim_time) {
             game_redraw(me->frontend, me->drawstate, me->oldstate,
-                        me->states[me->statepos-1], me->anim_pos);
+                        me->states[me->statepos-1], me->anim_pos,
+			me->flash_pos);
         } else {
             game_redraw(me->frontend, me->drawstate, NULL,
-                        me->states[me->statepos-1], 0.0);
+                        me->states[me->statepos-1], 0.0, me->flash_pos);
         }
         end_draw(me->frontend);
     }
@@ -207,12 +231,15 @@
     me->anim_pos += tplus;
     if (me->anim_pos >= me->anim_time ||
         me->anim_time == 0 || !me->oldstate) {
-        if (me->oldstate)
-            free_game(me->oldstate);
-        me->oldstate = NULL;
-        me->anim_pos = me->anim_time = 0;
-        deactivate_timer(me->frontend);
+	if (me->anim_time > 0)
+	    midend_finish_move(me);
     }
+    me->flash_pos += tplus;
+    if (me->flash_pos >= me->flash_time || me->flash_time == 0) {
+	me->flash_pos = me->flash_time = 0;
+    }
+    if (me->flash_time == 0 && me->anim_time == 0)
+	deactivate_timer(me->frontend);
     midend_redraw(me);
 }
 
--- a/net.c
+++ b/net.c
@@ -1060,7 +1060,7 @@
 }
 
 void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
-                 game_state *state, float t)
+                 game_state *state, float t, float ft)
 {
     int x, y, tx, ty, frame;
     unsigned char *active;
@@ -1118,7 +1118,6 @@
     }
 
     tx = ty = -1;
-    frame = -1;
     if (oldstate && (t < ROTATE_TIME)) {
         /*
          * We're animating a tile rotation. Find the turning tile,
@@ -1140,12 +1139,15 @@
                 angle = state->last_rotate_dir * -90.0F * (t / ROTATE_TIME);
             state = oldstate;
         }
-    } else if (t > ROTATE_TIME) {
+    }
+    
+    frame = -1;
+    if (ft > 0) {
         /*
          * We're animating a completion flash. Find which frame
          * we're at.
          */
-        frame = (int)((t - ROTATE_TIME) / FLASH_FRAME);
+        frame = (int)(ft / FLASH_FRAME);
     }
 
     /*
@@ -1192,7 +1194,6 @@
 
 float game_anim_length(game_state *oldstate, game_state *newstate)
 {
-    float ret = 0.0F;
     int x, y;
 
     /*
@@ -1202,14 +1203,17 @@
     for (x = 0; x < oldstate->width; x++)
         for (y = 0; y < oldstate->height; y++)
             if ((tile(oldstate, x, y) ^ tile(newstate, x, y)) & 0xF) {
-                ret = ROTATE_TIME;
-                goto break_label;      /* leave both loops at once */
+                return ROTATE_TIME;
             }
-    break_label:
 
+    return 0.0F;
+}
+
+float game_flash_length(game_state *oldstate, game_state *newstate)
+{
     /*
-     * Also, if the game has just been completed, allow time for a
-     * completion flash.
+     * If the game has just been completed, we display a completion
+     * flash.
      */
     if (!oldstate->completed && newstate->completed) {
         int size;
@@ -1222,8 +1226,8 @@
             size = newstate->width - newstate->cx;
         if (size < newstate->height - newstate->cy)
             size = newstate->height - newstate->cy;
-        ret += FLASH_FRAME * (size+4);
+        return FLASH_FRAME * (size+4);
     }
 
-    return ret;
+    return 0.0F;
 }
--- a/puzzles.h
+++ b/puzzles.h
@@ -108,7 +108,8 @@
 game_drawstate *game_new_drawstate(game_state *state);
 void game_free_drawstate(game_drawstate *ds);
 void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate,
-                 game_state *newstate, float t);
+                 game_state *newstate, float anim_time, float flash_time);
 float game_anim_length(game_state *oldstate, game_state *newstate);
+float game_flash_length(game_state *oldstate, game_state *newstate);
 
 #endif /* PUZZLES_PUZZLES_H */