test timing and input handling
[ansitris] / src / game.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <inttypes.h>
4 #include "game.h"
5 #include "pieces.h"
6 #include "ansi.h"
7
8 enum {
9         G_DIAMOND       = 0x04,
10         G_CHECKER       = 0xb1,
11         G_LR_CORNER     = 0xd9,
12         G_UR_CORNER     = 0xbf,
13         G_UL_CORNER     = 0xda,
14         G_LL_CORNER     = 0xc0,
15         G_CROSS         = 0xc5,
16         G_HLINE         = 0xc4,
17         G_L_TEE         = 0xc3,
18         G_R_TEE         = 0xb4,
19         G_B_TEE         = 0xc1,
20         G_T_TEE         = 0xc2,
21         G_VLINE         = 0xb3,
22         G_CDOT          = 0xf8
23 };
24
25 enum { BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, YELLOW, WHITE };
26
27 /* dimensions of the whole screen */
28 #define SCR_ROWS        20
29 #define SCR_COLS        20
30
31 /* dimensions of the playfield */
32 #define PF_ROWS         18
33 #define PF_COLS         10
34 /* offset of the playfield from the left side of the screen */
35 #define PF_XOFFS        2
36
37 #define CHAR(c, fg, bg) \
38         ((uint16_t)(c) | ((uint16_t)(fg) << 12) | ((uint16_t)(bg) << 8))
39
40 uint16_t scr[SCR_COLS * SCR_ROWS];
41
42 static void wrchar(uint16_t c);
43
44
45 int init_game(void)
46 {
47         int i, j;
48         uint16_t *row = scr;
49
50         tick_interval = 1000;
51
52         ansi_clearscr();
53         ansi_cursor(0);
54
55         /* fill the screen buffer, and draw */
56         for(i=0; i<SCR_ROWS; i++) {
57                 ansi_setcursor(i, 0);
58
59                 for(j=0; j<SCR_COLS; j++) {
60                         if(i > PF_ROWS || j < PF_XOFFS - 1 || j > PF_XOFFS + PF_COLS) {
61                                 row[j] = CHAR(' ', WHITE, BLACK);
62                         } else if((i == PF_ROWS && j >= PF_XOFFS && j < PF_XOFFS + PF_COLS) ||
63                                         j == PF_XOFFS - 1 || j == PF_XOFFS + PF_COLS) {
64                                 row[j] = CHAR(G_CHECKER, WHITE, BLACK);
65                         } else {
66                                 row[j] = CHAR(' ', BLACK, WHITE);
67                         }
68
69                         wrchar(row[j]);
70                 }
71
72                 row += SCR_COLS;
73         }
74         fflush(stdout);
75
76         return 0;
77 }
78
79 void cleanup_game(void)
80 {
81         ansi_reset();
82 }
83
84 static int pos[2] = {0, PF_COLS / 2};
85 static int next_pos[2] = {0, PF_COLS / 2};
86
87 long update(long msec)
88 {
89         static long prev_tick;
90         long dt;
91
92         dt = msec - prev_tick;
93
94         /* fall */
95         while(dt >= tick_interval) {
96                 next_pos[0] = (pos[0] + 1) % PF_ROWS;
97                 dt -= tick_interval;
98                 prev_tick = msec;
99         }
100
101         if(memcmp(pos, next_pos, sizeof pos) != 0) {
102                 ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
103                 wrchar(CHAR(' ', BLACK, WHITE));
104
105                 memcpy(pos, next_pos, sizeof pos);
106                 ansi_setcursor(pos[0], (PF_XOFFS + pos[1]) * 2);
107                 wrchar(CHAR(' ', RED, RED));
108
109                 fflush(stdout);
110         }
111         return tick_interval - dt;
112 }
113
114 void game_input(int c)
115 {
116         switch(c) {
117         case 27:
118                 quit = 1;
119                 break;
120
121         case 'a':
122                 if(pos[1] > 0) {
123                         next_pos[1] = pos[1] - 1;
124                 }
125                 break;
126
127         case 'd':
128                 if(pos[1] < PF_COLS - 1) {
129                         next_pos[1] = pos[1] + 1;
130                 }
131                 break;
132
133         default:
134                 break;
135         }
136 }
137
138 static void wrchar(uint16_t c)
139 {
140         unsigned char cc = c & 0xff;
141         unsigned char ca = c >> 8;
142
143         ansi_ibmchar(cc, ca);
144         ansi_ibmchar(cc, ca);
145 }