puzzles: resync with upstream (adds new Palisade cursor interface).

Resyncs properly with this slightly modified upstream:

https://www.franklinwei.com/git/puzzles/commit/?h=rockbox-devel&id=1c62dac3f4f1a819a394ff33cc82912cf9079b50

Change-Id: I2018e81647c22010f9d74d8d14d13982f2969a8f
This commit is contained in:
Franklin Wei 2024-07-23 06:05:45 -04:00
parent 09aa8de52c
commit 62b0456a4b
46 changed files with 309 additions and 128 deletions

View file

@ -868,18 +868,48 @@ static char *game_text_format(const game_state *state)
}
struct game_ui {
/* These are half-grid coordinates - (0,0) is the top left corner
* of the top left square; (1,1) is the center of the top left
* grid square. */
int x, y;
bool show;
bool legacy_cursor;
};
static game_ui *new_ui(const game_state *state)
{
game_ui *ui = snew(game_ui);
ui->x = ui->y = 0;
ui->x = ui->y = 1;
ui->show = getenv_bool("PUZZLES_SHOW_CURSOR", false);
ui->legacy_cursor = false;
return ui;
}
static config_item *get_prefs(game_ui *ui)
{
config_item *cfg;
cfg = snewn(2, config_item);
cfg[0].name = "Cursor mode";
cfg[0].kw = "cursor-mode";
cfg[0].type = C_CHOICES;
cfg[0].u.choices.choicenames = ":Half-grid:Full-grid";
cfg[0].u.choices.choicekws = ":half:full";
cfg[0].u.choices.selected = ui->legacy_cursor;
cfg[1].name = NULL;
cfg[1].type = C_END;
return cfg;
}
static void set_prefs(game_ui *ui, const config_item *cfg)
{
ui->legacy_cursor = cfg[0].u.choices.selected;
}
static void free_ui(game_ui *ui)
{
sfree(ui);
@ -890,7 +920,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
{
}
typedef unsigned short dsflags;
typedef int dsflags;
struct game_drawstate {
int tilesize;
@ -921,9 +951,6 @@ static char *interpret_move(const game_state *state, game_ui *ui,
if (OUT_OF_BOUNDS(gx, gy, w, h)) return NULL;
ui->x = gx;
ui->y = gy;
/* find edge closest to click point */
possible &=~ (2*px < TILESIZE ? BORDER_R : BORDER_L);
possible &=~ (2*py < TILESIZE ? BORDER_D : BORDER_U);
@ -934,6 +961,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
for (dir = 0; dir < 4 && BORDER(dir) != possible; ++dir);
if (dir == 4) return NULL; /* there's not exactly one such edge */
ui->x = min(max(2*gx + 1 + dx[dir], 1), 2*w-1);
ui->y = min(max(2*gy + 1 + dy[dir], 1), 2*h-1);
hx = gx + dx[dir];
hy = gy + dy[dir];
@ -963,17 +993,17 @@ static char *interpret_move(const game_state *state, game_ui *ui,
}
if (IS_CURSOR_MOVE(button)) {
if (control || shift) {
if(ui->legacy_cursor && (control || shift)) {
borderflag flag = 0, newflag;
int dir, i = ui->y * w + ui->x;
int dir, i = (ui->y/2) * w + (ui->x/2);
ui->show = true;
x = ui->x;
y = ui->y;
x = ui->x/2;
y = ui->y/2;
move_cursor(button, &x, &y, w, h, false, NULL);
if (OUT_OF_BOUNDS(x, y, w, h)) return NULL;
for (dir = 0; dir < 4; ++dir)
if (dx[dir] == x - ui->x && dy[dir] == y - ui->y) break;
if (dx[dir] == x - ui->x/2 && dy[dir] == y - ui->y/2) break;
if (dir == 4) return NULL; /* how the ... ?! */
if (control) flag |= BORDER(dir);
@ -987,9 +1017,67 @@ static char *interpret_move(const game_state *state, game_ui *ui,
if (control) newflag |= BORDER(FLIP(dir));
if (shift) newflag |= DISABLED(BORDER(FLIP(dir)));
return string(80, "F%d,%d,%dF%d,%d,%d",
ui->x, ui->y, flag, x, y, newflag);
} else
return move_cursor(button, &ui->x, &ui->y, w, h, false, &ui->show);
ui->x/2, ui->y/2, flag, x, y, newflag);
} else {
/* TODO: Refactor this and other half-grid cursor games
* (Tracks, etc.) */
int dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0);
int dy = (button == CURSOR_DOWN) ? +1 : ((button == CURSOR_UP) ? -1 : 0);
if(ui->legacy_cursor) {
dx *= 2; dy *= 2;
ui->x |= 1;
ui->y |= 1;
}
if (!ui->show) {
ui->show = true;
}
ui->x = min(max(ui->x + dx, 1), 2*w-1);
ui->y = min(max(ui->y + dy, 1), 2*h-1);
return MOVE_UI_UPDATE;
}
} else if (IS_CURSOR_SELECT(button)) {
int px = ui->x % 2, py = ui->y % 2;
int gx = ui->x / 2, gy = ui->y / 2;
int dir = (px == 0) ? 3 : 0; /* left = 3; up = 0 */
int hx = gx + dx[dir];
int hy = gy + dy[dir];
int i = gy * w + gx;
if(!ui->show) {
ui->show = true;
return MOVE_UI_UPDATE;
}
/* clicks on square corners and centers do nothing */
if (px == py)
return MOVE_NO_EFFECT;
/* TODO: Refactor this and the mouse click handling code
* above. */
switch ((button == CURSOR_SELECT2) |
((state->borders[i] & BORDER(dir)) >> dir << 1) |
((state->borders[i] & DISABLED(BORDER(dir))) >> dir >> 2)) {
case MAYBE_LEFT:
case ON_LEFT:
case ON_RIGHT:
return string(80, "F%d,%d,%dF%d,%d,%d",
gx, gy, BORDER(dir),
hx, hy, BORDER(FLIP(dir)));
case MAYBE_RIGHT:
case OFF_LEFT:
case OFF_RIGHT:
return string(80, "F%d,%d,%dF%d,%d,%d",
gx, gy, DISABLED(BORDER(dir)),
hx, hy, DISABLED(BORDER(FLIP(dir))));
}
}
return NULL;
@ -1098,7 +1186,7 @@ static float *game_colours(frontend *fe, int *ncolours)
#define F_ERROR_L BORDER_ERROR(BORDER_L) /* BIT(11) */
#define F_ERROR_CLUE BIT(12)
#define F_FLASH BIT(13)
#define F_CURSOR BIT(14)
#define CONTAINS_CURSOR(x) ((x) << 14)
static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
{
@ -1132,9 +1220,6 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c,
draw_rect(dr, x + WIDTH, y + WIDTH, TILESIZE - WIDTH, TILESIZE - WIDTH,
(flags & F_FLASH ? COL_FLASH : COL_BACKGROUND));
if (flags & F_CURSOR)
draw_rect_corners(dr, x + CENTER, y + CENTER, TILESIZE / 3, COL_GRID);
if (clue != EMPTY) {
char buf[2];
buf[0] = '0' + clue;
@ -1158,6 +1243,47 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c,
draw_update(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH);
}
static void draw_cursor(drawing *dr, game_drawstate *ds,
int cur_x, int cur_y, bool legacy_cursor)
{
int off_x = cur_x % 2, off_y = cur_y % 2;
/* Figure out the tile coordinates corresponding to these cursor
* coordinates. */
int x = MARGIN + TILESIZE * (cur_x / 2), y = MARGIN + TILESIZE * (cur_y / 2);
/* off_x and off_y are either 0 or 1. The possible cases are
* therefore:
*
* (0, 0): the cursor is in the top left corner of the tile.
* (0, 1): the cursor is on the left border of the tile.
* (1, 0): the cursor is on the top border of the tile.
* (1, 1): the cursor is in the center of the tile.
*/
enum { TOP_LEFT_CORNER, LEFT_BORDER, TOP_BORDER, TILE_CENTER } cur_type = (off_x << 1) + off_y;
int center_x = x + ((off_x == 0) ? WIDTH/2 : CENTER),
center_y = y + ((off_y == 0) ? WIDTH/2 : CENTER);
struct { int w, h; } cursor_dimensions[] = {
{ TILESIZE / 3, TILESIZE / 3 }, /* top left corner */
{ TILESIZE / 3, 2 * TILESIZE / 3}, /* left border */
{ 2 * TILESIZE / 3, TILESIZE / 3}, /* top border */
{ 2 * TILESIZE / 3, 2 * TILESIZE / 3 } /* center */
}, *dims = cursor_dimensions + cur_type;
if(legacy_cursor && cur_type == TILE_CENTER)
draw_rect_corners(dr, center_x, center_y, TILESIZE / 3, COL_GRID);
else
draw_rect_outline(dr,
center_x - dims->w / 2, center_y - dims->h / 2,
dims->w, dims->h, COL_GRID);
draw_update(dr,
center_x - dims->w / 2, center_y - dims->h / 2,
dims->w, dims->h);
}
#define FLASH_TIME 0.7F
static void game_redraw(drawing *dr, game_drawstate *ds,
@ -1203,8 +1329,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
if (clue != EMPTY && (on > clue || clue > 4 - off))
flags |= F_ERROR_CLUE;
if (ui->show && ui->x == c && ui->y == r)
flags |= F_CURSOR;
if (ui->show) {
int u, v;
for(u = 0; u < 3; u++)
for(v = 0; v < 3; v++)
if(ui->x == 2*c+u && ui->y == 2*r+v)
flags |= CONTAINS_CURSOR(BIT(3*u+v));
}
/* border errors */
for (dir = 0; dir < 4; ++dir) {
@ -1248,6 +1379,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
draw_tile(dr, ds, r, c, ds->grid[i], clue);
}
if (ui->show)
draw_cursor(dr, ds, ui->x, ui->y, ui->legacy_cursor);
dsf_free(black_border_dsf);
dsf_free(yellow_border_dsf);
}
@ -1375,7 +1509,7 @@ const struct game thegame = {
free_game,
true, solve_game,
true, game_can_format_as_text_now, game_text_format,
NULL, NULL, /* get_prefs, set_prefs */
get_prefs, set_prefs, /* get_prefs, set_prefs */
new_ui,
free_ui,
NULL, /* encode_ui */