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