1 /*****************************************************************************/
2 /* */
3 /* */
4 /* X patience version 2 -- module commands.c */
5 /* */
6 /* Most of the entries for commands assignable to keys */
7 /* written by Michael Bischoff */
8 /* see COPYRIGHT.xpat2 for Copyright details */
9 /* */
10 /* */
11 /*****************************************************************************/
12 #include "xpatgame.h"
13 #include "version.h"
14
change_rules(const char * new_rules_name)15 void change_rules(const char *new_rules_name) {
16 cmd_CancelSelection();
17 new_rules_coming();
18 new_rules(new_rules_name, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); /* std rules */
19 new_rules_notify();
20 newgame(-1L); /* new game with random seed */
21 }
22
rq_LeavePat(void)23 void rq_LeavePat(void) {
24 if (game.finished || !game.n_moves)
25 cmd_LeavePat();
26 else
27 request_confirm(cmd_LeavePat, TXT_QUIT_CONFIRM);
28 }
29
rq_AnotherGame(void)30 void rq_AnotherGame(void) {
31 if (game.finished || !game.n_moves)
32 cmd_AnotherGame();
33 else
34 request_confirm(cmd_AnotherGame, TXT_NEW_CONFIRM);
35 }
36
37 /* unused, since this can be undone */
rq_RestartGame(void)38 void rq_RestartGame(void) {
39 request_confirm(cmd_RestartGame, TXT_RESTART_CONFIRM);
40 }
41
cmd_AnotherGame(void)42 void cmd_AnotherGame(void) {
43 if (!game.finished) {
44 play_sound("giveup");
45 }
46 newgame(-1L);
47 refresh_screen();
48 }
49
graphics_control(GraphicsControl cmd)50 void graphics_control(GraphicsControl cmd) {
51 Pileindex i;
52 switch (cmd) {
53 case Disable:
54 game.graphic = False;
55 for (i = 0; i < game.numpiles; ++i)
56 game.pile_changed[i] = PILE_UNCHANGED;
57 break;
58 case Enable:
59 game.graphic = True;
60 break;
61 case EnableAndRedraw:
62 game.graphic = True;
63 for (i = 0; i < game.numpiles; ++i)
64 if (game.pile_changed[i] != PILE_UNCHANGED) {
65 /* printf("pile_changed(%d) = %d\n", i, game.pile_changed[i]); */
66 draw_pileupdate(i, game.pile_changed[i]);
67 }
68 break;
69 }
70 }
graphics_pile_control(GraphicsControl cmd,Pileindex pile)71 void graphics_pile_control(GraphicsControl cmd, Pileindex pile) {
72 switch (cmd) {
73 case Disable:
74 game.disable[pile] = True;
75 break;
76 case Enable:
77 game.disable[pile] = False;
78 break;
79 case EnableAndRedraw:
80 game.disable[pile] = False;
81 draw_pileupdate(pile, 0);
82 break;
83 }
84 }
85
cmd_ReplayGame(void)86 void cmd_ReplayGame(void) {
87 int i, oldcheatcount = game.cheat_count;
88 int movenum = game.n_moves;
89 cmd_RestartGame(); /* with graphics! */
90 /* explicitly paint all the piles! */
91 for (i = 0; i < game.numpiles; ++i)
92 draw_pileupdate(i, 0);
93 while (game.n_moves < movenum) {
94 /* XSync(dpy, 0); */
95 redo_move();
96 }
97 game.cheat_count = oldcheatcount;
98 /* problem: we should ignore the following expose events! */
99 }
100
cmd_DropBookmark(void)101 void cmd_DropBookmark(void) {
102 game.bookmark = game.move_ptr; /* easy, isn't it? */
103 show_message(TXT_BOOKMARK_SET);
104 }
105
jumpto_movenr(int move_ptr)106 void jumpto_movenr(int move_ptr) {
107 int remgraphic = game.graphic;
108 if (move_ptr == game.move_ptr)
109 return;
110 assert(move_ptr <= game.stored_moves);
111 if (remgraphic) /* graphic was on */
112 graphics_control(Disable);
113 if (move_ptr > game.move_ptr) /* move forward */
114 while (move_ptr > game.move_ptr)
115 redo_move();
116 else
117 while (game.move_ptr > move_ptr)
118 undo_move();
119 if (remgraphic)
120 graphics_control(EnableAndRedraw);
121 }
122
cmd_RestartGame(void)123 void cmd_RestartGame(void) {
124 jumpto_movenr(0);
125 }
126
cmd_GotoBookmark(void)127 void cmd_GotoBookmark(void) {
128 jumpto_movenr(game.bookmark);
129 }
130
cmd_SaveGame(void)131 void cmd_SaveGame(void) {
132 save_game(NULL);
133 }
134
cmd_ShowVersion(void)135 void cmd_ShowVersion(void) {
136 show_message("%s %s", TXT_VERSION, VERSION);
137 }
138
infosub(char * buff,int n,int txtindex)139 static void infosub(char *buff, int n, int txtindex) {
140 switch (n) {
141 case 0:
142 strcpy(buff, xpat_messages[txtindex+0]);
143 break;
144 case 1:
145 strcpy(buff, xpat_messages[txtindex+1]);
146 break;
147 default:
148 sprintf(buff, xpat_messages[txtindex+2], n);
149 break;
150 }
151 }
152
cmd_ShowScore(void)153 void cmd_ShowScore(void) {
154 char buf[256];
155 sprintf(buf, TXT_INFO1, game.seed, game.cheat_count);
156 strcat(buf, " ");
157 infosub(buf+strlen(buf), game.n_moves, TXT_MOVEBLOCK);
158 strcat(buf, " ");
159 if (rules.score) {
160 infosub(buf+strlen(buf), (*rules.score)(), TXT_SCOREBLOCK);
161 sprintf(buf+strlen(buf), " %d.", rules.maxscore);
162 } else
163 sprintf(buf+strlen(buf), TXT_NOSCORE);
164 show_message(buf);
165 }
166
cmd_Info(void)167 void cmd_Info(void) {
168 char buf[256];
169 int i;
170 buf[0] = '\0';
171 for (i = 0; i < 4; ++i) {
172 if (rules.paramstring[i]) {
173 infosub(buf+strlen(buf), rules.param[i]-game.counter[i], rules.paramstring[i]+1);
174 strcat(buf, " ");
175 }
176 }
177 if (!(rules.variant & NODEAL) && CARDS_ON_DECK)
178 infosub(buf+strlen(buf), CARDS_ON_DECK, TXTI_CARDS+1);
179 show_message(buf);
180 }
181
cmd_DealCards(void)182 void cmd_DealCards(void) {
183 cmd_CancelSelection();
184 if (rules.variant & NODEAL) {
185 show_message(TXT_NODEAL);
186 return;
187 }
188 if (EMPTY(IDECK) && (rules.variant & DECK_SOURCE)) {
189 int i;
190 for (i = 0; i < 4; ++i)
191 if (rules.paramstring[i] == TXTI_FLIP) {
192 /* try a flip */
193 if (game.counter[i] == rules.param[i])
194 show_message(TXT_NOFLIPLEFT);
195 else {
196 store_move(give_new_cards());
197 show_message(TXT_FLIPPING);
198 }
199 return;
200 }
201 }
202 if (check_new_cards()) {
203 show_message(TXT_NEWCARDS);
204 store_move(give_new_cards());
205 } else
206 show_message(TXT_NONEWCARDS);
207 }
208
cmd_AllToStack(void)209 void cmd_AllToStack(void) {
210 cmd_CancelSelection();
211 cmd_ToStack();
212 }
213
cmd_OneToStack(void)214 void cmd_OneToStack(void) {
215 if (game.srcind < 0) {
216 game.srcind = UNSELECTED;
217 show_message(TXT_NOSOURCEPILE);
218 } else
219 cmd_ToStack();
220 }
221
cmd_ToStack(void)222 void cmd_ToStack(void) {
223 if (game.srcind < 0) { /* all to stack */
224 game.srcind = UNSELECTED;
225 if (!all_to_stack())
226 show_message(TXT_NONE_TO_STACK);
227 else
228 show_message(TXT_MOVED_TO_STACK);
229 } else {
230 show_mark(False);
231 if (!move_to_stack(getpile(game.srcind)))
232 show_message(TXT_MOVENOTPOSSIBLE);
233 game.srcind = UNSELECTED;
234 }
235 }
236
cmd_UndoMove(void)237 void cmd_UndoMove(void) {
238 cmd_CancelSelection();
239 switch (undo_move()) {
240 case 0: show_message(TXT_NOUNDO);
241 break;
242 case 1: show_message(TXT_UNDO);
243 break;
244 case 2: show_message(TXT_UNDOCHEAT);
245 break;
246 }
247 }
248
cmd_RedoMove(void)249 void cmd_RedoMove(void) {
250 cmd_CancelSelection();
251 switch (redo_move()) {
252 case 0: show_message(TXT_NOREDO);
253 break;
254 case 1: show_message(TXT_REDO);
255 break;
256 case 2: show_message(TXT_REDOUNCHEAT);
257 break;
258 }
259 }
260
hit_card(Pileindex pile,Cardindex card)261 static void hit_card(Pileindex pile, Cardindex card) {
262 static int srcpile; /* temp. variable to hold getpile(srcind) */
263
264 /* printf("hit_card(%d,%d) called\n", pile, card); */
265
266 cmd_ResetHints();
267 if (game.srcind >= 0) {
268 Cardindex h;
269 h = game.srcind;
270 game.srcind = -1;
271 /* do move */
272 show_mark(False);
273 if (pile < 0) {
274 show_message("");
275 return;
276 }
277 if (pile != srcpile) { /* else just unselect slot */
278 if (game.piletype[pile] == FacedownDeck && !(rules.variant & DECK_VISIBLE))
279 cmd_DealCards();
280 else {
281 if (move_valid(h, pile)) {
282 store_move(do_move(h, pile));
283 show_message("");
284 } else
285 show_message(TXT_INVALIDMOVE);
286 }
287 }
288 } else { /* no mark to clear, set srcpile and game.srcind */
289 if (pile < 0) {
290 show_message("");
291 game.srcind = UNSELECTED;
292 return;
293 }
294 if (game.piletype[pile] == FacedownDeck && !(rules.variant & DECK_VISIBLE))
295 cmd_DealCards();
296 else {
297 game.srcind = card;
298 srcpile = pile;
299 if (card == -1)
300 show_message(TXT_BADSRC);
301 else {
302 show_message(TXT_SRCSELECTED);
303 show_mark(True);
304 }
305 }
306 }
307 }
308
cmd_CancelSelection(void)309 void cmd_CancelSelection(void) {
310 hit_card(-1, -1);
311 }
cmd_RotateUp(void)312 void cmd_RotateUp(void) {
313 int i;
314 hit_card(-1, -1);
315 for (i = 0; i < 4; ++i)
316 if (rules.paramstring[i] == TXTI_ROTATE) {
317 if (rules.param[i] > game.counter[i]) {
318 game.srcind = ROTATE_UP_SEL;
319 show_message(TXT_ROTUP);
320 return;
321 } else {
322 show_message(xpat_messages[TXTI_ROTATE+1]);
323 return;
324 }
325 }
326 show_message(xpat_messages[TXTI_ROTATE]);
327 }
cmd_RotateDown(void)328 void cmd_RotateDown(void) {
329 int i;
330 hit_card(-1, -1);
331 for (i = 0; i < 4; ++i)
332 if (rules.paramstring[i] == TXTI_ROTATE) {
333 if (rules.param[i] > game.counter[i]) {
334 game.srcind = ROTATE_DOWN_SEL;
335 show_message(TXT_ROTDN);
336 return;
337 } else {
338 show_message(xpat_messages[TXTI_ROTATE+1]);
339 return;
340 }
341 }
342 show_message(xpat_messages[TXTI_ROTATE]);
343 }
344
button_pressed(Pileindex i,Cardindex card,int button)345 void button_pressed(Pileindex i, Cardindex card, int button) {
346 /*printf("press %d %d %d called\n", i, card, button); */
347 if (i == -1) { /* no pile hit => cancel */
348 cmd_CancelSelection();
349 return;
350 }
351 if (game.srcind == ROTATE_UP_SEL || game.srcind == ROTATE_DOWN_SEL) {
352 if (game.piletype[i] != Slot)
353 show_message(TXT_SLOTREQUIRED);
354 else if (!game.visible[card])
355 show_message(TXT_CARDNOTVISIBLE);
356 else
357 store_move(game.srcind == ROTATE_UP_SEL ? RotateUp(card) : RotateDown(card));
358 game.srcind = UNSELECTED;
359 return;
360 }
361
362 switch (button) {
363 case 1:
364 cmd_CancelSelection(); /* calls cmd_ResetHints(); */
365 switch (game.piletype[i]) {
366 case FacedownDeck:
367 if (!(rules.variant & DECK_VISIBLE)) {
368 hit_card(i, 0);
369 return;
370 }
371 /* else fall through */
372 case FaceupDeck:
373 case Slot:
374 case Stack:
375 case Tmp:
376 { Cardindex ind;
377 if ((ind = maxsequence(i, card)) < 0)
378 show_message(TXT_BADSRC);
379 else if (rules.automove ? !(*rules.automove)(ind) : !generic_automove(ind))
380 show_message(TXT_NOMOVE);
381 }
382 break; /* no action */
383 }
384 break;
385 case 2:
386 hit_card(i, maxsequence(i, card));
387 break;
388 }
389 }
390