diff --git a/html/undead.html b/html/undead.html index 5ed976d..c21374f 100644 --- a/html/undead.html +++ b/html/undead.html @@ -17,3 +17,6 @@ press Backspace. Right-click in a square and then type a letter to add or remove the monster as a pencil mark, indicating monsters that you think might go in that square. +

+Left-click on a clue to mark it as done (grey it out). To unmark a +clue as done, left-click on it again. diff --git a/puzzles.but b/puzzles.but index 86caa15..11205f0 100644 --- a/puzzles.but +++ b/puzzles.but @@ -3054,6 +3054,9 @@ If you prefer plain letters of the alphabet to cute monster pictures, you can press \q{A} to toggle between showing the monsters as monsters or showing them as letters. +Left-clicking a clue will mark it as done (grey it out), or unmark it +if it is already marked. + (All the actions described in \k{common-actions} are also available.) \H{undead-parameters} \I{parameters, for Undead}Undead parameters diff --git a/undead.c b/undead.c index d7d5b09..f828ac0 100644 --- a/undead.c +++ b/undead.c @@ -49,6 +49,7 @@ enum { COL_GHOST, COL_ZOMBIE, COL_VAMPIRE, + COL_DONE, NCOLOURS }; @@ -237,6 +238,7 @@ struct game_state { unsigned char *pencils; unsigned char *cell_errors; unsigned char *hint_errors; + unsigned char *hints_done; unsigned char count_errors[3]; int solved; int cheated; @@ -289,6 +291,9 @@ static game_state *new_state(const game_params *params) { state->hint_errors = snewn(2*state->common->num_paths, unsigned char); for (i=0;i<2*state->common->num_paths;i++) state->hint_errors[i] = FALSE; + state->hints_done = snewn(2 * state->common->num_paths, unsigned char); + memset(state->hints_done, 0, + 2 * state->common->num_paths * sizeof(unsigned char)); for (i=0;i<3;i++) state->count_errors[i] = FALSE; @@ -332,6 +337,13 @@ static game_state *dup_game(const game_state *state) } else ret->hint_errors = NULL; + if (state->hints_done != NULL) { + ret->hints_done = snewn(2 * state->common->num_paths, unsigned char); + memcpy(ret->hints_done, state->hints_done, + 2 * state->common->num_paths * sizeof(unsigned char)); + } + else ret->hints_done = NULL; + ret->count_errors[0] = state->count_errors[0]; ret->count_errors[1] = state->count_errors[1]; ret->count_errors[2] = state->count_errors[2]; @@ -358,6 +370,7 @@ static void free_game(game_state *state) { if (state->common->fixed != NULL) sfree(state->common->fixed); sfree(state->common); } + if (state->hints_done != NULL) sfree(state->hints_done); if (state->hint_errors != NULL) sfree(state->hint_errors); if (state->cell_errors != NULL) sfree(state->cell_errors); if (state->pencils != NULL) sfree(state->pencils); @@ -1662,12 +1675,40 @@ struct game_drawstate { unsigned char count_errors[3]; unsigned char *cell_errors; unsigned char *hint_errors; + unsigned char *hints_done; int hx, hy, hshow, hpencil; /* as for game_ui. */ int hflash; int ascii; }; +static int is_clue(const game_state *state, int x, int y) +{ + int h = state->common->params.h, w = state->common->params.w; + + if (((x == 0 || x == w + 1) && y > 0 && y <= h) || + ((y == 0 || y == h + 1) && x > 0 && x <= w)) + return TRUE; + + return FALSE; +} + +static int clue_index(const game_state *state, int x, int y) +{ + int h = state->common->params.h, w = state->common->params.w; + + if (y == 0) + return x - 1; + else if (x == w + 1) + return w + y - 1; + else if (y == h + 1) + return 2 * w + h - x; + else if (x == 0) + return 2 * (w + h) - y; + + return -1; +} + #define TILESIZE (ds->tilesize) #define BORDER (TILESIZE/4) @@ -1818,6 +1859,11 @@ static char *interpret_move(const game_state *state, game_ui *ui, } } } + } else if (button == LEFT_BUTTON) { + if (is_clue(state, gx, gy)) { + sprintf(buf, "D%d,%d", gx, gy); + return dupstr(buf); + } } return NULL; @@ -1942,7 +1988,7 @@ int check_path_solution(game_state *state, int p) { static game_state *execute_move(const game_state *state, const char *move) { - int x,n,p,i; + int x,y,n,p,i; char c; int correct; int solver; @@ -1969,6 +2015,11 @@ static game_state *execute_move(const game_state *state, const char *move) if (c == 'z') ret->pencils[x] ^= 4; move += n; } + if (c == 'D' && sscanf(move + 1, "%d,%d%n", &x, &y, &n) == 2 && + is_clue(ret, x, y)) { + ret->hints_done[clue_index(ret, x, y)] ^= 1; + move += n + 1; + } if (*move == ';') move++; } @@ -2058,6 +2109,10 @@ static float *game_colours(frontend *fe, int *ncolours) ret[COL_VAMPIRE * 3 + 1] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; ret[COL_VAMPIRE * 3 + 2] = ret[COL_BACKGROUND * 3 + 0] * 0.9F; + ret[COL_DONE * 3 + 0] = ret[COL_BACKGROUND * 3 + 0] / 1.5F; + ret[COL_DONE * 3 + 1] = ret[COL_BACKGROUND * 3 + 1] / 1.5F; + ret[COL_DONE * 3 + 2] = ret[COL_BACKGROUND * 3 + 2] / 1.5F; + *ncolours = NCOLOURS; return ret; } @@ -2090,6 +2145,9 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) ds->hint_errors = snewn(2*state->common->num_paths,unsigned char); for (i=0;i<2*state->common->num_paths;i++) ds->hint_errors[i] = FALSE; + ds->hints_done = snewn(2 * state->common->num_paths, unsigned char); + memset(ds->hints_done, 0, + 2 * state->common->num_paths * sizeof(unsigned char)); ds->hshow = ds->hpencil = ds->hflash = 0; ds->hx = ds->hy = 0; @@ -2097,6 +2155,7 @@ static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) } static void game_free_drawstate(drawing *dr, game_drawstate *ds) { + sfree(ds->hints_done); sfree(ds->hint_errors); sfree(ds->cell_errors); sfree(ds->pencils); @@ -2325,6 +2384,8 @@ static void draw_path_hint(drawing *dr, game_drawstate *ds, color = COL_ERROR; else if (hflash) color = COL_FLASH; + else if (ds->hints_done[hint_index]) + color = COL_DONE; else color = COL_TEXT; @@ -2453,6 +2514,11 @@ static int is_hint_stale(const game_drawstate *ds, int hflash, return TRUE; } + if (ds->hints_done[index] != state->hints_done[index]) { + ds->hints_done[index] = state->hints_done[index]; + return TRUE; + } + return FALSE; }