X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ian/git?a=blobdiff_plain;f=undead.c;h=b1f536e8d0233183a3d0ecf553999038670bf120;hb=db313b3948d27244dd7c34c2609c66d6204d8931;hp=ddc8aafefa2261be8235ab9d2801a27ee055ebd1;hpb=9def49ae9abc6ee7831264827adcd9ef2a5c28e4;p=sgt-puzzles.git diff --git a/undead.c b/undead.c index ddc8aaf..b1f536e 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) @@ -1686,6 +1727,10 @@ static char *interpret_move(const game_state *state, game_ui *ui, ui->ascii = !ui->ascii; return ""; } + + if (button == 'm' || button == 'M') { + return dupstr("M"); + } if (ui->hshow == 1 && ui->hpencil == 0) { xi = state->common->xinfo[ui->hx + ui->hy*(state->common->params.w+2)]; @@ -1818,6 +1863,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; @@ -1905,7 +1955,9 @@ int check_path_solution(game_state *state, int p) { } } - if (unfilled == 0 && count != state->common->paths[p].sightings_start) { + if (count > state->common->paths[p].sightings_start || + count + unfilled < state->common->paths[p].sightings_start) + { correct = FALSE; state->hint_errors[state->common->paths[p].grid_start] = TRUE; } @@ -1927,7 +1979,9 @@ int check_path_solution(game_state *state, int p) { } } - if (unfilled == 0 && count != state->common->paths[p].sightings_end) { + if (count > state->common->paths[p].sightings_end || + count + unfilled < state->common->paths[p].sightings_end) + { correct = FALSE; state->hint_errors[state->common->paths[p].grid_end] = TRUE; } @@ -1942,7 +1996,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 +2023,23 @@ 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 (c == 'M') { + /* + * Fill in absolutely all pencil marks in unfilled + * squares, for those who like to play by the rigorous + * approach of starting off in that state and eliminating + * things. + */ + for (i = 0; i < ret->common->wh; i++) + if (ret->guess[i] == 7) + ret->pencils[i] = 7; + move++; + } if (*move == ';') move++; } @@ -2058,6 +2129,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 +2165,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 +2175,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); @@ -2316,22 +2395,37 @@ static void draw_monster_count(drawing *dr, game_drawstate *ds, } static void draw_path_hint(drawing *dr, game_drawstate *ds, - const game_state *state, - int i, int hflash, int start) { - int dx,dy,x,y; - int p,error; - char buf[80]; - - p = start ? state->common->paths[i].grid_start : state->common->paths[i].grid_end; - range2grid(p,state->common->params.w,state->common->params.h,&x,&y); - error = ds->hint_errors[p]; - - dx = BORDER+(x* ds->tilesize)+(TILESIZE/2); - dy = BORDER+(y* ds->tilesize)+(TILESIZE/2)+TILESIZE; - sprintf(buf,"%d", start ? state->common->paths[i].sightings_start : state->common->paths[i].sightings_end); - draw_rect(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,TILESIZE-3,COL_BACKGROUND); - draw_text(dr,dx,dy,FONT_FIXED,TILESIZE/2,ALIGN_HCENTRE|ALIGN_VCENTRE, error ? COL_ERROR : hflash ? COL_FLASH : COL_TEXT,buf); - draw_update(dr,dx-(TILESIZE/2)+2,dy-(TILESIZE/2)+2,TILESIZE-3,TILESIZE-3); + const struct game_params *params, + int hint_index, int hflash, int hint) { + int x, y, color, dx, dy, text_dx, text_dy, text_size; + char buf[4]; + + if (ds->hint_errors[hint_index]) + color = COL_ERROR; + else if (hflash) + color = COL_FLASH; + else if (ds->hints_done[hint_index]) + color = COL_DONE; + else + color = COL_TEXT; + + range2grid(hint_index, params->w, params->h, &x, &y); + /* Upper-left corner of the "tile" */ + dx = BORDER + x * TILESIZE; + dy = BORDER + y * TILESIZE + TILESIZE; + /* Center of the "tile" */ + text_dx = dx + TILESIZE / 2; + text_dy = dy + TILESIZE / 2; + /* Avoid wiping out the borders of the puzzle */ + dx += 2; + dy += 2; + text_size = TILESIZE - 3; + + sprintf(buf,"%d", hint); + draw_rect(dr, dx, dy, text_size, text_size, COL_BACKGROUND); + draw_text(dr, text_dx, text_dy, FONT_FIXED, TILESIZE / 2, + ALIGN_HCENTRE | ALIGN_VCENTRE, color, buf); + draw_update(dr, dx, dy, text_size, text_size); return; } @@ -2432,15 +2526,21 @@ static void draw_pencils(drawing *dr, game_drawstate *ds, static int is_hint_stale(const game_drawstate *ds, int hflash, const game_state *state, int index) { - if (!ds->started) return TRUE; - if (ds->hflash != hflash) return TRUE; + int ret = FALSE; + if (!ds->started) ret = TRUE; + if (ds->hflash != hflash) ret = TRUE; if (ds->hint_errors[index] != state->hint_errors[index]) { ds->hint_errors[index] = state->hint_errors[index]; - return TRUE; + ret = TRUE; } - return FALSE; + if (ds->hints_done[index] != state->hints_done[index]) { + ds->hints_done[index] = state->hints_done[index]; + ret = TRUE; + } + + return ret; } static void game_redraw(drawing *dr, game_drawstate *ds, @@ -2501,11 +2601,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds, struct path *path = &state->common->paths[i]; if (is_hint_stale(ds, hflash, state, path->grid_start)) { - draw_path_hint(dr, ds, state, i, hflash, TRUE); + draw_path_hint(dr, ds, &state->common->params, path->grid_start, + hflash, path->sightings_start); } if (is_hint_stale(ds, hflash, state, path->grid_end)) { - draw_path_hint(dr, ds, state, i, hflash, FALSE); + draw_path_hint(dr, ds, &state->common->params, path->grid_end, + hflash, path->sightings_end); } } @@ -2600,7 +2702,7 @@ static void game_print(drawing *dr, const game_state *state, int tilesize) const struct game thegame = { "Undead", "games.undead", "undead", default_params, - game_fetch_preset, + game_fetch_preset, NULL, decode_params, encode_params, free_params,