X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/f10106138f70a92b276899d0822650cb2ec1adae..e28d0584ec76ae4bd34805756b4c18bf174d3460:/net.c diff --git a/net.c b/net.c index 71c2b9d..7ad8c56 100644 --- a/net.c +++ b/net.c @@ -1517,7 +1517,7 @@ static char *validate_desc(game_params *params, char *desc) * Construct an initial game state, given a description and parameters. */ -static game_state *new_game(midend_data *me, game_params *params, char *desc) +static game_state *new_game(midend *me, game_params *params, char *desc) { game_state *state; int w, h, x, y; @@ -1660,6 +1660,8 @@ static char *solve_game(game_state *state, game_state *currstate, tiles[i] = c - 'a' + 10; else if (c >= 'A' && c <= 'F') tiles[i] = c - 'A' + 10; + + tiles[i] |= LOCKED; } } @@ -2109,7 +2111,7 @@ static game_state *execute_move(game_state *from, char *move) * Routines for drawing the game position on the screen. */ -static game_drawstate *game_new_drawstate(game_state *state) +static game_drawstate *game_new_drawstate(drawing *dr, game_state *state) { game_drawstate *ds = snew(game_drawstate); @@ -2124,7 +2126,7 @@ static game_drawstate *game_new_drawstate(game_state *state) return ds; } -static void game_free_drawstate(game_drawstate *ds) +static void game_free_drawstate(drawing *dr, game_drawstate *ds) { sfree(ds->visible); sfree(ds); @@ -2137,8 +2139,8 @@ static void game_compute_size(game_params *params, int tilesize, *y = WINDOW_OFFSET * 2 + tilesize * params->height + TILE_BORDER; } -static void game_set_size(game_drawstate *ds, game_params *params, - int tilesize) +static void game_set_size(drawing *dr, game_drawstate *ds, + game_params *params, int tilesize) { ds->tilesize = tilesize; } @@ -2201,17 +2203,17 @@ static float *game_colours(frontend *fe, game_state *state, int *ncolours) return ret; } -static void draw_thick_line(frontend *fe, int x1, int y1, int x2, int y2, +static void draw_thick_line(drawing *dr, int x1, int y1, int x2, int y2, int colour) { - draw_line(fe, x1-1, y1, x2-1, y2, COL_WIRE); - draw_line(fe, x1+1, y1, x2+1, y2, COL_WIRE); - draw_line(fe, x1, y1-1, x2, y2-1, COL_WIRE); - draw_line(fe, x1, y1+1, x2, y2+1, COL_WIRE); - draw_line(fe, x1, y1, x2, y2, colour); + draw_line(dr, x1-1, y1, x2-1, y2, COL_WIRE); + draw_line(dr, x1+1, y1, x2+1, y2, COL_WIRE); + draw_line(dr, x1, y1-1, x2, y2-1, COL_WIRE); + draw_line(dr, x1, y1+1, x2, y2+1, COL_WIRE); + draw_line(dr, x1, y1, x2, y2, colour); } -static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2, +static void draw_rect_coords(drawing *dr, int x1, int y1, int x2, int y2, int colour) { int mx = (x1 < x2 ? x1 : x2); @@ -2219,13 +2221,13 @@ static void draw_rect_coords(frontend *fe, int x1, int y1, int x2, int y2, int dx = (x2 + x1 - 2*mx + 1); int dy = (y2 + y1 - 2*my + 1); - draw_rect(fe, mx, my, dx, dy, colour); + draw_rect(dr, mx, my, dx, dy, colour); } /* * draw_barrier_corner() and draw_barrier() are passed physical coords */ -static void draw_barrier_corner(frontend *fe, game_drawstate *ds, +static void draw_barrier_corner(drawing *dr, game_drawstate *ds, int x, int y, int dx, int dy, int phase) { int bx = WINDOW_OFFSET + TILE_SIZE * x; @@ -2236,20 +2238,20 @@ static void draw_barrier_corner(frontend *fe, game_drawstate *ds, y1 = (dy > 0 ? TILE_SIZE+TILE_BORDER-1 : 0); if (phase == 0) { - draw_rect_coords(fe, bx+x1+dx, by+y1, + draw_rect_coords(dr, bx+x1+dx, by+y1, bx+x1-TILE_BORDER*dx, by+y1-(TILE_BORDER-1)*dy, COL_WIRE); - draw_rect_coords(fe, bx+x1, by+y1+dy, + draw_rect_coords(dr, bx+x1, by+y1+dy, bx+x1-(TILE_BORDER-1)*dx, by+y1-TILE_BORDER*dy, COL_WIRE); } else { - draw_rect_coords(fe, bx+x1, by+y1, + draw_rect_coords(dr, bx+x1, by+y1, bx+x1-(TILE_BORDER-1)*dx, by+y1-(TILE_BORDER-1)*dy, COL_BARRIER); } } -static void draw_barrier(frontend *fe, game_drawstate *ds, +static void draw_barrier(drawing *dr, game_drawstate *ds, int x, int y, int dir, int phase) { int bx = WINDOW_OFFSET + TILE_SIZE * x; @@ -2262,16 +2264,16 @@ static void draw_barrier(frontend *fe, game_drawstate *ds, h = (Y(dir) ? TILE_BORDER : TILE_SIZE - TILE_BORDER); if (phase == 0) { - draw_rect(fe, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE); + draw_rect(dr, bx+x1-X(dir), by+y1-Y(dir), w, h, COL_WIRE); } else { - draw_rect(fe, bx+x1, by+y1, w, h, COL_BARRIER); + draw_rect(dr, bx+x1, by+y1, w, h, COL_BARRIER); } } /* * draw_tile() is passed physical coordinates */ -static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, +static void draw_tile(drawing *dr, game_state *state, game_drawstate *ds, int x, int y, int tile, int src, float angle, int cursor) { int bx = WINDOW_OFFSET + TILE_SIZE * x; @@ -2287,16 +2289,16 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * we must draw those connections on the borders themselves. */ - clip(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); + clip(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); /* * So. First blank the tile out completely: draw a big * rectangle in border colour, and a smaller rectangle in * background colour to fill it in. */ - draw_rect(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER, + draw_rect(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER, COL_BORDER); - draw_rect(fe, bx+TILE_BORDER, by+TILE_BORDER, + draw_rect(dr, bx+TILE_BORDER, by+TILE_BORDER, TILE_SIZE-TILE_BORDER, TILE_SIZE-TILE_BORDER, tile & LOCKED ? COL_LOCKED : COL_BACKGROUND); @@ -2306,16 +2308,16 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * in. */ if (cursor) { - draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8, + draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); - draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE/8, + draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); - draw_line(fe, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8, + draw_line(dr, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); - draw_line(fe, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, + draw_line(dr, bx+TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, bx+TILE_SIZE-TILE_SIZE/8, by+TILE_SIZE-TILE_SIZE/8, tile & LOCKED ? COL_BACKGROUND : COL_LOCKED); } @@ -2338,7 +2340,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); MATMUL(tx, ty, matrix, ex, ey); - draw_thick_line(fe, bx+(int)cx, by+(int)cy, + draw_thick_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+tx), by+(int)(cy+ty), COL_WIRE); } @@ -2348,7 +2350,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, ex = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * X(dir); ey = (TILE_SIZE - TILE_BORDER - 1.0F) / 2.0F * Y(dir); MATMUL(tx, ty, matrix, ex, ey); - draw_line(fe, bx+(int)cx, by+(int)cy, + draw_line(dr, bx+(int)cx, by+(int)cy, bx+(int)(cx+tx), by+(int)(cy+ty), col); } } @@ -2381,7 +2383,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, points[i+1] = by+(int)(cy+ty); } - draw_polygon(fe, points, 4, col, COL_WIRE); + draw_polygon(dr, points, 4, col, COL_WIRE); } /* @@ -2418,8 +2420,8 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * in: if we are fully connected to the other tile then * the two ACTIVE states will be the same.) */ - draw_rect_coords(fe, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE); - draw_rect_coords(fe, px, py, px+lx, py+ly, + draw_rect_coords(dr, px-vx, py-vy, px+lx+vx, py+ly+vy, COL_WIRE); + draw_rect_coords(dr, px, py, px+lx, py+ly, (tile & ACTIVE) ? COL_POWERED : COL_WIRE); } else { /* @@ -2427,7 +2429,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * actually connected to us. Just draw a single black * dot. */ - draw_rect_coords(fe, px, py, px, py, COL_WIRE); + draw_rect_coords(dr, px, py, px, py, COL_WIRE); } } @@ -2471,7 +2473,7 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, * At least one barrier terminates here. Draw a * corner. */ - draw_barrier_corner(fe, ds, x, y, + draw_barrier_corner(dr, ds, x, y, X(dir)+X(A(dir)), Y(dir)+Y(A(dir)), phase); } @@ -2479,15 +2481,15 @@ static void draw_tile(frontend *fe, game_state *state, game_drawstate *ds, for (dir = 1; dir < 0x10; dir <<= 1) if (barrier(state, GX(x), GY(y)) & dir) - draw_barrier(fe, ds, x, y, dir, phase); + draw_barrier(dr, ds, x, y, dir, phase); } - unclip(fe); + unclip(dr); - draw_update(fe, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); + draw_update(dr, bx, by, TILE_SIZE+TILE_BORDER, TILE_SIZE+TILE_BORDER); } -static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, +static void game_redraw(drawing *dr, game_drawstate *ds, game_state *oldstate, game_state *state, int dir, game_ui *ui, float t, float ft) { int x, y, tx, ty, frame, last_rotate_dir, moved_origin = FALSE; @@ -2503,7 +2505,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, ds->started = TRUE; - draw_rect(fe, 0, 0, + draw_rect(dr, 0, 0, WINDOW_OFFSET * 2 + TILE_SIZE * state->width + TILE_BORDER, WINDOW_OFFSET * 2 + TILE_SIZE * state->height + TILE_BORDER, COL_BACKGROUND); @@ -2512,7 +2514,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, ds->org_y = ui->org_y; moved_origin = TRUE; - draw_update(fe, 0, 0, + draw_update(dr, 0, 0, WINDOW_OFFSET*2 + TILE_SIZE*state->width + TILE_BORDER, WINDOW_OFFSET*2 + TILE_SIZE*state->height + TILE_BORDER); @@ -2521,38 +2523,38 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, for (x = 0; x < ds->width; x++) { if (x+1 < ds->width) { if (barrier(state, GX(x), GY(0)) & R) - draw_barrier_corner(fe, ds, x, -1, +1, +1, phase); + draw_barrier_corner(dr, ds, x, -1, +1, +1, phase); if (barrier(state, GX(x), GY(ds->height-1)) & R) - draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase); + draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase); } if (barrier(state, GX(x), GY(0)) & U) { - draw_barrier_corner(fe, ds, x, -1, -1, +1, phase); - draw_barrier_corner(fe, ds, x, -1, +1, +1, phase); - draw_barrier(fe, ds, x, -1, D, phase); + draw_barrier_corner(dr, ds, x, -1, -1, +1, phase); + draw_barrier_corner(dr, ds, x, -1, +1, +1, phase); + draw_barrier(dr, ds, x, -1, D, phase); } if (barrier(state, GX(x), GY(ds->height-1)) & D) { - draw_barrier_corner(fe, ds, x, ds->height, -1, -1, phase); - draw_barrier_corner(fe, ds, x, ds->height, +1, -1, phase); - draw_barrier(fe, ds, x, ds->height, U, phase); + draw_barrier_corner(dr, ds, x, ds->height, -1, -1, phase); + draw_barrier_corner(dr, ds, x, ds->height, +1, -1, phase); + draw_barrier(dr, ds, x, ds->height, U, phase); } } for (y = 0; y < ds->height; y++) { if (y+1 < ds->height) { if (barrier(state, GX(0), GY(y)) & D) - draw_barrier_corner(fe, ds, -1, y, +1, +1, phase); + draw_barrier_corner(dr, ds, -1, y, +1, +1, phase); if (barrier(state, GX(ds->width-1), GY(y)) & D) - draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase); + draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase); } if (barrier(state, GX(0), GY(y)) & L) { - draw_barrier_corner(fe, ds, -1, y, +1, -1, phase); - draw_barrier_corner(fe, ds, -1, y, +1, +1, phase); - draw_barrier(fe, ds, -1, y, R, phase); + draw_barrier_corner(dr, ds, -1, y, +1, -1, phase); + draw_barrier_corner(dr, ds, -1, y, +1, +1, phase); + draw_barrier(dr, ds, -1, y, R, phase); } if (barrier(state, GX(ds->width-1), GY(y)) & R) { - draw_barrier_corner(fe, ds, ds->width, y, -1, -1, phase); - draw_barrier_corner(fe, ds, ds->width, y, -1, +1, phase); - draw_barrier(fe, ds, ds->width, y, L, phase); + draw_barrier_corner(dr, ds, ds->width, y, -1, -1, phase); + draw_barrier_corner(dr, ds, ds->width, y, -1, +1, phase); + draw_barrier(dr, ds, ds->width, y, L, phase); } } } @@ -2618,7 +2620,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, index(state, ds->visible, x, y) != c || index(state, ds->visible, x, y) == 0xFF || is_src || is_anim || is_cursor) { - draw_tile(fe, state, ds, x, y, c, + draw_tile(dr, state, ds, x, y, c, is_src, (is_anim ? angle : 0.0F), is_cursor); if (is_src || is_anim || is_cursor) index(state, ds->visible, x, y) = 0xFF; @@ -2646,7 +2648,7 @@ static void game_redraw(frontend *fe, game_drawstate *ds, game_state *oldstate, (state->used_solve ? "Auto-solved. " : state->completed ? "COMPLETED! " : ""), a, n2); - status_bar(fe, statusbuf); + status_bar(dr, statusbuf); } sfree(active); @@ -2705,6 +2707,141 @@ static int game_timing_state(game_state *state, game_ui *ui) return TRUE; } +static void game_print_size(game_params *params, float *x, float *y) +{ + int pw, ph; + + /* + * I'll use 8mm squares by default. + */ + game_compute_size(params, 800, &pw, &ph); + *x = pw / 100.0; + *y = ph / 100.0; +} + +static void draw_diagram(drawing *dr, game_drawstate *ds, int x, int y, + int topleft, int v, int drawlines, int ink) +{ + int tx, ty, cx, cy, r, br, k, thick; + + tx = WINDOW_OFFSET + TILE_SIZE * x; + ty = WINDOW_OFFSET + TILE_SIZE * y; + + /* + * Find our centre point. + */ + if (topleft) { + cx = tx + (v & L ? TILE_SIZE / 4 : TILE_SIZE / 6); + cy = ty + (v & U ? TILE_SIZE / 4 : TILE_SIZE / 6); + r = TILE_SIZE / 8; + br = TILE_SIZE / 32; + } else { + cx = tx + TILE_SIZE / 2; + cy = ty + TILE_SIZE / 2; + r = TILE_SIZE / 2; + br = TILE_SIZE / 8; + } + thick = r / 20; + + /* + * Draw the square block if we have an endpoint. + */ + if (v == 1 || v == 2 || v == 4 || v == 8) + draw_rect(dr, cx - br, cy - br, br*2, br*2, ink); + + /* + * Draw each radial line. + */ + if (drawlines) { + for (k = 1; k < 16; k *= 2) + if (v & k) { + int x1 = min(cx, cx + (r-thick) * X(k)); + int x2 = max(cx, cx + (r-thick) * X(k)); + int y1 = min(cy, cy + (r-thick) * Y(k)); + int y2 = max(cy, cy + (r-thick) * Y(k)); + draw_rect(dr, x1 - thick, y1 - thick, + (x2 - x1) + 2*thick, (y2 - y1) + 2*thick, ink); + } + } +} + +static void game_print(drawing *dr, game_state *state, int tilesize) +{ + int w = state->width, h = state->height; + int ink = print_mono_colour(dr, 0); + int x, y; + + /* Ick: fake up `ds->tilesize' for macro expansion purposes */ + game_drawstate ads, *ds = &ads; + ads.tilesize = tilesize; + + /* + * Border. + */ + print_line_width(dr, TILE_SIZE / (state->wrapping ? 128 : 12)); + draw_rect_outline(dr, WINDOW_OFFSET, WINDOW_OFFSET, + TILE_SIZE * w, TILE_SIZE * h, ink); + + /* + * Grid. + */ + print_line_width(dr, TILE_SIZE / 128); + for (x = 1; x < w; x++) + draw_line(dr, WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET, + WINDOW_OFFSET + TILE_SIZE * x, WINDOW_OFFSET + TILE_SIZE * h, + ink); + for (y = 1; y < h; y++) + draw_line(dr, WINDOW_OFFSET, WINDOW_OFFSET + TILE_SIZE * y, + WINDOW_OFFSET + TILE_SIZE * w, WINDOW_OFFSET + TILE_SIZE * y, + ink); + + /* + * Barriers. + */ + for (y = 0; y <= h; y++) + for (x = 0; x <= w; x++) { + int b = barrier(state, x % w, y % h); + if (x < w && (b & U)) + draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24, + WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24, + TILE_SIZE + TILE_SIZE/24 * 2, TILE_SIZE/24 * 2, ink); + if (y < h && (b & L)) + draw_rect(dr, WINDOW_OFFSET + TILE_SIZE * x - TILE_SIZE/24, + WINDOW_OFFSET + TILE_SIZE * y - TILE_SIZE/24, + TILE_SIZE/24 * 2, TILE_SIZE + TILE_SIZE/24 * 2, ink); + } + + /* + * Grid contents. + */ + for (y = 0; y < h; y++) + for (x = 0; x < w; x++) { + int vx, v = tile(state, x, y); + int locked = v & LOCKED; + + v &= 0xF; + + /* + * Rotate into a standard orientation for the top left + * corner diagram. + */ + vx = v; + while (vx != 0 && vx != 15 && vx != 1 && vx != 9 && vx != 13 && + vx != 5) + vx = A(vx); + + /* + * Draw the top left corner diagram. + */ + draw_diagram(dr, ds, x, y, TRUE, vx, TRUE, ink); + + /* + * Draw the real solution diagram, if we're doing so. + */ + draw_diagram(dr, ds, x, y, FALSE, v, locked, ink); + } +} + #ifdef COMBINED #define thegame net #endif @@ -2740,6 +2877,7 @@ const struct game thegame = { game_redraw, game_anim_length, game_flash_length, + TRUE, FALSE, game_print_size, game_print, game_wants_statusbar, FALSE, game_timing_state, 0, /* mouse_priorities */