/*****************************************************************************/ /* */ /* */ /* X patience version 2 -- module commands.c */ /* */ /* Most of the entries for commands assignable to keys */ /* written by Michael Bischoff */ /* see COPYRIGHT.xpat2 for Copyright details */ /* */ /* */ /*****************************************************************************/ #include "xpatgame.h" #include "version.h" void change_rules(const char *new_rules_name) { cmd_CancelSelection(); new_rules_coming(); new_rules(new_rules_name, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); /* std rules */ new_rules_notify(); newgame(-1L); /* new game with random seed */ } void rq_LeavePat(void) { if (game.finished || !game.n_moves) cmd_LeavePat(); else request_confirm(cmd_LeavePat, TXT_QUIT_CONFIRM); } void rq_AnotherGame(void) { if (game.finished || !game.n_moves) cmd_AnotherGame(); else request_confirm(cmd_AnotherGame, TXT_NEW_CONFIRM); } /* unused, since this can be undone */ void rq_RestartGame(void) { request_confirm(cmd_RestartGame, TXT_RESTART_CONFIRM); } void cmd_AnotherGame(void) { if (!game.finished) { play_sound("giveup"); } newgame(-1L); refresh_screen(); } void graphics_control(GraphicsControl cmd) { Pileindex i; switch (cmd) { case Disable: game.graphic = False; for (i = 0; i < game.numpiles; ++i) game.pile_changed[i] = PILE_UNCHANGED; break; case Enable: game.graphic = True; break; case EnableAndRedraw: game.graphic = True; for (i = 0; i < game.numpiles; ++i) if (game.pile_changed[i] != PILE_UNCHANGED) { /* printf("pile_changed(%d) = %d\n", i, game.pile_changed[i]); */ draw_pileupdate(i, game.pile_changed[i]); } break; } } void graphics_pile_control(GraphicsControl cmd, Pileindex pile) { switch (cmd) { case Disable: game.disable[pile] = True; break; case Enable: game.disable[pile] = False; break; case EnableAndRedraw: game.disable[pile] = False; draw_pileupdate(pile, 0); break; } } void cmd_ReplayGame(void) { int i, oldcheatcount = game.cheat_count; int movenum = game.n_moves; cmd_RestartGame(); /* with graphics! */ /* explicitly paint all the piles! */ for (i = 0; i < game.numpiles; ++i) draw_pileupdate(i, 0); while (game.n_moves < movenum) { /* XSync(dpy, 0); */ redo_move(); } game.cheat_count = oldcheatcount; /* problem: we should ignore the following expose events! */ } void cmd_DropBookmark(void) { game.bookmark = game.move_ptr; /* easy, isn't it? */ show_message(TXT_BOOKMARK_SET); } void jumpto_movenr(int move_ptr) { int remgraphic = game.graphic; if (move_ptr == game.move_ptr) return; assert(move_ptr <= game.stored_moves); if (remgraphic) /* graphic was on */ graphics_control(Disable); if (move_ptr > game.move_ptr) /* move forward */ while (move_ptr > game.move_ptr) redo_move(); else while (game.move_ptr > move_ptr) undo_move(); if (remgraphic) graphics_control(EnableAndRedraw); } void cmd_RestartGame(void) { jumpto_movenr(0); } void cmd_GotoBookmark(void) { jumpto_movenr(game.bookmark); } void cmd_SaveGame(void) { save_game(NULL); } void cmd_ShowVersion(void) { show_message("%s %s", TXT_VERSION, VERSION); } static void infosub(char *buff, int n, int txtindex) { switch (n) { case 0: strcpy(buff, xpat_messages[txtindex+0]); break; case 1: strcpy(buff, xpat_messages[txtindex+1]); break; default: sprintf(buff, xpat_messages[txtindex+2], n); break; } } void cmd_ShowScore(void) { char buf[256]; sprintf(buf, TXT_INFO1, game.seed, game.cheat_count); strcat(buf, " "); infosub(buf+strlen(buf), game.n_moves, TXT_MOVEBLOCK); strcat(buf, " "); if (rules.score) { infosub(buf+strlen(buf), (*rules.score)(), TXT_SCOREBLOCK); sprintf(buf+strlen(buf), " %d.", rules.maxscore); } else sprintf(buf+strlen(buf), TXT_NOSCORE); show_message(buf); } void cmd_Info(void) { char buf[256]; int i; buf[0] = '\0'; for (i = 0; i < 4; ++i) { if (rules.paramstring[i]) { infosub(buf+strlen(buf), rules.param[i]-game.counter[i], rules.paramstring[i]+1); strcat(buf, " "); } } if (!(rules.variant & NODEAL) && CARDS_ON_DECK) infosub(buf+strlen(buf), CARDS_ON_DECK, TXTI_CARDS+1); show_message(buf); } void cmd_DealCards(void) { cmd_CancelSelection(); if (rules.variant & NODEAL) { show_message(TXT_NODEAL); return; } if (EMPTY(IDECK) && (rules.variant & DECK_SOURCE)) { int i; for (i = 0; i < 4; ++i) if (rules.paramstring[i] == TXTI_FLIP) { /* try a flip */ if (game.counter[i] == rules.param[i]) show_message(TXT_NOFLIPLEFT); else { store_move(give_new_cards()); show_message(TXT_FLIPPING); } return; } } if (check_new_cards()) { show_message(TXT_NEWCARDS); store_move(give_new_cards()); } else show_message(TXT_NONEWCARDS); } void cmd_AllToStack(void) { cmd_CancelSelection(); cmd_ToStack(); } void cmd_OneToStack(void) { if (game.srcind < 0) { game.srcind = UNSELECTED; show_message(TXT_NOSOURCEPILE); } else cmd_ToStack(); } void cmd_ToStack(void) { if (game.srcind < 0) { /* all to stack */ game.srcind = UNSELECTED; if (!all_to_stack()) show_message(TXT_NONE_TO_STACK); else show_message(TXT_MOVED_TO_STACK); } else { show_mark(False); if (!move_to_stack(getpile(game.srcind))) show_message(TXT_MOVENOTPOSSIBLE); game.srcind = UNSELECTED; } } void cmd_UndoMove(void) { cmd_CancelSelection(); switch (undo_move()) { case 0: show_message(TXT_NOUNDO); break; case 1: show_message(TXT_UNDO); break; case 2: show_message(TXT_UNDOCHEAT); break; } } void cmd_RedoMove(void) { cmd_CancelSelection(); switch (redo_move()) { case 0: show_message(TXT_NOREDO); break; case 1: show_message(TXT_REDO); break; case 2: show_message(TXT_REDOUNCHEAT); break; } } static void hit_card(Pileindex pile, Cardindex card) { static int srcpile; /* temp. variable to hold getpile(srcind) */ /* printf("hit_card(%d,%d) called\n", pile, card); */ cmd_ResetHints(); if (game.srcind >= 0) { Cardindex h; h = game.srcind; game.srcind = -1; /* do move */ show_mark(False); if (pile < 0) { show_message(""); return; } if (pile != srcpile) { /* else just unselect slot */ if (game.piletype[pile] == FacedownDeck && !(rules.variant & DECK_VISIBLE)) cmd_DealCards(); else { if (move_valid(h, pile)) { store_move(do_move(h, pile)); show_message(""); } else show_message(TXT_INVALIDMOVE); } } } else { /* no mark to clear, set srcpile and game.srcind */ if (pile < 0) { show_message(""); game.srcind = UNSELECTED; return; } if (game.piletype[pile] == FacedownDeck && !(rules.variant & DECK_VISIBLE)) cmd_DealCards(); else { game.srcind = card; srcpile = pile; if (card == -1) show_message(TXT_BADSRC); else { show_message(TXT_SRCSELECTED); show_mark(True); } } } } void cmd_CancelSelection(void) { hit_card(-1, -1); } void cmd_RotateUp(void) { int i; hit_card(-1, -1); for (i = 0; i < 4; ++i) if (rules.paramstring[i] == TXTI_ROTATE) { if (rules.param[i] > game.counter[i]) { game.srcind = ROTATE_UP_SEL; show_message(TXT_ROTUP); return; } else { show_message(xpat_messages[TXTI_ROTATE+1]); return; } } show_message(xpat_messages[TXTI_ROTATE]); } void cmd_RotateDown(void) { int i; hit_card(-1, -1); for (i = 0; i < 4; ++i) if (rules.paramstring[i] == TXTI_ROTATE) { if (rules.param[i] > game.counter[i]) { game.srcind = ROTATE_DOWN_SEL; show_message(TXT_ROTDN); return; } else { show_message(xpat_messages[TXTI_ROTATE+1]); return; } } show_message(xpat_messages[TXTI_ROTATE]); } void button_pressed(Pileindex i, Cardindex card, int button) { /*printf("press %d %d %d called\n", i, card, button); */ if (i == -1) { /* no pile hit => cancel */ cmd_CancelSelection(); return; } if (game.srcind == ROTATE_UP_SEL || game.srcind == ROTATE_DOWN_SEL) { if (game.piletype[i] != Slot) show_message(TXT_SLOTREQUIRED); else if (!game.visible[card]) show_message(TXT_CARDNOTVISIBLE); else store_move(game.srcind == ROTATE_UP_SEL ? RotateUp(card) : RotateDown(card)); game.srcind = UNSELECTED; return; } switch (button) { case 1: cmd_CancelSelection(); /* calls cmd_ResetHints(); */ switch (game.piletype[i]) { case FacedownDeck: if (!(rules.variant & DECK_VISIBLE)) { hit_card(i, 0); return; } /* else fall through */ case FaceupDeck: case Slot: case Stack: case Tmp: { Cardindex ind; if ((ind = maxsequence(i, card)) < 0) show_message(TXT_BADSRC); else if (rules.automove ? !(*rules.automove)(ind) : !generic_automove(ind)) show_message(TXT_NOMOVE); } break; /* no action */ } break; case 2: hit_card(i, maxsequence(i, card)); break; } }