jag

tetoris_c

public

Small block game in C

Star0
Watch0
7058e495333ef02de16ea0e89fd8ef3353205f6c
1
ssh://git@git.jaglekon.de:30/jag/tetoris_c.git
source/main.cC396 lines7.0 KB
1
#include "main.h"
2
3
4
tetromino playfield[FULL_HEIGHT][FULL_WIDTH] = {};
5
6
uint8_t level = 0;
7
uint16_t all_cleared_lines = 0;
8
uint32_t score = 0;
9
10
11
int main () {
12
  
13
14
  /* Setting up the seed */
15
  
16
  srand(time(NULL));
17
18
19
  /* Setting up terminal with termios */
20
  
21
  struct termios old, new;
22
23
  tcgetattr(STDIN_FILENO, &old);
24
  new = old;
25
26
  new.c_lflag &= ~(ECHO | ICANON);
27
  new.c_cc[VMIN] = 0;
28
  new.c_cc[VTIME] = 0;
29
30
  tcsetattr(STDIN_FILENO, TCSANOW, &new);
31
32
  struct winsize init_size, current_size;
33
  ioctl(STDOUT_FILENO, TIOCGWINSZ, &init_size);
34
  current_size = init_size;
35
36
  printf("\033[?25l\033[?1049h\033[2J\033[H");
37
38
39
  /* Polling */
40
41
  struct pollfd polling[1];
42
43
  polling[0].fd = 0;
44
  polling[0].events = POLLIN;
45
46
47
  /* Init */
48
49
  init_field();
50
 
51
  bool blink[FIELD_HEIGHT] = {};
52
53
  bool is_piece = false;
54
55
  bool paused = false;
56
  
57
  uint16_t lines_to_level = 0;
58
59
  uint16_t pot_score_lines = 0;
60
  uint16_t pot_score_fall = 0;
61
62
  bool add_score = false;
63
64
  piece current_piece = {};
65
  piece next_piece = init_piece((rand() % Z_PIECE) + 1);
66
67
68
  /* Time keeping */
69
70
  struct timespec start, current;
71
  clock_gettime(CLOCK_MONOTONIC_RAW, &start);
72
73
  uint64_t time_acc = 0;
74
75
  uint16_t tick_fall = 0;
76
  uint16_t tick_blink = 0;
77
  uint16_t tick_spin = 0;
78
  uint16_t tick_fall_prot = 0;
79
80
  uint8_t i;
81
  bool is_tetris = false;
82
83
  /* Game Loop */
84
85
  while (true) {
86
87
    int8_t move = 0;
88
    bool down = false;
89
    bool draw = false;
90
    bool rotate = false;
91
92
93
    /* Polling for input */
94
95
    int is_poll = poll(polling, 1, paused ? -1 : 17);
96
97
98
    /* Dealing with Ticks */
99
100
    uint16_t ticks = 0;
101
102
    {
103
104
      clock_gettime(CLOCK_MONOTONIC_RAW, &current);
105
106
      uint64_t time_diff = 
107
        (current.tv_sec - start.tv_sec) * 1000000000ULL + 
108
        (current.tv_nsec - start.tv_nsec) + time_acc;
109
110
      if (!paused) {
111
112
        while (time_diff >= FRAME) {
113
114
          time_diff -= FRAME;
115
          ticks++;
116
        }
117
118
        time_acc = time_diff;
119
      }
120
121
      start = current;
122
    }
123
124
125
    /* Take care of the input */
126
127
    if (is_poll > 0 && polling[0].revents & POLLIN) {
128
129
      char buf[10] = {};
130
131
      if (read(STDIN_FILENO, buf, sizeof(buf)) > 0) {
132
        
133
        if (tolower(buf[0]) == 'q') {
134
          break;
135
        }
136
137
        if (tolower(buf[0]) == 'p') {
138
          if (paused) {
139
140
141
            paused = false;
142
          } else {
143
144
145
            draw_pause();
146
147
            paused = true;
148
          }
149
        }
150
151
152
        if (buf[0] == '\033' && buf[1] == '[') {
153
          
154
          switch (buf[2]) {
155
            case 'A':
156
              rotate = true;
157
              break;
158
            case 'B':
159
              down = true;
160
              break;
161
            case 'C':
162
              move = 1;
163
              break;
164
            case 'D':
165
              move = -1;
166
              break;
167
            default:
168
              break;
169
          }
170
        }
171
      }
172
    }
173
174
175
    if (paused)
176
      continue;
177
178
179
180
    /* Dealing with cleared Lines */
181
182
    if (is_tetris) {
183
184
      uint8_t lines_cleared = 0;
185
186
      tick_blink += ticks;
187
188
      while (tick_blink >= BLINK && i < 4) { 
189
 
190
        tick_blink -= BLINK;
191
192
        draw_board(current_piece, next_piece, (i % 2 == 0) ? blink : NULL, is_piece);
193
        i++;
194
      }
195
      
196
197
      if (i == 4) {
198
      
199
        int8_t j, k;
200
201
        for (j = 0; j < FIELD_HEIGHT; j++) {
202
          if (blink[j]) {
203
204
            for (k = j; k > 0; k--) {
205
              int8_t l;
206
          
207
              for (l = 0; l < FIELD_WIDTH; l++) {
208
                playfield[k][l + BORDER_WIDTH] = playfield[k - 1][l + BORDER_WIDTH];
209
              }
210
            }
211
212
            lines_cleared++;
213
          }
214
215
          all_cleared_lines += lines_cleared;
216
217
          pot_score_lines = line_points_add(lines_cleared, level);
218
        }
219
220
        i = 0;
221
        is_tetris = false;
222
      }
223
224
      continue;
225
    }
226
227
    /* Adding score */
228
229
    if (add_score) {
230
      score += pot_score_fall + pot_score_lines;
231
      pot_score_fall = pot_score_lines = 0;
232
      add_score = false;
233
    }
234
235
    /* Creates new piece */
236
237
    if (!is_piece) {
238
      current_piece = next_piece;
239
      next_piece = init_piece((rand() % Z_PIECE) + 1);
240
      is_piece = true;
241
      draw = true;
242
243
      tick_fall = tick_blink = tick_spin = tick_fall_prot = 0;
244
    }
245
246
247
    /* Move piece */
248
249
    if (move != 0) {
250
      if (
251
        current_piece.x + move >= 0 && 
252
        current_piece.x + move + current_piece.size <= FULL_WIDTH
253
      ) {
254
       
255
        piece moved_piece = current_piece;
256
        moved_piece.x += move;
257
258
        if (valid_position(moved_piece)) {
259
          current_piece.x += move;
260
          draw = true;
261
        }
262
      }
263
    }
264
265
266
    /* Piece rotates */
267
268
    if (tick_spin < SPIN)
269
      tick_spin += ticks;
270
271
    if (rotate && current_piece.positions > 1 && tick_spin >= SPIN) {
272
      
273
      piece rotated = current_piece;
274
275
      rotated.rotation = (current_piece.rotation + 1) % (current_piece.positions);
276
      
277
      if (valid_position(rotated)) {
278
        current_piece = rotated;
279
        draw = true;
280
      }
281
282
      tick_spin = 0;
283
    } 
284
    
285
286
    /* Piece falls */
287
288
    tick_fall += ticks;
289
  
290
    if (tick_fall_prot < FALL_PROTECTION)
291
      tick_fall_prot += ticks;
292
293
    uint8_t fall_delay = level_delay(); 
294
295
    while (tick_fall >= fall_delay || (down && tick_fall_prot >= FALL_PROTECTION)) {
296
      current_piece.y++;
297
      
298
299
      if (tick_fall >= fall_delay) {
300
        tick_fall -= fall_delay;
301
      } else {
302
        tick_fall = 0;
303
      }
304
305
      if (down) {
306
        pot_score_fall++;
307
      } else {
308
        pot_score_fall = 0;
309
      }
310
      
311
      down = false;
312
313
      draw = true;
314
    }
315
    
316
317
318
    /* Looks for stuck piece */
319
320
    if (!valid_position(current_piece)) {
321
322
      int8_t j, k;
323
324
      for (j = 0; j < current_piece.size; j++) {
325
        for (k = 0; k < current_piece.size; k++) {
326
          
327
          if (current_piece.piece[j][k]) {
328
            
329
            coord solid = find_direction(current_piece, k, j);
330
331
            playfield[current_piece.y - 1 + solid.y][current_piece.x + solid.x] = current_piece.name;
332
          }
333
        }
334
      }
335
      is_piece = false;
336
      draw = true;
337
338
      add_score = true;
339
    }
340
341
342
    /* Looks for cleared line */
343
344
    int8_t j, k;
345
346
    for (j = FIELD_HEIGHT - 1; j >= 0; j--) {
347
348
      uint8_t blocked = 0;
349
350
      for (k = 0; k < FIELD_WIDTH; k++) {
351
        if (playfield[j][k + BORDER_WIDTH] != EMPTY)
352
          blocked++;
353
      }
354
355
      if (blocked == 10) {
356
        
357
        blink[j] = true;
358
        is_tetris = true;
359
        lines_to_level++;
360
      } else {
361
        blink[j] = false;
362
      }
363
    }
364
365
    /* Level up */
366
367
    if (lines_to_level >= LINES_LEVEL && level < MAX_LEVEL) {
368
      level++;
369
      lines_to_level -= LINES_LEVEL;
370
    }
371
372
    /* Looks for game over */
373
374
    for (j = 0; j < FIELD_WIDTH; j++) {
375
      if (playfield[TOP_GAP][j + BORDER_WIDTH] > 0) {
376
        draw_board(current_piece, next_piece, NULL, is_piece);
377
        sleep(2);
378
        printf("\033[2J\033[H");
379
        printf("HAHA LOSER\n");
380
        sleep(1);
381
        goto end;
382
      }
383
    }
384
385
    if (draw)
386
      draw_board(current_piece, next_piece, NULL, is_piece);
387
  }
388
389
end:
390
391
  printf("\033[?1049l\033[?25h");
392
393
  tcsetattr(STDIN_FILENO, TCSANOW, &old);
394
395
  return 0;
396
}