Solitaire for the TI-84 Plus CE!
1// Calculation Solitaire / CALCSLTR for the TI-84 Plus CE
2// Copyright (C) 2025 euphory
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <https://www.gnu.org/licenses/>.
16
17#include "ops.h"
18
19#include <stdlib.h>
20#include <fileioc.h>
21
22#include "variables.h"
23#include "save.h"
24#include "drawing.h"
25
26unsigned char cursorStack;
27unsigned char cursorIndex;
28enum cursorMode_t cursorMode;
29unsigned char selectedCard;
30unsigned char selectedQty;
31unsigned char orgStack;
32unsigned char orgIndex;
33
34void start()
35{
36 loadWins();
37 load(); // will call deal() as well if necessary
38
39 // set initial variables
40 cursorMode = SELECT;
41 cursorStack = NUM_FREECELLS;
42 maxCursorIndex();
43 selectedCard = CARD_EMPTY;
44}
45
46bool canGrabCard()
47{
48 if (cursorStack < NUM_FREECELLS) return false;
49 else if (tableau[cursorStack - NUM_FREECELLS][cursorIndex + 1] & CARD_EXISTS) return false;
50 else return tableau[cursorStack - NUM_FREECELLS][cursorIndex] & CARD_EXISTS;
51}
52
53bool canDropCard()
54{
55 if (cursorStack < NUM_FREECELLS)
56 {
57 if ((freeCells[cursorStack] & CARD_NUMBER) == CARD_KING) return false;
58 else return (selectedCard & CARD_NUMBER) == (cursorStack + (freeCells[cursorStack] & CARD_NUMBER) + 1) % 13;
59 }
60 else if (orgStack != DECK_ORG)
61 {
62 return cursorStack == orgStack;
63 }
64 else if (cursorIndex == 0)
65 {
66 return true;
67 }
68 else
69 {
70 return !(tableau[cursorStack - NUM_FREECELLS][cursorIndex + 1] & CARD_EXISTS);
71 }
72}
73
74bool canClearCard()
75{
76 if (orgStack == DECK_ORG) return false;
77 else return selectedCard & CARD_EXISTS;
78}
79
80void getNewCard()
81{
82 while (true)
83 {
84 selectedCard = (rand() & CARD_SUIT) | (rand() % 13) | CARD_EXISTS;
85 if (!removeFromDeck(selectedCard)) break;
86 }
87
88 animateDraw();
89}
90
91bool removeFromDeck(card_t toRemove)
92{
93 unsigned char cardIndex = ((toRemove & CARD_SUIT) >> 4) * 13 + (toRemove & CARD_NUMBER);
94 unsigned char *deckByte = deck + (cardIndex / 8);
95 unsigned char pokeByte = 0x01 << (cardIndex % 8);
96 if (*deckByte & pokeByte) return true;
97
98 *deckByte |= pokeByte;
99 deckCards--;
100 return false;
101}
102
103void grabCard()
104{
105 orgStack = cursorStack;
106 orgIndex = cursorIndex;
107
108 selectedCard = tableau[cursorStack - NUM_FREECELLS][cursorIndex];
109 tableau[cursorStack - NUM_FREECELLS][cursorIndex] = CARD_EMPTY;
110
111 animateGrab();
112}
113
114void dropCard()
115{
116 animateDrop();
117
118 unsigned char const prevProgress = progress;
119
120 if (cursorStack < NUM_FREECELLS)
121 {
122 freeCells[cursorStack] = selectedCard;
123 if ((selectedCard & CARD_NUMBER) == CARD_KING) progress++;
124 }
125 else
126 {
127 tableau[cursorStack - NUM_FREECELLS][cursorIndex] = selectedCard;
128 }
129
130 if (progress == PROGRESS_COMPLETE && prevProgress < PROGRESS_COMPLETE) (*numWins)++;
131}
132
133void clearCard()
134{
135 animateClear();
136 tableau[orgStack - NUM_FREECELLS][orgIndex] = selectedCard;
137 selectedCard = CARD_EMPTY;
138}
139
140void maxCursorIndex()
141{
142 if (cursorStack < NUM_FREECELLS) return;
143
144 cursorIndex = 0;
145 while (tableau[cursorStack - NUM_FREECELLS][cursorIndex + 1] & CARD_EXISTS) cursorIndex++;
146}