1 #include <stdlib.h>
2 #include <string.h>
3 #include "tetris.h"
4 #include "../timer.h"
5 #include "../input/input.h"
6 #include "../draw/draw.h"
7 
8 struct game *game = NULL;
9 char clearedlines[4];
10 
11 #define RETURN_ON_INPUT 4
12 
13 /* process single-player input */
14 static int processinput(int tm, int flags);
15 
randnum(int n)16 int randnum(int n)
17 {
18 	return (int) (n*(rand()/(RAND_MAX+1.0)));
19 }
20 
gettetrom(struct tetr * t,int i)21 void gettetrom(struct tetr *t, int i)
22 {
23 	t->x = 3;
24 	t->y = -3;
25 	switch (i) {
26 	case 0:
27 		t->y = -4;
28 		t->blocks = TETR_I;
29 		break;
30 	case 1:
31 		t->blocks = TETR_J;
32 		break;
33 	case 2:
34 		t->blocks = TETR_L;
35 		break;
36 	case 3:
37 		t->y = -2;
38 		t->blocks = TETR_O;
39 		break;
40 	case 4:
41 		t->blocks = TETR_S;
42 		break;
43 	case 5:
44 		t->blocks = TETR_T;
45 		break;
46 	case 6:
47 		t->blocks = TETR_Z;
48 		break;
49 	default:
50 		t->blocks = 0;
51 		return;
52 	}
53 	t->color = tetrom_colors[i];
54 }
55 
hitbtm(struct tetr * p,struct player * plr)56 int hitbtm(struct tetr *p, struct player *plr)
57 {
58 	uint_least32_t *board;
59 	int i, mask;
60 	int x, y;
61 
62 	i = 12;
63 	while (!(p->blocks >> i))
64 		i -= 4;
65 	if ((y = p->y+i/4) == 19)
66 		return 1;
67 	board = plr->board;
68 	if (y < -1 || !board[y+1])
69 		return 0;
70 	mask = 15;
71 	while (1) {
72 		if (p->blocks & mask<<i) {
73 			for (x = 0; x < 4; x++)
74 				if (1<<x & mask && p->blocks & 1<<i+x &&
75 				    board[y+1]>>3*(p->x+x) & 7)
76 					return 1;
77 			mask ^= p->blocks>>i & mask;
78 		}
79 		if (!i || y < 0)
80 			break;
81 		i -= 4;
82 		y--;
83 	}
84 	return 0;
85 }
86 
levelup(struct player * p)87 static void levelup(struct player *p)
88 {
89 	p->level++;
90 	if (!p->level)
91 		p->falltime = 799;
92 	else if (p->level < 9)
93 		p->falltime -= 83;
94 	else if (p->level == 9)
95 		p->falltime = 100;
96 	else if (p->level == 10)
97 		p->falltime = 83;
98 	else if (p->level < 20)
99 		p->falltime -= 5 + p->level%2;
100 	else if (p->level < 30)
101 		p->falltime -= 2;
102 }
103 
upd_score_level(struct player * p,int n)104 static void upd_score_level(struct player *p, int n)
105 {
106 	int lines;
107 	if (!(game->mode & MODE_2PLAYER)) {
108 		switch (n) {
109 		case 1:
110 			p->score += 40*(p->level+1);
111 			break;
112 		case 2:
113 			p->score += 100*(p->level+1);
114 			break;
115 		case 3:
116 			p->score += 300*(p->level+1);
117 			break;
118 		case 4:
119 			p->score += 1200*(p->level+1);
120 		}
121 	}
122 	if (game->mode & MODE_BTYPE) {
123 		p->lines -= n;
124 		lines = p->lineslimit - p->lines;
125 		if (p->lines <= 0) {
126 			p->lines = 0;
127 			// This ends the game!
128 			p->piece.y = -1;
129 		}
130 	} else {
131 		p->lines += n;
132 		lines = p->lines;
133 	}
134 	if (p->level == p->startlevel) {
135 		if (lines >= 10*p->startlevel+10 || lines >= 100)
136 			levelup(p);
137 	} else if (lines/10 != (lines-n)/10)
138 		levelup(p);
139 }
140 
clearlines(struct player * p,int n)141 static void clearlines(struct player *p, int n)
142 {
143 	uint_least32_t *board = p->board;
144 	unsigned char lines[4];
145 	int i;
146 	upd_score_level(p, n);
147 	memcpy(lines, clearedlines, 4);
148 	for (i = 0; i < n; i++)
149 		board[lines[i]-1] = 0;
150 	while (n--) {
151 		for (i = lines[n]-1; i > 0; i--) {
152 			board[i] = board[i-1];
153 			if (!n && !board[i])
154 				break;
155 		}
156 		if (board[0])
157 			board[0] = 0;
158 		for (i = n-1; i >= 0; i--)
159 			lines[i]++;
160 	}
161 }
162 
draw_lineclear_anim(int n)163 static void draw_lineclear_anim(int n)
164 {
165 	int x, i;
166 	int t = gettm(0);
167 	int tm;
168 	for (x = 4; x >= 0; x--) {
169 		for (i = 0; i < n; i++) {
170 			clearblocks(&player1, 1, x, clearedlines[i]-1);
171 			clearblocks(&player1, 1, 9-x, clearedlines[i]-1);
172 		}
173 		tm = CLEAR_DELAY/5;
174 		tm = (5-x)*tm-gettm(t)+t;
175 		processinput(tm, DISCARD_MOVES | NO_PAUSE);
176 	}
177 	redrawboard(&player1, clearedlines[n-1]-1);
178 }
179 
lockdelay()180 static int lockdelay()
181 {
182 	struct tetr *p = &player1.piece;
183 	int t = gettm(0);
184 	int d = 0;
185 	int x1, x2;
186 	int b1, b2;
187 
188 	x1 = x2 = p->x;
189 	b1 = b2 = p->blocks;
190 	while (d < LOCK_DELAY) {
191 		switch (processinput(LOCK_DELAY-d, RETURN_ON_INPUT)) {
192 		case -2:
193 			return -2;
194 		case 0:
195 			return 0;
196 		}
197 		if (!hitbtm(p, &player1))
198 			return 1;
199 		if (p->x != x2) {
200 			if (p->x == x1)
201 				break;
202 			x1 = x2;
203 			x2 = p->x;
204 		} else if (p->blocks != b2) {
205 			if (p->blocks == b1)
206 				break;
207 			b2 = p->blocks;
208 		} else
209 			d = -1;
210 		if (d == -1)
211 			d = gettm(t)-t;
212 		else {
213 			d = gettm(t)-t-LOCK_DELAY+d;
214 			if (d < 0)
215 				d = 0;
216 			else if (d > LOCK_DELAY-10)
217 				d = LOCK_DELAY-10;
218 			t = gettm(0)-d;
219 		}
220 	}
221 	return 0;
222 }
223 
lockpiece(struct player * plr)224 void lockpiece(struct player *plr)
225 {
226 	struct tetr *p = &plr->piece;
227 	int x, y;
228 	int n = 0;
229 
230 	if (!p->blocks)
231 		return;
232 	drawblocks(plr, p->blocks, p->x, p->y, DRAW_BLOCKS);
233 	hide_dropmarker(plr);
234 	while (!(p->blocks & 15)) {
235 		p->blocks >>= 4;
236 		p->y++;
237 	}
238 	if (p->y < 0) {
239 		p->blocks = 0;
240 		return;
241 	}
242 	memset(clearedlines, 0, 4);
243 	y = p->y;
244 	do {
245 		x = 0;
246 		while (!(p->blocks & 1<<x))
247 			x++;
248 		do plr->board[y] |= (uint_least32_t) p->color << 3*(p->x+x);
249 		while (p->blocks & 1<<++x);
250 
251 		for (x = 0; x < 10; x++)
252 			if (!(plr->board[y]>>3*x & 7))
253 				break;
254 		if (x == 10)
255 			clearedlines[n++] = y+1;
256 		y++;
257 	} while (p->blocks >>= 4);
258 	x = plr->level;
259 	if (n)
260 		clearlines(plr, n);
261 	upd_stat(plr, x != plr->level);
262 	if (n && !(game->mode & MODE_2PLAYER))
263 		draw_lineclear_anim(n);
264 }
265 
can_moveright(struct tetr * p,uint_least32_t * board)266 static int can_moveright(struct tetr *p, uint_least32_t *board)
267 {
268 	int bl = p->blocks;
269 	int i;
270 	int x, y;
271 
272 	if (i = (bl != TETR_I))
273 		i += !(bl & 0x444);
274 	if (p->x-i > 5)
275 		return 0;
276 	y = p->y;
277 	while (y < 0 || !(bl & 15)) {
278 		bl >>= 4;
279 		y++;
280 	}
281 	x = 3-i;
282 	i = 0;
283 	while (1) {
284 		while (!(bl & 1<<i+x))
285 			x--;
286 		if (board[y] && board[y]>>3*(p->x+x+1) & 7)
287 			return 0;
288 		if (x)
289 			bl &= ~(((1<<x)-1) << i);
290 		if (!(bl >> (i += 4)))
291 			break;
292 		x = 2-!(bl & 0x444);
293 		y++;
294 	}
295 	return bl;
296 }
297 
moveright(struct player * plr)298 void moveright(struct player *plr)
299 {
300 	struct tetr *p = &plr->piece;
301 	int bl = can_moveright(p, plr->board);
302 	int y = p->y;
303 	int i = 0;
304 	if (!bl) {
305 		if (plr->falltime < LOCK_DELAY) {
306 			plr->mvright_tm = gettm(0);
307 			plr->mvleft_tm = 0;
308 		}
309 		return;
310 	}
311 	while (y < 0 || !(p->blocks & 15<<i)) {
312 		y++;
313 		i += 4;
314 	}
315 	drawpiece(plr, bl, p->x+1, y);
316 	bl = p->blocks >> i;
317 	do {
318 		i = 1;
319 		while (!(bl & i))
320 			i <<= 1;
321 		clearblocks(plr, bl & i, p->x, y);
322 		y++;
323 	} while (bl >>= 4);
324 	upd_dropmarker(plr, 1);
325 	p->x++;
326 }
327 
can_moveleft(struct tetr * p,uint_least32_t * board)328 static int can_moveleft(struct tetr *p, uint_least32_t *board)
329 {
330 	int bl;
331 	int i;
332 	int x, y;
333 
334 	if (!(p->x + !(p->blocks & 0x111)))
335 		return 0;
336 	bl = p->blocks;
337 	y = p->y;
338 	while (y < 0 || !(bl & 15)) {
339 		bl >>= 4;
340 		y++;
341 	}
342 	i = 0;
343 	while (1) {
344 		x = 0;
345 		while (!(bl & 1<<i+x))
346 			x++;
347 		if (board[y] && board[y]>>3*(p->x+x-1) & 7)
348 			return 0;
349 		if (x < 3)
350 			bl &= ~(16-(1<<x+1) << i);
351 		if (!(bl >> (i += 4)))
352 			break;
353 		y++;
354 	}
355 	return bl;
356 }
357 
moveleft(struct player * plr)358 void moveleft(struct player *plr)
359 {
360 	struct tetr *p = &plr->piece;
361 	int bl = can_moveleft(p, plr->board);
362 	int y = p->y;
363 	int i = 0;
364 	if (!bl) {
365 		if (plr->falltime < LOCK_DELAY) {
366 			plr->mvleft_tm = gettm(0);
367 			plr->mvright_tm = 0;
368 		}
369 		return;
370 	}
371 	while (y < 0 || !(p->blocks & 15<<i)) {
372 		y++;
373 		i += 4;
374 	}
375 	drawpiece(plr, bl, p->x-1, y);
376 	bl = p->blocks >> i;
377 	do {
378 		i = 8;
379 		while (!(bl & i))
380 			i >>= 1;
381 		clearblocks(plr, bl & i, p->x, y);
382 		y++;
383 	} while (bl >>= 4);
384 	upd_dropmarker(plr, -1);
385 	p->x--;
386 }
387 
drop_score()388 static void drop_score()
389 {
390 	if (!(game->mode & MODE_2PLAYER))
391 		player1.score++;
392 }
393 
movedown(struct player * plr,int drop)394 int movedown(struct player *plr, int drop)
395 {
396 	struct tetr *p = &plr->piece;
397 	int bl;
398 	int i, mask;
399 
400 	if (hitbtm(p, plr))
401 		return 0;
402 	if (drop)
403 		drop_score();
404 	bl = 0;
405 	mask = 15;
406 	for (i = 12; i >= 0; i -= 4)
407 		if (p->blocks & mask<<i) {
408 			bl |= p->blocks & mask<<i;
409 			mask ^= bl>>i & mask;
410 		}
411 	drawpiece(plr, bl, p->x, p->y+1);
412 	bl = 0;
413 	mask = 15;
414 	for (i = 0; i <= 12; i += 4)
415 		if (p->blocks & mask<<i) {
416 			bl |= p->blocks & mask<<i;
417 			mask ^= bl>>i & mask;
418 		}
419 	clearblocks(plr, bl, p->x, p->y);
420 	p->y++;
421 	if (plr->falltime >= LOCK_DELAY)
422 		goto out;
423 	if (!drop && p->y >= 0) {
424 		if (plr->mvright_tm && LOCK_DELAY - plr->falltime >=
425 				gettm(plr->mvright_tm) - plr->mvright_tm)
426 			moveright(plr);
427 		else if (plr->mvleft_tm && LOCK_DELAY - plr->falltime >=
428 				gettm(plr->mvleft_tm) - plr->mvleft_tm)
429 			moveleft(plr);
430 	}
431 	plr->mvright_tm = 0;
432 	plr->mvleft_tm = 0;
433 out:	upd_screen(1+(plr > game->player));
434 	return 1;
435 }
436 
can_rotate(int bl,int x,int y,uint_least32_t * board)437 static int can_rotate(int bl, int x, int y, uint_least32_t *board)
438 {
439 	int row;
440 	int i = bl != TETR_I;
441 	if (i)
442 		i += !(bl & 0x444);
443 	if (x-i > 6)
444 		return 0;
445 	if (x + !(bl & 0x111) < 0)
446 		return 0;
447 	while (y < 0 || !(bl & 15)) {
448 		bl >>= 4;
449 		y++;
450 	}
451 	x *= 3;
452 	while (bl) {
453 		if (y > 19)
454 			return 0;
455 		row = board[y]>>x & 0xFFF;
456 		i = 1;
457 		while (row) {
458 			if (bl & i && row & 7)
459 				return 0;
460 			row >>= 3;
461 			i <<= 1;
462 		}
463 		bl >>= 4;
464 		y++;
465 	}
466 	return 1;
467 }
468 
rotate_JL(struct player * plr,int bl)469 static void rotate_JL(struct player *plr, int bl)
470 {
471 	struct tetr *p = &plr->piece;
472 	int x = p->x;
473 	int y = p->y;
474 	if (can_rotate(bl, x, y, plr->board)) {
475 		drawpiece(plr, bl, x, y);
476 		clearblocks(plr, p->blocks ^ 0x20, x, y);
477 		p->blocks = bl;
478 	}
479 }
480 
rotate(struct player * plr,int clockwise)481 void rotate(struct player *plr, int clockwise)
482 {
483 	struct tetr *p = &plr->piece;
484 	uint_least32_t *board = plr->board;
485 	int y = p->y;
486 	int i = !(plr->rotationsys & ROT_LEFTHAND);
487 
488 	switch (p->blocks) {
489 	case TETR_I:
490 		if (!can_rotate(TETR_I2, p->x+i, y, board))
491 			return;
492 		p->x += i;
493 		p->blocks = TETR_I2;
494 		drawpiece(plr, 0x1011, p->x+1, y);
495 		clearblocks(plr, i?11:13, p->x-i, y+2);
496 		break;
497 	case TETR_I2:
498 		if (!can_rotate(TETR_I, p->x-i, y, board))
499 			return;
500 		p->x -= i;
501 		p->blocks = TETR_I;
502 		drawpiece(plr, 15, p->x, y+2);
503 		clearblocks(plr, 0x1011, p->x+i+1, y);
504 		break;
505 	case TETR_J3:
506 		clockwise = !clockwise;
507 	case TETR_J:
508 		rotate_JL(plr, clockwise ? TETR_J2 : TETR_J4);
509 		break;
510 	case TETR_J4:
511 		clockwise = !clockwise;
512 	case TETR_J2:
513 		rotate_JL(plr, clockwise ? TETR_J3 : TETR_J);
514 		break;
515 	case TETR_L3:
516 		clockwise = !clockwise;
517 	case TETR_L:
518 		rotate_JL(plr, clockwise ? TETR_L2 : TETR_L4);
519 		break;
520 	case TETR_L4:
521 		clockwise = !clockwise;
522 	case TETR_L2:
523 		rotate_JL(plr, clockwise ? TETR_L3 : TETR_L);
524 		break;
525 	case TETR_S:
526 		if (!can_rotate(TETR_S2, p->x+i, y, board))
527 			return;
528 		p->blocks = TETR_S2;
529 		if (!i) {
530 			drawpiece(plr, 0x11, p->x, y);
531 			clearblocks(plr, 0x14, p->x, y+1);
532 		} else {
533 			p->x++;
534 			drawpiece(plr, 0x201, p->x, y);
535 			clearblocks(plr, 3, p->x-1, y+2);
536 		}
537 		break;
538 	case TETR_S2:
539 		if (!can_rotate(TETR_S, p->x-i, y, board))
540 			return;
541 		p->blocks = TETR_S;
542 		if (!i) {
543 			drawpiece(plr, 0x14, p->x, y+1);
544 			clearblocks(plr, 0x11, p->x, y);
545 		} else {
546 			p->x--;
547 			drawpiece(plr, 3, p->x, y+2);
548 			clearblocks(plr, 0x201, p->x+1, y);
549 		}
550 		break;
551 	case TETR_T:
552 		i = clockwise ? TETR_T2 : TETR_T4;
553 		if (!can_rotate(i, p->x, y, board))
554 			return;
555 		p->blocks = i;
556 		drawpiece(plr, 1, p->x+1, y);
557 		clearblocks(plr, 1, p->x+(clockwise?2:0), y+1);
558 		break;
559 	case TETR_T2:
560 		i = clockwise ? TETR_T3 : TETR_T;
561 		if (!can_rotate(i, p->x, y, board))
562 			return;
563 		p->blocks = i;
564 		drawpiece(plr, 1, p->x+2, y+1);
565 		clearblocks(plr, 1, p->x+1, y+(clockwise?2:0));
566 		break;
567 	case TETR_T3:
568 		i = clockwise ? TETR_T4 : TETR_T2;
569 		if (!can_rotate(i, p->x, y, board))
570 			return;
571 		p->blocks = i;
572 		drawpiece(plr, 1, p->x+1, y+2);
573 		clearblocks(plr, 1, p->x+(clockwise?0:2), y+1);
574 		break;
575 	case TETR_T4:
576 		i = clockwise ? TETR_T : TETR_T3;
577 		if (!can_rotate(i, p->x, y, board))
578 			return;
579 		p->blocks = i;
580 		drawpiece(plr, 1, p->x, y+1);
581 		clearblocks(plr, 1, p->x+1, y+(clockwise?0:2));
582 		break;
583 	case TETR_Z:
584 		if (!can_rotate(TETR_Z2, p->x+i, y, board))
585 			return;
586 		p->blocks = TETR_Z2;
587 		if (!i) {
588 			drawpiece(plr, 0x102, p->x, y);
589 			clearblocks(plr, 3, p->x+1, y+2);
590 		} else {
591 			p->x++;
592 			drawpiece(plr, 0x11, p->x+1, y);
593 			clearblocks(plr, 0x41, p->x-1, y+1);
594 		}
595 		break;
596 	case TETR_Z2:
597 		if (!can_rotate(TETR_Z, p->x-i, y, board))
598 			return;
599 		p->blocks = TETR_Z;
600 		if (!i) {
601 			drawpiece(plr, 3, p->x+1, y+2);
602 			clearblocks(plr, 0x102, p->x, y);
603 		} else {
604 			p->x--;
605 			drawpiece(plr, 0x41, p->x, y+1);
606 			clearblocks(plr, 0x11, p->x+2, y);
607 		}
608 	}
609 	upd_dropmarker(plr, 0);
610 }
611 
atspawnpos(struct tetr * p)612 static int atspawnpos(struct tetr *p)
613 {
614 	const short bl[7] = {TETR_I,TETR_J,TETR_L,TETR_O,TETR_S,TETR_T,TETR_Z};
615 	struct tetr t;
616 	int i;
617 	if (p->x != 3 || p->y > 0)
618 		return 0;
619 	for (i = 0; i < 7; i++)
620 		if (p->blocks == bl[i]) {
621 			gettetrom(&t, i);
622 			return (p->y == t.y+2);
623 		}
624 	return 0;
625 }
626 
movedown_n(struct player * plr,int drop,int n)627 static void movedown_n(struct player *plr, int drop, int n)
628 {
629 	struct tetr *p = &plr->piece;
630 	int bl = p->blocks;
631 	int y = p->y;
632 	int i, x;
633 
634 	for (i = 0; i < n && !hitbtm(p, plr); i++) {
635 		p->y++;
636 		if (drop)
637 			drop_score();
638 	}
639 	if (y == p->y)
640 		return;
641 	drawpiece(plr, p->blocks, p->x, p->y);
642 	i = 0;
643 	do {
644 		if (bl & 15) {
645 			x = 0;
646 			while (!(bl & 1<<x))
647 				x++;
648 			do if (y+i >= p->y && p->blocks & 1<<4*(i-p->y+y)+x)
649 				bl ^= 1 << x;
650 			while (bl & 1<<++x);
651 			clearblocks(plr, bl & 15, p->x, y+i);
652 		}
653 		i++;
654 	} while (y+i < 19 && (bl >>= 4));
655 }
656 
harddrop(struct player * plr,int safe)657 int harddrop(struct player *plr, int safe)
658 {
659 	struct tetr *p = &plr->piece;
660 	if (safe && atspawnpos(p))
661 		return -1;
662 	movedown_n(plr, 1, 19);
663 	drawblocks(plr, p->blocks, p->x, p->y, DRAW_BLOCKS);
664 	lockpiece(plr);
665 	return 0;
666 }
667 
softdrop(int n,int safe)668 int softdrop(int n, int safe)
669 {
670 	struct player *p = &player1;
671 	int t = gettm(0);
672 	int tm = -1;
673 	int y = p->piece.y;
674 
675 	if (safe && atspawnpos(&p->piece))
676 		return -1;
677 	if (!movedown(p, 1))
678 		return 0;
679 	n--;
680 	while (n > 0) {
681 		y = p->piece.y;
682 		movedown_n(p, 1, 1+(n>1));
683 		processinput(tm-gettm(t)+t, DISCARD_DROPS);
684 		t = gettm(0);
685 		if (tm == -1) {
686 			tm = 2*p->falltime/20;
687 			if (tm > 10)
688 				tm = 10;
689 		}
690 		if (hitbtm(&p->piece, p))
691 			return 2;
692 		n -= p->piece.y-y;
693 	}
694 	return 1;
695 }
696 
newclr(int old)697 static int newclr(int old)
698 {
699 	int clr = randnum(7)+1;
700 	if (clr == old)
701 		return newclr(0);
702 	return clr;
703 }
704 
gen_garbage_height(struct player * p,int h)705 static void gen_garbage_height(struct player *p, int h)
706 {
707 	int c, clr = randnum(7)+1;
708 	int x, i;
709 	if (p > game->player && p->height == player1.height) {
710 		memcpy(p->board, player1.board, 20*sizeof(uint_least32_t));
711 		return;
712 	}
713 	switch (h) {
714 	case 1:
715 	case 2:
716 		h = 2*h+1;
717 		break;
718 	default:
719 		h = 2*(h+1);
720 	}
721 	while (h) {
722 		i = 0;
723 		for (x = 0; x < 10; x++) {
724 			if (!randnum(2))
725 				continue;
726 			i++;
727 			if (i == 10)
728 				break;
729 			if (x && !(p->board[20-h]>>3*(x-1) & 7)) {
730 				c = p->board[19-h]>>3*x & 7;
731 				if (c && c != clr)
732 					clr = c;
733 				else
734 					clr = newclr(clr);
735 			}
736 			p->board[20-h] |= (uint_least32_t) clr << 3*x;
737 		}
738 		h--;
739 	}
740 }
741 
setupplayer(struct player * p)742 void setupplayer(struct player *p)
743 {
744 	p->piece.blocks = 0;
745 	p->piece.y = 0;
746 	memset(p->board, 0, 20*sizeof(int_least32_t));
747 	if (p->height)
748 		gen_garbage_height(p, p->height);
749 	if  (!(game->mode & MODE_2PLAYER)) {
750 		p->score = 0;
751 		memset(tetr_stats, 0, 7);
752 	}
753 	p->level = -1;
754 	while (p->level < p->startlevel)
755 		levelup(p);
756 	p->lines = (game->mode & MODE_BTYPE) ? p->lineslimit : 0;
757 }
758 
nextpiece(struct tetr * next)759 static int nextpiece(struct tetr *next)
760 {
761 	int i = randnum(7);
762 	player1.piece = *next;
763 	gettetrom(next, i);
764 	tetr_stats[i]++;
765 	drawnext(&player1, next);
766 	return movedown(&player1, 0) && movedown(&player1, 0);
767 }
768 
startgame_1p()769 int startgame_1p()
770 {
771 	struct tetr next;
772 	int i = randnum(7);
773 	int t;
774 	drawgamescreen_1p();
775 	gettetrom(&next, i);
776 	drawnext(&player1, &next);
777 	game->next = &next;
778 	if (!startgame_wait(SINGLE_PL))
779 		return 0;
780 	tetr_stats[i] = 1;
781 	upd_stat(&player1, 0);
782 	while (nextpiece(&next)) {
783 		spawn_discard_drops(0);
784 		t = gettm(0);
785 		show_dropmarker(&player1);
786 		while (1) {
787 			t = player1.falltime-gettm(t)+t;
788 			i = processinput(t, 0);
789 			if (!i)
790 				break;
791 			if (i == -2)
792 				return 0;
793 gravity:		t = gettm(0);
794 			if (i == 2 || movedown(&player1, 0))
795 				continue;
796 			i = lockdelay();
797 			if (i == -2)
798 				return 0;
799 			if (i)
800 				goto gravity;
801 			lockpiece(&player1);
802 			break;
803 		}
804 		if (player1.piece.y < 0)
805 			break;
806 		if (processinput(SPAWN_DELAY, DISCARD_MOVES) == -2)
807 			return 0;
808 	}
809 	game->state = GAME_OVER;
810 	return 1;
811 }
812 
startgame_wait(int n)813 int startgame_wait(int n)
814 {
815 	int key;
816 	print_press_key();
817 	game->state = 0;
818 	key = getkeypress_block(n);
819 	n = processkey_ingame(key, DISCARD_MOVES | NO_PAUSE);
820 	if (n == -2)
821 		return 0;
822 	upd_screen(1);
823 	if (game->mode & MODE_2PLAYER)
824 		upd_screen(2);
825 	game->state = GAME_RUNNING;
826 	return 1;
827 }
828 
pausegame()829 int pausegame()
830 {
831 	int t = gettm(0);
832 	int key;
833 	game->state = GAME_PAUSED;
834 	clearboard_paused();
835 	hide_dropmarker(&player1);
836 	drawnext(&player1, NULL);
837 	do key = getkeypress_block(SINGLE_PL);
838 	while (gettm(t)-t < 500);
839 	if (processkey_ingame(key, NO_PAUSE | DISCARD_MOVES) == -2)
840 		return -2;
841 	upd_screen(1);
842 	show_dropmarker(&player1);
843 	drawnext(&player1, game->next);
844 	game->state = GAME_RUNNING;
845 	return 2;
846 }
847 
processinput(int tm,int flags)848 static int processinput(int tm, int flags)
849 {
850 	int key;
851 	int t = gettm(0);
852 	int d = 0;
853 	int ret;
854 	upd_screen(1);
855 	while (d < tm) {
856 		ret = -1;
857 		if (key = getkeypress(tm-d, IN_GAME | SINGLE_PL)) {
858 			ret = processkey_ingame(key, flags);
859 			if (!ret) {
860 				lockpiece(&player1);
861 				return 0;
862 			}
863 		}
864 		if (abs(ret) == 2 || ret > -1 && (flags & RETURN_ON_INPUT))
865 			return ret;
866 		d = gettm(t)-t;
867 	}
868 	if (!(flags & (DISCARD_MOVES | NO_PAUSE | RETURN_ON_INPUT))) {
869 		tm -= d;
870 		d = 0;
871 		while (tm <= -player1.falltime) {
872 			tm += player1.falltime;
873 			d++;
874 		}
875 		if (d) {
876 			movedown_n(&player1, 0, d);
877 			upd_screen(1);
878 		}
879 	}
880 	return 1;
881 }
882