1 #include <stdlib.h>
2 #include <ncurses.h>
3 #include <assert.h>
4
5 #include "keyboard.h"
6 #include "card.h"
7 #include "stack.h"
8 #include "game.h"
9 #include "cursor.h"
10 #include "gui.h"
11 #include "common.h"
12
handle_term_resize()13 static void handle_term_resize() {
14 clear();
15 refresh();
16 if (term_size_ok()) {
17 draw_deck(deck);
18 draw_cursor(cursor);
19 } else {
20 mvprintw(1, 1, SMALL_TERM_MSG);
21 }
22 }
23
24 /* FIXME: this function does not work on stacks with no marked cards.
25 * In that case it returns the stack's length. */
marked_cards_count(struct stack * stack)26 static int marked_cards_count(struct stack *stack) {
27 if (stack_length(stack) == 1) {
28 if (stack->card->frame->begin_y > MANEUVRE_BEGIN_Y) {
29 return(1);
30 }
31 } else if (stack_length(stack) > 1) {
32 for (int marked_cards_count = 0; stack; stack = stack->next) {
33 marked_cards_count++;
34 if (!stack->next || (stack->card->frame->begin_y - stack->next->card->frame->begin_y) > 1) {
35 return(marked_cards_count);
36 }
37 }
38 }
39 return(0);
40 }
41
unmark_cards(struct stack * stack)42 static void unmark_cards(struct stack *stack) {
43 int _marked_cards_count = marked_cards_count(stack);
44 for (int i = 0; i < _marked_cards_count; stack = stack->next, i++) {
45 card_unmark(stack->card);
46 }
47 }
48
handle_card_movement(struct cursor * cursor)49 static void handle_card_movement(struct cursor *cursor) {
50 struct stack **origin = cursor_stack(cursor);
51 int key;
52
53 if (cursor_on_invalid_spot(cursor) || stack_empty(*origin)) {
54 return;
55 }
56 if (maneuvre_stack(*origin)) {
57 erase_stack(*origin);
58 card_mark((*origin)->card);
59 draw_stack(*origin);
60 cursor->y++;
61 }
62 erase_cursor(cursor);
63 cursor_mark(cursor);
64 draw_cursor(cursor);
65
66 for (;;) {
67 if ((key = getch()) == 'q' || key == 'Q') {
68 endwin();
69 exit(0);
70 }
71 if (term_size_ok()) {
72 switch (key) {
73 case 'h':
74 case 'j':
75 case 'k':
76 case 'l':
77 case KEY_LEFT:
78 case KEY_DOWN:
79 case KEY_UP:
80 case KEY_RIGHT:
81 erase_cursor(cursor);
82 cursor_move(cursor, cursor_direction(key));
83 draw_cursor(cursor);
84 break;
85 case 'm':
86 if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
87 for (struct stack *i = *origin; i && i->next; i = i->next) {
88 if (i->next->card->face == EXPOSED &&
89 (i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
90 erase_stack(*origin);
91 card_mark(i->next->card);
92 draw_stack(*origin);
93 break;
94 }
95 }
96 }
97 break;
98 case 'M':
99 if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
100 for (struct stack *i = *origin; i && i->next; i = i->next) {
101 if (i->next->card->face == EXPOSED &&
102 (i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
103 erase_stack(*origin);
104 card_mark(i->next->card);
105 draw_stack(*origin);
106 }
107 }
108 }
109 break;
110 case 'n':
111 if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
112 for (struct stack *i = (*origin)->next; i; i = i->next) {
113 if (i->next) {
114 if ((i->card->frame->begin_y - i->next->card->frame->begin_y) > 1) {
115 erase_stack(*origin);
116 card_unmark(i->card);
117 draw_stack(*origin);
118 break;
119 }
120 } else {
121 if (i->card->frame->begin_y == (MANEUVRE_BEGIN_Y + 1)) {
122 erase_stack(*origin);
123 card_unmark(i->card);
124 draw_stack(*origin);
125 break;
126 }
127 }
128 }
129 }
130 break;
131 case 'N':
132 if (origin == cursor_stack(cursor) && maneuvre_stack(*origin)) {
133 erase_stack(*origin);
134 unmark_cards(*origin);
135 card_mark((*origin)->card);
136 draw_stack(*origin);
137 }
138 break;
139
140 case KEY_SPACEBAR:;
141 /* http://www.mail-archive.com/gcc-bugs@gcc.gnu.org/msg259382.html */
142 struct stack **destination = cursor_stack(cursor);
143 int _marked_cards_count = marked_cards_count(*origin);
144 if (maneuvre_stack(*origin) && _marked_cards_count > 0) {
145 erase_stack(*origin);
146 unmark_cards(*origin);
147 draw_stack(*origin);
148 }
149 if (destination) {
150 erase_stack(*origin);
151 erase_cursor(cursor);
152 if (_marked_cards_count > 1 &&
153 maneuvre_stack(*origin) &&
154 maneuvre_stack(*destination)) {
155 struct stack *block = *origin;
156 for (int i = 1; i < _marked_cards_count; block = block->next, i++)
157 ;
158 if (valid_move(block, *destination)) {
159 move_block(origin, destination, _marked_cards_count);
160 }
161 } else {
162 if (valid_move(*origin, *destination)) {
163 if (maneuvre_stack(*destination)) {
164 cursor->y++;
165 }
166 move_card(origin, destination);
167 }
168 }
169 draw_stack(*origin);
170 draw_stack(*destination);
171 if (maneuvre_stack(*origin) && *origin == *destination) {
172 erase_cursor(cursor);
173 cursor->y--;
174 }
175 }
176 cursor_unmark(cursor);
177 draw_cursor(cursor);
178 return;
179 case KEY_ESCAPE:
180 if (cursor_stack(cursor) == origin && maneuvre_stack(*origin)) {
181 erase_cursor(cursor);
182 cursor->y--;
183 }
184 if (marked_cards_count(*origin) > 0 && maneuvre_stack(*origin)) {
185 erase_stack(*origin);
186 unmark_cards(*origin);
187 draw_stack(*origin);
188 }
189 if (cursor->marked) {
190 cursor_unmark(cursor);
191 draw_cursor(cursor);
192 }
193 return;
194 case KEY_RESIZE:
195 handle_term_resize();
196 break;
197 case 'q':
198 case 'Q':
199 endwin();
200 game_end();
201 exit(0);
202 }
203 } else if (key == KEY_RESIZE) {
204 handle_term_resize();
205 }
206 }
207 }
208
keyboard_event(int key)209 void keyboard_event(int key) {
210 if (key == 'q' || key == 'Q') {
211 endwin();
212 game_end();
213 exit(0);
214 }
215 if (term_size_ok()) {
216 switch (key) {
217 case 'h':
218 case 'j':
219 case 'k':
220 case 'l':
221 case KEY_LEFT:
222 case KEY_DOWN:
223 case KEY_UP:
224 case KEY_RIGHT:
225 erase_cursor(cursor);
226 cursor_move(cursor, cursor_direction(key));
227 draw_cursor(cursor);
228 break;
229 case KEY_SPACEBAR:
230 if (cursor_on_stock(cursor)) {
231 if (stack_empty(deck->stock)) {
232 if (game.passes_through_deck_left >= 1) {
233 while (!stack_empty(deck->waste_pile)) {
234 move_card(&(deck->waste_pile), &(deck->stock));
235 card_cover(deck->stock->card);
236 }
237 draw_stack(deck->stock);
238 draw_stack(deck->waste_pile);
239 }
240 } else {
241 move_card(&(deck->stock), &(deck->waste_pile));
242 if (stack_empty(deck->stock)) {
243 game.passes_through_deck_left--;
244 }
245 card_expose(deck->waste_pile->card);
246 erase_stack(deck->waste_pile);
247 draw_stack(deck->stock);
248 draw_stack(deck->waste_pile);
249 }
250 } else {
251 struct card *card;
252 if (cursor_stack(cursor) &&
253 (card = (*cursor_stack(cursor))->card)->face == COVERED) {
254 card_expose(card);
255 draw_card(card);
256 } else {
257 handle_card_movement(cursor);
258 }
259 }
260 break;
261 case KEY_RESIZE:
262 handle_term_resize();
263 break;
264 }
265 } else if (key == KEY_RESIZE) {
266 handle_term_resize();
267 }
268 }
269