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