summaryrefslogtreecommitdiff
path: root/apps/plugins/puzzles/src/palisade.c
diff options
context:
space:
mode:
authorFranklin Wei <franklin@rockbox.org>2024-07-23 06:05:45 -0400
committerFranklin Wei <franklin@rockbox.org>2024-07-23 06:05:45 -0400
commit62b0456a4b1415d3e4138e8dbca4b22f88d374d6 (patch)
tree393620d5f8ac19bddf40aaf90721e792017e1623 /apps/plugins/puzzles/src/palisade.c
parent09aa8de52cb962f1ceebfb1fd44f2c54a924fc5c (diff)
downloadrockbox-62b0456a4b1415d3e4138e8dbca4b22f88d374d6.tar.gz
rockbox-62b0456a4b1415d3e4138e8dbca4b22f88d374d6.zip
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
Diffstat (limited to 'apps/plugins/puzzles/src/palisade.c')
-rw-r--r--apps/plugins/puzzles/src/palisade.c174
1 files changed, 154 insertions, 20 deletions
diff --git a/apps/plugins/puzzles/src/palisade.c b/apps/plugins/puzzles/src/palisade.c
index 811204b1fe..ecbbbb4d6f 100644
--- a/apps/plugins/puzzles/src/palisade.c
+++ b/apps/plugins/puzzles/src/palisade.c
@@ -868,18 +868,48 @@ static char *game_text_format(const game_state *state)
868} 868}
869 869
870struct game_ui { 870struct game_ui {
871 /* These are half-grid coordinates - (0,0) is the top left corner
872 * of the top left square; (1,1) is the center of the top left
873 * grid square. */
871 int x, y; 874 int x, y;
872 bool show; 875 bool show;
876
877 bool legacy_cursor;
873}; 878};
874 879
875static game_ui *new_ui(const game_state *state) 880static game_ui *new_ui(const game_state *state)
876{ 881{
877 game_ui *ui = snew(game_ui); 882 game_ui *ui = snew(game_ui);
878 ui->x = ui->y = 0; 883 ui->x = ui->y = 1;
879 ui->show = getenv_bool("PUZZLES_SHOW_CURSOR", false); 884 ui->show = getenv_bool("PUZZLES_SHOW_CURSOR", false);
885 ui->legacy_cursor = false;
880 return ui; 886 return ui;
881} 887}
882 888
889static config_item *get_prefs(game_ui *ui)
890{
891 config_item *cfg;
892
893 cfg = snewn(2, config_item);
894
895 cfg[0].name = "Cursor mode";
896 cfg[0].kw = "cursor-mode";
897 cfg[0].type = C_CHOICES;
898 cfg[0].u.choices.choicenames = ":Half-grid:Full-grid";
899 cfg[0].u.choices.choicekws = ":half:full";
900 cfg[0].u.choices.selected = ui->legacy_cursor;
901
902 cfg[1].name = NULL;
903 cfg[1].type = C_END;
904
905 return cfg;
906}
907
908static void set_prefs(game_ui *ui, const config_item *cfg)
909{
910 ui->legacy_cursor = cfg[0].u.choices.selected;
911}
912
883static void free_ui(game_ui *ui) 913static void free_ui(game_ui *ui)
884{ 914{
885 sfree(ui); 915 sfree(ui);
@@ -890,7 +920,7 @@ static void game_changed_state(game_ui *ui, const game_state *oldstate,
890{ 920{
891} 921}
892 922
893typedef unsigned short dsflags; 923typedef int dsflags;
894 924
895struct game_drawstate { 925struct game_drawstate {
896 int tilesize; 926 int tilesize;
@@ -921,9 +951,6 @@ static char *interpret_move(const game_state *state, game_ui *ui,
921 951
922 if (OUT_OF_BOUNDS(gx, gy, w, h)) return NULL; 952 if (OUT_OF_BOUNDS(gx, gy, w, h)) return NULL;
923 953
924 ui->x = gx;
925 ui->y = gy;
926
927 /* find edge closest to click point */ 954 /* find edge closest to click point */
928 possible &=~ (2*px < TILESIZE ? BORDER_R : BORDER_L); 955 possible &=~ (2*px < TILESIZE ? BORDER_R : BORDER_L);
929 possible &=~ (2*py < TILESIZE ? BORDER_D : BORDER_U); 956 possible &=~ (2*py < TILESIZE ? BORDER_D : BORDER_U);
@@ -934,6 +961,9 @@ static char *interpret_move(const game_state *state, game_ui *ui,
934 for (dir = 0; dir < 4 && BORDER(dir) != possible; ++dir); 961 for (dir = 0; dir < 4 && BORDER(dir) != possible; ++dir);
935 if (dir == 4) return NULL; /* there's not exactly one such edge */ 962 if (dir == 4) return NULL; /* there's not exactly one such edge */
936 963
964 ui->x = min(max(2*gx + 1 + dx[dir], 1), 2*w-1);
965 ui->y = min(max(2*gy + 1 + dy[dir], 1), 2*h-1);
966
937 hx = gx + dx[dir]; 967 hx = gx + dx[dir];
938 hy = gy + dy[dir]; 968 hy = gy + dy[dir];
939 969
@@ -963,17 +993,17 @@ static char *interpret_move(const game_state *state, game_ui *ui,
963 } 993 }
964 994
965 if (IS_CURSOR_MOVE(button)) { 995 if (IS_CURSOR_MOVE(button)) {
966 if (control || shift) { 996 if(ui->legacy_cursor && (control || shift)) {
967 borderflag flag = 0, newflag; 997 borderflag flag = 0, newflag;
968 int dir, i = ui->y * w + ui->x; 998 int dir, i = (ui->y/2) * w + (ui->x/2);
969 ui->show = true; 999 ui->show = true;
970 x = ui->x; 1000 x = ui->x/2;
971 y = ui->y; 1001 y = ui->y/2;
972 move_cursor(button, &x, &y, w, h, false, NULL); 1002 move_cursor(button, &x, &y, w, h, false, NULL);
973 if (OUT_OF_BOUNDS(x, y, w, h)) return NULL; 1003 if (OUT_OF_BOUNDS(x, y, w, h)) return NULL;
974 1004
975 for (dir = 0; dir < 4; ++dir) 1005 for (dir = 0; dir < 4; ++dir)
976 if (dx[dir] == x - ui->x && dy[dir] == y - ui->y) break; 1006 if (dx[dir] == x - ui->x/2 && dy[dir] == y - ui->y/2) break;
977 if (dir == 4) return NULL; /* how the ... ?! */ 1007 if (dir == 4) return NULL; /* how the ... ?! */
978 1008
979 if (control) flag |= BORDER(dir); 1009 if (control) flag |= BORDER(dir);
@@ -987,9 +1017,67 @@ static char *interpret_move(const game_state *state, game_ui *ui,
987 if (control) newflag |= BORDER(FLIP(dir)); 1017 if (control) newflag |= BORDER(FLIP(dir));
988 if (shift) newflag |= DISABLED(BORDER(FLIP(dir))); 1018 if (shift) newflag |= DISABLED(BORDER(FLIP(dir)));
989 return string(80, "F%d,%d,%dF%d,%d,%d", 1019 return string(80, "F%d,%d,%dF%d,%d,%d",
990 ui->x, ui->y, flag, x, y, newflag); 1020 ui->x/2, ui->y/2, flag, x, y, newflag);
991 } else 1021 } else {
992 return move_cursor(button, &ui->x, &ui->y, w, h, false, &ui->show); 1022 /* TODO: Refactor this and other half-grid cursor games
1023 * (Tracks, etc.) */
1024 int dx = (button == CURSOR_LEFT) ? -1 : ((button == CURSOR_RIGHT) ? +1 : 0);
1025 int dy = (button == CURSOR_DOWN) ? +1 : ((button == CURSOR_UP) ? -1 : 0);
1026
1027 if(ui->legacy_cursor) {
1028 dx *= 2; dy *= 2;
1029
1030 ui->x |= 1;
1031 ui->y |= 1;
1032 }
1033
1034 if (!ui->show) {
1035 ui->show = true;
1036 }
1037
1038 ui->x = min(max(ui->x + dx, 1), 2*w-1);
1039 ui->y = min(max(ui->y + dy, 1), 2*h-1);
1040
1041 return MOVE_UI_UPDATE;
1042 }
1043 } else if (IS_CURSOR_SELECT(button)) {
1044 int px = ui->x % 2, py = ui->y % 2;
1045 int gx = ui->x / 2, gy = ui->y / 2;
1046 int dir = (px == 0) ? 3 : 0; /* left = 3; up = 0 */
1047 int hx = gx + dx[dir];
1048 int hy = gy + dy[dir];
1049
1050 int i = gy * w + gx;
1051
1052 if(!ui->show) {
1053 ui->show = true;
1054 return MOVE_UI_UPDATE;
1055 }
1056
1057 /* clicks on square corners and centers do nothing */
1058 if (px == py)
1059 return MOVE_NO_EFFECT;
1060
1061 /* TODO: Refactor this and the mouse click handling code
1062 * above. */
1063 switch ((button == CURSOR_SELECT2) |
1064 ((state->borders[i] & BORDER(dir)) >> dir << 1) |
1065 ((state->borders[i] & DISABLED(BORDER(dir))) >> dir >> 2)) {
1066
1067 case MAYBE_LEFT:
1068 case ON_LEFT:
1069 case ON_RIGHT:
1070 return string(80, "F%d,%d,%dF%d,%d,%d",
1071 gx, gy, BORDER(dir),
1072 hx, hy, BORDER(FLIP(dir)));
1073
1074 case MAYBE_RIGHT:
1075 case OFF_LEFT:
1076 case OFF_RIGHT:
1077 return string(80, "F%d,%d,%dF%d,%d,%d",
1078 gx, gy, DISABLED(BORDER(dir)),
1079 hx, hy, DISABLED(BORDER(FLIP(dir))));
1080 }
993 } 1081 }
994 1082
995 return NULL; 1083 return NULL;
@@ -1098,7 +1186,7 @@ static float *game_colours(frontend *fe, int *ncolours)
1098#define F_ERROR_L BORDER_ERROR(BORDER_L) /* BIT(11) */ 1186#define F_ERROR_L BORDER_ERROR(BORDER_L) /* BIT(11) */
1099#define F_ERROR_CLUE BIT(12) 1187#define F_ERROR_CLUE BIT(12)
1100#define F_FLASH BIT(13) 1188#define F_FLASH BIT(13)
1101#define F_CURSOR BIT(14) 1189#define CONTAINS_CURSOR(x) ((x) << 14)
1102 1190
1103static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state) 1191static game_drawstate *game_new_drawstate(drawing *dr, const game_state *state)
1104{ 1192{
@@ -1132,9 +1220,6 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c,
1132 draw_rect(dr, x + WIDTH, y + WIDTH, TILESIZE - WIDTH, TILESIZE - WIDTH, 1220 draw_rect(dr, x + WIDTH, y + WIDTH, TILESIZE - WIDTH, TILESIZE - WIDTH,
1133 (flags & F_FLASH ? COL_FLASH : COL_BACKGROUND)); 1221 (flags & F_FLASH ? COL_FLASH : COL_BACKGROUND));
1134 1222
1135 if (flags & F_CURSOR)
1136 draw_rect_corners(dr, x + CENTER, y + CENTER, TILESIZE / 3, COL_GRID);
1137
1138 if (clue != EMPTY) { 1223 if (clue != EMPTY) {
1139 char buf[2]; 1224 char buf[2];
1140 buf[0] = '0' + clue; 1225 buf[0] = '0' + clue;
@@ -1158,6 +1243,47 @@ static void draw_tile(drawing *dr, game_drawstate *ds, int r, int c,
1158 draw_update(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH); 1243 draw_update(dr, x, y, TILESIZE + WIDTH, TILESIZE + WIDTH);
1159} 1244}
1160 1245
1246static void draw_cursor(drawing *dr, game_drawstate *ds,
1247 int cur_x, int cur_y, bool legacy_cursor)
1248{
1249 int off_x = cur_x % 2, off_y = cur_y % 2;
1250
1251 /* Figure out the tile coordinates corresponding to these cursor
1252 * coordinates. */
1253 int x = MARGIN + TILESIZE * (cur_x / 2), y = MARGIN + TILESIZE * (cur_y / 2);
1254
1255 /* off_x and off_y are either 0 or 1. The possible cases are
1256 * therefore:
1257 *
1258 * (0, 0): the cursor is in the top left corner of the tile.
1259 * (0, 1): the cursor is on the left border of the tile.
1260 * (1, 0): the cursor is on the top border of the tile.
1261 * (1, 1): the cursor is in the center of the tile.
1262 */
1263 enum { TOP_LEFT_CORNER, LEFT_BORDER, TOP_BORDER, TILE_CENTER } cur_type = (off_x << 1) + off_y;
1264
1265 int center_x = x + ((off_x == 0) ? WIDTH/2 : CENTER),
1266 center_y = y + ((off_y == 0) ? WIDTH/2 : CENTER);
1267
1268 struct { int w, h; } cursor_dimensions[] = {
1269 { TILESIZE / 3, TILESIZE / 3 }, /* top left corner */
1270 { TILESIZE / 3, 2 * TILESIZE / 3}, /* left border */
1271 { 2 * TILESIZE / 3, TILESIZE / 3}, /* top border */
1272 { 2 * TILESIZE / 3, 2 * TILESIZE / 3 } /* center */
1273 }, *dims = cursor_dimensions + cur_type;
1274
1275 if(legacy_cursor && cur_type == TILE_CENTER)
1276 draw_rect_corners(dr, center_x, center_y, TILESIZE / 3, COL_GRID);
1277 else
1278 draw_rect_outline(dr,
1279 center_x - dims->w / 2, center_y - dims->h / 2,
1280 dims->w, dims->h, COL_GRID);
1281
1282 draw_update(dr,
1283 center_x - dims->w / 2, center_y - dims->h / 2,
1284 dims->w, dims->h);
1285}
1286
1161#define FLASH_TIME 0.7F 1287#define FLASH_TIME 0.7F
1162 1288
1163static void game_redraw(drawing *dr, game_drawstate *ds, 1289static void game_redraw(drawing *dr, game_drawstate *ds,
@@ -1203,8 +1329,13 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1203 if (clue != EMPTY && (on > clue || clue > 4 - off)) 1329 if (clue != EMPTY && (on > clue || clue > 4 - off))
1204 flags |= F_ERROR_CLUE; 1330 flags |= F_ERROR_CLUE;
1205 1331
1206 if (ui->show && ui->x == c && ui->y == r) 1332 if (ui->show) {
1207 flags |= F_CURSOR; 1333 int u, v;
1334 for(u = 0; u < 3; u++)
1335 for(v = 0; v < 3; v++)
1336 if(ui->x == 2*c+u && ui->y == 2*r+v)
1337 flags |= CONTAINS_CURSOR(BIT(3*u+v));
1338 }
1208 1339
1209 /* border errors */ 1340 /* border errors */
1210 for (dir = 0; dir < 4; ++dir) { 1341 for (dir = 0; dir < 4; ++dir) {
@@ -1248,6 +1379,9 @@ static void game_redraw(drawing *dr, game_drawstate *ds,
1248 draw_tile(dr, ds, r, c, ds->grid[i], clue); 1379 draw_tile(dr, ds, r, c, ds->grid[i], clue);
1249 } 1380 }
1250 1381
1382 if (ui->show)
1383 draw_cursor(dr, ds, ui->x, ui->y, ui->legacy_cursor);
1384
1251 dsf_free(black_border_dsf); 1385 dsf_free(black_border_dsf);
1252 dsf_free(yellow_border_dsf); 1386 dsf_free(yellow_border_dsf);
1253} 1387}
@@ -1375,7 +1509,7 @@ const struct game thegame = {
1375 free_game, 1509 free_game,
1376 true, solve_game, 1510 true, solve_game,
1377 true, game_can_format_as_text_now, game_text_format, 1511 true, game_can_format_as_text_now, game_text_format,
1378 NULL, NULL, /* get_prefs, set_prefs */ 1512 get_prefs, set_prefs, /* get_prefs, set_prefs */
1379 new_ui, 1513 new_ui,
1380 free_ui, 1514 free_ui,
1381 NULL, /* encode_ui */ 1515 NULL, /* encode_ui */