mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 08:01:30 -07:00
UI change to Filling: allow multiple squares to be set at once.
(This change adds a new possibility to the save format, such that new save files won't necessarily be loadable by old binaries. I think that's acceptable -- it's certainly happened before -- but I couldn't find anything in the developer docs explicitly blessing it.) [originally from svn r7849]
This commit is contained in:
99
filling.c
99
filling.c
@ -976,20 +976,22 @@ static char *solve_game(game_state *state, game_state *currstate,
|
||||
*****************************************************************************/
|
||||
|
||||
struct game_ui {
|
||||
int x, y; /* highlighted square, or (-1, -1) if none */
|
||||
int *sel; /* w*h highlighted squares, or NULL */
|
||||
};
|
||||
|
||||
static game_ui *new_ui(game_state *state)
|
||||
{
|
||||
game_ui *ui = snew(game_ui);
|
||||
|
||||
ui->x = ui->y = -1;
|
||||
ui->sel = NULL;
|
||||
|
||||
return ui;
|
||||
}
|
||||
|
||||
static void free_ui(game_ui *ui)
|
||||
{
|
||||
if (ui->sel)
|
||||
sfree(ui->sel);
|
||||
sfree(ui);
|
||||
}
|
||||
|
||||
@ -1005,6 +1007,11 @@ static void decode_ui(game_ui *ui, char *encoding)
|
||||
static void game_changed_state(game_ui *ui, game_state *oldstate,
|
||||
game_state *newstate)
|
||||
{
|
||||
/* Clear any selection */
|
||||
if (ui->sel) {
|
||||
sfree(ui->sel);
|
||||
ui->sel = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#define PREFERRED_TILE_SIZE 32
|
||||
@ -1029,23 +1036,34 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
||||
const int tx = (x + TILE_SIZE - BORDER) / TILE_SIZE - 1;
|
||||
const int ty = (y + TILE_SIZE - BORDER) / TILE_SIZE - 1;
|
||||
|
||||
char *move = NULL;
|
||||
int i;
|
||||
|
||||
assert(ui);
|
||||
assert(ds);
|
||||
|
||||
button &= ~MOD_MASK;
|
||||
|
||||
if (tx >= 0 && tx < w && ty >= 0 && ty < h) {
|
||||
if (button == LEFT_BUTTON || button == LEFT_DRAG) {
|
||||
/* A left-click anywhere will clear the current selection. */
|
||||
if (button == LEFT_BUTTON) {
|
||||
if ((tx == ui->x && ty == ui->y) || state->shared->clues[w*ty+tx])
|
||||
ui->x = ui->y = -1;
|
||||
else ui->x = tx, ui->y = ty;
|
||||
return ""; /* redraw */
|
||||
if (ui->sel) {
|
||||
sfree(ui->sel);
|
||||
ui->sel = NULL;
|
||||
}
|
||||
}
|
||||
if (tx >= 0 && tx < w && ty >= 0 && ty < h) {
|
||||
if (!ui->sel) {
|
||||
ui->sel = snewn(w*h, int);
|
||||
memset(ui->sel, 0, w*h*sizeof(int));
|
||||
}
|
||||
if (!state->shared->clues[w*ty+tx])
|
||||
ui->sel[w*ty+tx] = 1;
|
||||
}
|
||||
return ""; /* redraw */
|
||||
}
|
||||
|
||||
assert((ui->x == -1) == (ui->y == -1));
|
||||
if (ui->x == -1) return NULL;
|
||||
assert(state->shared->clues[w*ui->y + ui->x] == 0);
|
||||
if (!ui->sel) return NULL;
|
||||
|
||||
switch (button) {
|
||||
case ' ':
|
||||
@ -1061,17 +1079,32 @@ static char *interpret_move(game_state *state, game_ui *ui, game_drawstate *ds,
|
||||
if (button > (w == 2 && h == 2? 3: max(w, h))) return NULL;
|
||||
}
|
||||
|
||||
{
|
||||
const int i = w*ui->y + ui->x;
|
||||
char buf[64];
|
||||
ui->x = ui->y = -1;
|
||||
if (state->board[i] == button) {
|
||||
return ""; /* no change - just update ui */
|
||||
} else {
|
||||
sprintf(buf, "%d_%d", i, button);
|
||||
return dupstr(buf);
|
||||
}
|
||||
for (i = 0; i < w*h; i++) {
|
||||
char buf[32];
|
||||
if (ui->sel[i]) {
|
||||
assert(state->shared->clues[i] == 0);
|
||||
if (state->board[i] != button) {
|
||||
sprintf(buf, "%s%d", move ? "," : "", i);
|
||||
if (move) {
|
||||
move = srealloc(move, strlen(move)+strlen(buf)+1);
|
||||
strcat(move, buf);
|
||||
} else {
|
||||
move = smalloc(strlen(buf)+1);
|
||||
strcpy(move, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (move) {
|
||||
char buf[32];
|
||||
sprintf(buf, "_%d", button);
|
||||
move = srealloc(move, strlen(move)+strlen(buf)+1);
|
||||
strcat(move, buf);
|
||||
}
|
||||
sfree(ui->sel);
|
||||
ui->sel = NULL;
|
||||
/* Need to update UI at least, as we cleared the selection */
|
||||
return move ? move : "";
|
||||
}
|
||||
|
||||
static game_state *execute_move(game_state *state, char *move)
|
||||
@ -1085,18 +1118,22 @@ static game_state *execute_move(game_state *state, char *move)
|
||||
for (++move; i < sz; ++i) new_state->board[i] = move[i] - '0';
|
||||
new_state->cheated = TRUE;
|
||||
} else {
|
||||
char *endptr;
|
||||
const int i = strtol(move, &endptr, 0);
|
||||
int value;
|
||||
if (endptr == move) return NULL;
|
||||
if (*endptr != '_') return NULL;
|
||||
move = endptr + 1;
|
||||
value = strtol(move, &endptr, 0);
|
||||
if (endptr == move) return NULL;
|
||||
if (*endptr != '\0') return NULL;
|
||||
if (i < 0 || i >= sz || value < 0 || value > 9) return NULL;
|
||||
char *endptr, *delim = strchr(move, '_');
|
||||
if (!delim) return NULL;
|
||||
value = strtol(delim+1, &endptr, 0);
|
||||
if (*endptr || endptr == delim+1) return NULL;
|
||||
if (value < 0 || value > 9) return NULL;
|
||||
new_state = dup_game(state);
|
||||
new_state->board[i] = value;
|
||||
while (*move) {
|
||||
const int i = strtol(move, &endptr, 0);
|
||||
if (endptr == move) return NULL;
|
||||
if (i < 0 || i >= sz) return NULL;
|
||||
new_state->board[i] = value;
|
||||
if (*endptr == '_') break;
|
||||
if (*endptr != ',') return NULL;
|
||||
move = endptr + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1414,7 +1451,7 @@ static void draw_grid(drawing *dr, game_drawstate *ds, game_state *state,
|
||||
|
||||
if (flashy || !shading) {
|
||||
/* clear all background flags */
|
||||
} else if (x == ui->x && y == ui->y) {
|
||||
} else if (ui->sel && ui->sel[y*w+x]) {
|
||||
flags |= CURSOR_BG;
|
||||
} else if (v) {
|
||||
int size = dsf_size(ds->dsf_scratch, y*w+x);
|
||||
|
@ -2233,9 +2233,11 @@ Filling was contributed to this collection by Jonas K\u00F6{oe}lker.
|
||||
\H{filling-controls} \I{controls, for Filling}Filling controls
|
||||
|
||||
To play Filling, simply click the mouse in any empty square and then
|
||||
type a digit on the keyboard to fill that square. If you make a
|
||||
mistake, click the mouse in the incorrect square and press 0, Space,
|
||||
Backspace or Enter to clear it again (or use the Undo feature).
|
||||
type a digit on the keyboard to fill that square. By dragging the
|
||||
mouse, you can select multiple squares to fill with a single keypress.
|
||||
If you make a mistake, click the mouse in the incorrect square and
|
||||
press 0, Space, Backspace or Enter to clear it again (or use the Undo
|
||||
feature).
|
||||
|
||||
(All the actions described in \k{common-actions} are also available.)
|
||||
|
||||
|
Reference in New Issue
Block a user