From 425942c852f22d7d94f7643696522d32c0b02067 Mon Sep 17 00:00:00 2001 From: Ben Harris Date: Tue, 27 Dec 2022 17:26:42 +0000 Subject: [PATCH] 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. --- tracks.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/tracks.c b/tracks.c index a57ab0a..2a593c6 100644 --- a/tracks.c +++ b/tracks.c @@ -242,6 +242,7 @@ static const int nbits[] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4 }; #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 @@ static int tracks_neighbour(int vertex, void *vctx) 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 @@ static bool check_completion(game_state *state, bool mark) ret = false; } - if (mark) + if (mark) { state->completed = ret; + if (ret) set_flash_data(state); + } sfree(dsf); return ret; } @@ -2829,7 +2855,7 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst 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 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst } } - 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); @@ -2867,6 +2888,15 @@ static void game_redraw(drawing *dr, game_drawstate *ds, const game_state *oldst 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;