shithub: puzzles

Download patch

ref: 425942c852f22d7d94f7643696522d32c0b02067
parent: 99d3c31e12ac5bb7c12d2b7a59c702cb671e9b62
author: Ben Harris <bjh21@bjh21.me.uk>
date: Tue Dec 27 12:26:42 EST 2022

Fancier completion flash for Tracks

It now runs along the track from A to B, spending the first half of
FLASH_TIME lighting all the segments and the second half extinguishing
them.

--- a/tracks.c
+++ b/tracks.c
@@ -242,6 +242,7 @@
 #define S_CLUE 8
 #define S_MARK 16
 
+#define S_FLASH_SHIFT   8  /* Position of tile in solved track, 8 bits */
 #define S_TRACK_SHIFT   16 /* U/D/L/R flags for edge track indicators */
 #define S_NOTRACK_SHIFT 20 /* U/D/L/R flags for edge no-track indicators */
 
@@ -1820,6 +1821,29 @@
         return -1;
 }
 
+/*
+ * The completion flash moves along the track, so we want to label
+ * each tile with how far along the track it is.  This is represented
+ * as an eight-bit field, which is more than enough when the
+ * completion flash is only 0.5 s long.
+ */
+static void set_flash_data(game_state *state)
+{
+    int ntrack = 0, x, y, n, d;
+    const int w = state->p.w;
+
+    for (x = 0; x < w; x++)
+        ntrack += state->numbers->numbers[x];
+    n = 0; x = 0; y = state->numbers->row_s; d = R;
+    do {
+        /* Don't bother clearing; this only runs at completion. */
+        state->sflags[y*w + x] |= (n++ * 255 / (ntrack - 1)) << S_FLASH_SHIFT;
+        d = F(d); /* Find the direction we just arrived from. */
+        d = S_E_DIRS(state, x, y, E_TRACK) & ~d; /* Other track from here. */
+        x += DX(d); y += DY(d); /* Move to the next tile. */
+    } while (INGRID(state, x, y));
+}
+
 static bool check_completion(game_state *state, bool mark)
 {
     int w = state->p.w, h = state->p.h, x, y, i, target;
@@ -1961,8 +1985,10 @@
             ret = false;
     }
 
-    if (mark)
+    if (mark) {
         state->completed = ret;
+        if (ret) set_flash_data(state);
+    }
     sfree(dsf);
     return ret;
 }
@@ -2829,7 +2855,7 @@
                         const game_state *state, int dir, const game_ui *ui,
                         float animtime, float flashtime)
 {
-    int i, x, y, flashing = 0, w = ds->w, h = ds->h;
+    int i, x, y, flashing, w = ds->w, h = ds->h;
     bool force = false;
     game_state *drag_state = NULL;
 
@@ -2855,11 +2881,6 @@
         }
     }
 
-    if (flashtime > 0 &&
-            (flashtime <= FLASH_TIME/3 ||
-             flashtime >= FLASH_TIME*2/3))
-        flashing = DS_FLASH;
-
     if (ui->dragging)
         drag_state = copy_and_apply_drag(state, ui);
 
@@ -2866,6 +2887,15 @@
     for (x = 0; x < w; x++) {
         for (y = 0; y < h; y++) {
             unsigned int f, f_d;
+
+            flashing = 0;
+            if (flashtime > 0) {
+                float flashpos =
+                    (state->sflags[y*w+x] >> S_FLASH_SHIFT & 0xff) / 255.0F;
+                if (flashtime > FLASH_TIME / 2 * flashpos &&
+                    flashtime <= FLASH_TIME / 2 * (flashpos + 1.0F))
+                    flashing = DS_FLASH;
+            }
 
             f = s2d_flags(state, x, y, ui) | flashing;
             f_d = drag_state ? s2d_flags(drag_state, x, y, ui) : f;