1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2  * This program is public domain.
3  *
4  * Tetris core.
5  */
6 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/time.h>
11 #include "tetrinet.h"
12 #include "tetris.h"
13 #include "io.h"
14 #include "sockets.h"
15 
16 /*************************************************************************/
17 
18 int piecefreq[7];	/* Frequency (percentage) for each block type */
19 int specialfreq[9];	/* Frequency for each special type */
20 int old_mode;		/* Old mode? (i.e. Gameboy-style) */
21 int initial_level;	/* Initial level */
22 int lines_per_level;	/* Number of lines per level-up */
23 int level_inc;		/* Levels to increase at each level-up */
24 int level_average;	/* Average all players' levels */
25 int special_lines;	/* Number of lines needed for a special block */
26 int special_count;	/* Number of special blocks added each time */
27 int special_capacity;	/* Capacity of special block inventory */
28 
29 Field fields[6];	/* Current field states */
30 int levels[6];		/* Current levels */
31 int lines;		/* Lines completed (by us) */
32 char specials[MAX_SPECIALS] = {-1}; /* Special block inventory */
33 int next_piece;		/* Next piece to fall */
34 
35 static struct timeval timeout;	/* Time of next action */
36 int current_piece;	/* Current piece number */
37 int current_rotation;	/* Current rotation value */
38 int current_x;		/* Current X position */
39 int current_y;		/* Current Y position */
40 static int piece_waiting;	/* Are we waiting for a new piece to start? */
41 
42 static int last_special;	/* Last line for which we added a special */
43 
44 /*************************************************************************/
45 
46 #ifndef SERVER_ONLY
47 
48 /*************************************************************************/
49 
50 /* The array of piece shapes.  It is organized as:
51  *	- 7 pieces
52  *	  - 4 rows
53  *	    - 4 rotations (ordered clockwise)
54  *	      - 4 points
55  * A . is an empty point, a # is a full one.  An X (upper-case) represents
56  * the "hot-spot" of the piece; this is where the coordinates are fastened
57  * to, and is used to determine the piece's new position after rotation.
58  * If the location for an X empty, use a lowercase letter instead.
59  *
60  * This is all parsed by init_shapes, which should be called at startup.
61  */
62 
63 static const char shapes[7][4][4][4] = {
64     { { "##X#", "..X.", "##X#", "..X." },
65       { "....", "..#.", "....", "..#." },
66       { "....", "..#.", "....", "..#." },
67       { "....", "..#.", "....", "..#." } },
68 
69     { { "....", "....", "....", "...." },
70       { ".X#.", ".X#.", ".X#.", ".X#." },
71       { ".##.", ".##.", ".##.", ".##." },
72       { "....", "....", "....", "...." } },
73 
74     { { "....", ".#..", "#...", ".##." },
75       { "#X#.", ".X..", "#X#.", ".X.." },
76       { "..#.", "##..", "....", ".#.." },
77       { "....", "....", "....", "...." } },
78 
79     { { "....", "##..", "..#.", ".#.." },
80       { "#X#.", ".X..", "#X#.", ".X.." },
81       { "#...", ".#..", "....", ".##." },
82       { "....", "....", "....", "...." } },
83 
84     { { "....", ".#..", "....", ".#.." },
85       { "#X..", "#X..", "#X..", "#X.." },
86       { ".##.", "#...", ".##.", "#..." },
87       { "....", "....", "....", "...." } },
88 
89     { { "....", "#...", "....", "#..." },
90       { ".X#.", "#X..", ".X#.", "#X.." },
91       { "##..", ".#..", "##..", ".#.." },
92       { "....", "....", "....", "...." } },
93 
94     { { "....", ".#..", ".#..", ".#.." },
95       { "#X#.", "#X..", "#X#.", ".X#." },
96       { ".#..", ".#..", "....", ".#.." },
97       { "....", "....", "....", "...." } }
98 };
99 
100 /* piecedata[piece][rot]; filled in by init_shapes() */
101 PieceData piecedata[7][4];
102 
103 /*************************************************************************/
104 
105 /* Parse the shapes array and fill in the piece data. */
106 
init_shapes(void)107 void init_shapes(void)
108 {
109     int i, x, y, r;
110 
111     for (i = 0; i < 7; i++) {
112 	for (r = 0; r < 4; r++) {
113 	    piecedata[i][r].hot_x  = -1;
114 	    piecedata[i][r].hot_y  = -1;
115 	    piecedata[i][r].top    =  3;
116 	    piecedata[i][r].left   =  3;
117 	    piecedata[i][r].bottom =  0;
118 	    piecedata[i][r].right  =  0;
119 	    for (y = 0; y < 4; y++) {
120 		for (x = 0; x < 4; x++) {
121 		    switch (shapes[i][y][r][x]) {
122 		      case '.':
123 			piecedata[i][r].shape[y][x] = 0;
124 			break;
125 		      case '#':
126 			piecedata[i][r].shape[y][x] = 1;
127 			if (piecedata[i][r].top     > y)
128 			    piecedata[i][r].top     = y;
129 			if (piecedata[i][r].left    > x)
130 			    piecedata[i][r].left    = x;
131 			if (piecedata[i][r].bottom  < y)
132 			    piecedata[i][r].bottom  = y;
133 			if (piecedata[i][r].right   < x)
134 			    piecedata[i][r].right   = x;
135 			break;
136 		      case 'x':
137 			piecedata[i][r].shape[y][x] = 0;
138 			piecedata[i][r].hot_x       = x;
139 			piecedata[i][r].hot_y       = y;
140 			break;
141 		      case 'X':
142 			piecedata[i][r].shape[y][x] = 1;
143 			if (piecedata[i][r].top     > y)
144 			    piecedata[i][r].top     = y;
145 			if (piecedata[i][r].left    > x)
146 			    piecedata[i][r].left    = x;
147 			if (piecedata[i][r].bottom  < y)
148 			    piecedata[i][r].bottom  = y;
149 			if (piecedata[i][r].right   < x)
150 			    piecedata[i][r].right   = x;
151 			piecedata[i][r].hot_x       = x;
152 			piecedata[i][r].hot_y       = y;
153 			break;
154 		      default :
155 			fprintf(stderr, "Piece %d rotation %d: "
156 					"weird character `%c' at (%d,%d)\n",
157 				i, r, shapes[i][y][r][x], x, y);
158 			exit(1);
159 		    }
160 		}
161 	    }
162 	    if (piecedata[i][r].hot_x < 0 || piecedata[i][r].hot_y < 0) {
163 		fprintf(stderr, "Piece %d rotation %d missing hot spot!\n",
164 			i, r);
165 		exit(1);
166 	    }
167 	}
168     }
169 }
170 
171 /*************************************************************************/
172 
173 /* Retrieve the shape for the given piece and rotation.  Return -1 if piece
174  * or rotation is invalid, else 0.
175  */
176 
get_shape(int piece,int rotation,char buf[4][4])177 int get_shape(int piece, int rotation, char buf[4][4])
178 {
179     int x, y;
180     char *shape;
181 
182     if (piece < 0 || piece > 6 || rotation < 0 || rotation > 3)
183 	return -1;
184     shape = (char *) piecedata[piece][rotation].shape;
185     for (y = 0; y < 4; y++) {
186 	for (x = 0; x < 4; x++) {
187 	    buf[y][x] = *shape++ ? piece%5 + 1 : 0;
188 	}
189     }
190     return 0;
191 }
192 
193 /*************************************************************************/
194 /*************************************************************************/
195 
196 /* Return the number of milliseconds of delay between piece drops for the
197  * current level.
198  */
199 
level_delay()200 static int level_delay()
201 {
202     int level = levels[my_playernum-1];
203     int delay = 1000;
204 
205     while (--level)
206 	delay = (delay*69+35)/70;   /* multiply by 69/70 and round */
207     return delay;
208 }
209 
210 /*************************************************************************/
211 
212 /* Return whether the piece in the position given by the x, y, and rot
213  * variables (interpreted the same way as current_*) would overlap any
214  * other blocks in the field.  A value of -1 means use the current_* value.
215  */
216 
piece_overlaps(int x,int y,int rot)217 static int piece_overlaps(int x, int y, int rot)
218 {
219     Field *f = &fields[my_playernum-1];
220     PieceData *pd;
221     int i, j, ok;
222 
223     if (x < 0)
224 	x = current_x;
225     if (y < 0)
226 	y = current_y;
227     if (rot < 0)
228 	rot = current_rotation;
229     pd = &piecedata[current_piece][rot];
230     x -= pd->hot_x;
231     y -= pd->hot_y;
232     ok = 1;
233     for (j = 0; ok && j < 4; j++) {
234 	if (y+j < 0)
235 	    continue;
236 	for (i = 0; ok && i < 4; i++) {
237 	    if (pd->shape[j][i] && (y+j >= FIELD_HEIGHT || x+i < 0
238 				 || x+i >= FIELD_WIDTH || (*f)[y+j][x+i]))
239 		ok = 0;
240 	}
241     }
242     return !ok;
243 }
244 
245 /*************************************************************************/
246 
247 /* Draw the piece in its current position on the board.  If draw == 0, then
248  * erase the piece rather than drawing it.
249  */
250 
draw_piece(int draw)251 static void draw_piece(int draw)
252 {
253     Field *f = &fields[my_playernum-1];
254     char c = draw ? current_piece % 5 + 1 : 0;
255     int x = current_x - piecedata[current_piece][current_rotation].hot_x;
256     int y = current_y - piecedata[current_piece][current_rotation].hot_y;
257     char *shape = (char *) piecedata[current_piece][current_rotation].shape;
258     int i, j;
259 
260     for (j = 0; j < 4; j++) {
261 	if (y+j < 0) {
262 	    shape += 4;
263 	    continue;
264 	}
265 	for (i = 0; i < 4; i++) {
266 	    if (*shape++)
267 		(*f)[y+j][x+i] = c;
268 	}
269     }
270 }
271 
272 /*************************************************************************/
273 
274 /* Clear any full lines on the field; return the number of lines cleared. */
275 
clear_lines(int add_specials)276 static int clear_lines(int add_specials)
277 {
278     Field *f = &fields[my_playernum-1];
279     int x, y, count = 0, i, j, k;
280     int new_specials[9];
281 
282     for (y = 0; y < FIELD_HEIGHT; y++) {
283 	int full = 1;
284 	for (x = 0; x < FIELD_WIDTH; x++) {
285 	    if ((*f)[y][x] == 0) {
286 		full = 0;
287 		break;
288 	    }
289 	}
290 	if (full)
291 	    count++;
292     }
293 
294     memset(new_specials, 0, sizeof(new_specials));
295     for (y = 0; y < FIELD_HEIGHT; y++) {
296 	int full = 1;
297 	for (x = 0; x < FIELD_WIDTH; x++) {
298 	    if ((*f)[y][x] == 0) {
299 		full = 0;
300 		break;
301 	    }
302 	}
303 	if (full) {
304 	    for (x = 0; x < FIELD_WIDTH; x++) {
305 		if ((*f)[y][x] > 5)
306 		    new_specials[(*f)[y][x]-6]++;
307 	    }
308 	    if (y > 0)
309 		memmove((*f)[1], (*f)[0], FIELD_WIDTH*y);
310 	    memset((*f)[0], 0, FIELD_WIDTH);
311 	}
312     }
313 
314     if (add_specials) {
315 	int pos = 0;
316 	while (pos < special_capacity && specials[pos] >= 0)
317 	    pos++;
318 	for (i = 0; i < count && pos < special_capacity; i++) {
319 	    for (j = 0; j < 9 && pos < special_capacity; j++) {
320 		for (k = 0; k < new_specials[j] && pos < special_capacity; k++){
321 		    if (windows_mode && rand()%2) {
322 			memmove(specials+1, specials, pos);
323 			specials[0] = j;
324 			pos++;
325 		    } else
326 			specials[pos++] = j;
327 		}
328 	    }
329 	}
330 	if (pos < special_capacity)
331 	    specials[pos] = -1;
332 	io->draw_specials();
333     }
334 
335     return count;
336 }
337 
338 /*************************************************************************/
339 
340 /* Place the given number of specials on the field.  If there aren't enough
341  * blocks to replace, replace all of the blocks and drop the rest of the
342  * specials.
343  */
344 
place_specials(int num)345 static void place_specials(int num)
346 {
347     Field *f = &fields[my_playernum-1];
348     int nblocks = 0, left;
349     int x, y, tries;
350 
351     for (y = 0; y < FIELD_HEIGHT; y++) {
352 	for (x = 0; x < FIELD_WIDTH; x++) {
353 	    if ((*f)[y][x])
354 		nblocks++;
355 	}
356     }
357     if (num > nblocks)
358 	num = nblocks;
359     left = num;
360     tries = 10;
361     while (left > 0 && tries > 0) {
362 	for (y = 0; left > 0 && y < FIELD_HEIGHT; y++) {
363 	    for (x = 0; left > 0 && x < FIELD_WIDTH; x++) {
364 		if ((*f)[y][x] > 5 || (*f)[y][x] == 0)
365 		    continue;
366 		if (rand() % nblocks < num) {
367 		    int which = 0, n = rand() % 100;
368 		    while (n >= specialfreq[which]) {
369 			n -= specialfreq[which];
370 			which++;
371 		    }
372 		    (*f)[y][x] = 6 + which;
373 		    left--;
374 		}
375 	    }
376 	}
377 	tries--;
378     }
379 }
380 
381 /*************************************************************************/
382 
383 /* Send the new field, either as differences from the given old field or
384  * (if more efficient) as a complete field.  If oldfield is NULL, always
385  * send the complete field.
386  */
387 
send_field(Field * oldfield)388 static void send_field(Field *oldfield)
389 {
390     Field *f = &fields[my_playernum-1];
391     int i, x, y, diff = 0;
392     char buf[512], *s;
393 
394     if (oldfield) {
395 	for (y = 0; y < FIELD_HEIGHT; y++) {
396 	    for (x = 0; x < FIELD_WIDTH; x++) {
397 		if ((*f)[y][x] != (*oldfield)[y][x])
398 		    diff++;
399 	    }
400 	}
401     } else {
402 	diff = FIELD_WIDTH * FIELD_HEIGHT;
403     }
404     if (diff < (FIELD_WIDTH*FIELD_HEIGHT)/2) {
405 	s = buf + sprintf(buf, "f %d ", my_playernum);
406 	for (i = 0; i < 15; i++) {
407 	    int seen = 0;   /* Have we seen a difference of this block? */
408 	    for (y = 0; y < FIELD_HEIGHT; y++) {
409 		for (x = 0; x < FIELD_WIDTH; x++) {
410 		    if ((*f)[y][x] == i && (*f)[y][x] != (*oldfield)[y][x]) {
411 			if (!seen) {
412 			    *s++ = i + '!';
413 			    seen = 1;
414 			}
415 			*s++ = x + '3';
416 			*s++ = y + '3';
417 		    }
418 		} /* for x */
419 	    } /* for y */
420 	} /* for i (each tile type) */
421     } /* difference check */
422     /* -4 below is to adjust for "f %d " */
423     if (diff >= (FIELD_WIDTH*FIELD_HEIGHT)/2
424 				|| strlen(buf)-4 > FIELD_WIDTH*FIELD_HEIGHT) {
425 	static const char specials[] = "acnrsbgqo";
426 	s = buf + sprintf(buf, "f %d ", my_playernum);
427 	for (y = 0; y < FIELD_HEIGHT; y++) {
428 	    for (x = 0; x < FIELD_WIDTH; x++) {
429 		if ((*f)[y][x] > 5)
430 		    *s++ = specials[(*f)[y][x]-6];
431 		else
432 		    *s++ = (*f)[y][x] + '0';
433 	    }
434 	}
435     }
436     *s = 0;
437     sputs(buf, server_sock);
438 }
439 
440 /*************************************************************************/
441 /*************************************************************************/
442 
443 /* Generate a new piece and set up the timer. */
444 
new_piece(void)445 void new_piece(void)
446 {
447     int n;
448     PieceData *pd;
449 
450     current_piece = next_piece;
451     n = rand() % 100;
452     next_piece = 0;
453     while (n >= piecefreq[next_piece] && next_piece < 6) {
454 	n -= piecefreq[next_piece];
455 	next_piece++;
456     }
457     current_rotation = 0;
458     pd = &piecedata[current_piece][current_rotation];
459     current_x = 6;
460     current_y = pd->hot_y - pd->top;
461     if (piece_overlaps(-1, -1, -1)) {
462 	current_x--;
463 	if (piece_overlaps(-1, -1, -1)) {
464 	    current_x += 2;
465 	    if (piece_overlaps(-1, -1, -1)) {
466 		Field *f = &fields[my_playernum-1];
467 		int x, y;
468 		for (y = 0; y < FIELD_HEIGHT; y++) {
469 		    for (x = 0; x < FIELD_WIDTH; x++)
470 			(*f)[y][x] = rand()%5 + 1;
471 		}
472 		send_field(NULL);
473 		sockprintf(server_sock, "playerlost %d", my_playernum);
474 		playing_game = 0;
475 		not_playing_game = 1;
476 	    }
477 	}
478     }
479     draw_piece(1);
480     io->draw_status();
481     io->draw_own_field();
482     gettimeofday(&timeout, NULL);
483     timeout.tv_usec += level_delay() * 1000;
484     timeout.tv_sec += timeout.tv_usec / 1000000;
485     timeout.tv_usec %= 1000000;
486     piece_waiting = 0;
487 }
488 
489 /*************************************************************************/
490 
491 /* Step the current piece down one space.  If it's already as far as it can
492  * go, solidify it, check for completed lines, send the new field state,
493  * and start a new piece.
494  */
495 
step_down(void)496 void step_down(void)
497 {
498     Field *f = &fields[my_playernum-1];
499     PieceData *pd = &piecedata[current_piece][current_rotation];
500     int y = current_y - pd->hot_y;
501     int ynew;
502 
503     draw_piece(0);
504     ynew = current_y+1;
505     if (y+1 + pd->bottom < FIELD_HEIGHT && !piece_overlaps(-1, ynew, -1)) {
506 	current_y++;
507 	draw_piece(1);
508 	io->draw_own_field();
509 	gettimeofday(&timeout, NULL);
510 	timeout.tv_usec += level_delay() * 1000;
511 	timeout.tv_sec += timeout.tv_usec / 1000000;
512 	timeout.tv_usec %= 1000000;
513     } else {
514 	int completed, level, nspecials;
515 	Field oldfield;
516 	char buf[16];
517 
518 	memcpy(&oldfield, f, sizeof(oldfield));
519 	draw_piece(1);
520 	if (last_special > lines)	/* i.e. from a previous game */
521 	    last_special = 0;
522 	completed = clear_lines(1);
523 	lines += completed;
524 	if (old_mode && completed > 1) {
525 	    if (completed < 4)
526 		completed--;
527 	    sockprintf(server_sock, "sb 0 cs%d %d", completed, my_playernum);
528 	    sprintf(buf, "cs%d", completed);
529 	    io->draw_attdef(buf, my_playernum, 0);
530 	}
531 	level = initial_level + (lines / lines_per_level) * level_inc;
532 	if (level > 100)
533 	    level = 100;
534 	levels[my_playernum] = level;
535 	if (completed > 0) {
536 	    sockprintf(server_sock, "lvl %d %d", my_playernum, level);
537 	    io->draw_status();
538 	}
539 	nspecials = (lines - last_special) / special_lines;
540 	last_special += nspecials * special_lines;
541 	nspecials *= special_count;
542 	place_specials(nspecials);
543 	io->draw_own_field();
544 	send_field(&oldfield);
545 	piece_waiting = 1;
546 	gettimeofday(&timeout, NULL);
547 	timeout.tv_usec += tetrifast ? 0 : 600000;
548 	timeout.tv_sec += timeout.tv_usec / 1000000;
549 	timeout.tv_usec %= 1000000;
550     }
551 }
552 
553 /*************************************************************************/
554 
555 /* Do something for a special block. */
556 
do_special(const char * type,int from,int to)557 void do_special(const char *type, int from, int to)
558 {
559     Field *f = &fields[my_playernum-1];
560     Field oldfield;
561     int x, y;
562 
563     io->draw_attdef(type, from, to);
564 
565     if (!playing_game)
566 	return;
567     if (to != 0 && to != my_playernum && !(from==my_playernum && *type=='s'))
568 	return;
569 
570     if (!piece_waiting)
571 	draw_piece(0);
572 
573     memcpy(&oldfield, f, sizeof(Field));
574 
575     if (strncmp(type, "cs", 2) == 0) {
576 	int nlines = atoi(type+2);
577 
578 	/* Don't add lines from a team member */
579 	if (!teams[my_playernum-1]
580 	 || !teams[from-1]
581 	 || strcmp(teams[my_playernum-1],teams[from-1]) != 0
582 	) {
583 	    while (nlines--) {
584 		memmove((*f)[0], (*f)[1], FIELD_WIDTH*(FIELD_HEIGHT-1));
585 		for (x = 0; x < FIELD_WIDTH; x++)
586 		    (*f)[21][x] = 1 + rand()%5;
587 		(*f)[FIELD_HEIGHT-1][rand()%FIELD_WIDTH] = 0;
588 	    }
589 	}
590 
591     } else if (*type == 'a') {
592 	memmove((*f)[0], (*f)[1], FIELD_WIDTH*(FIELD_HEIGHT-1));
593 	for (x = 0; x < FIELD_WIDTH; x++)
594 	    (*f)[21][x] = 1 + rand()%5;
595 	(*f)[FIELD_HEIGHT-1][rand()%FIELD_WIDTH] = 0;
596 	(*f)[FIELD_HEIGHT-1][rand()%FIELD_WIDTH] = 0;
597 	(*f)[FIELD_HEIGHT-1][rand()%FIELD_WIDTH] = 0;
598 
599     } else if (*type == 'b') {
600 	for (y = 0; y < FIELD_HEIGHT; y++) {
601 	    for (x = 0; x < FIELD_WIDTH; x++) {
602 		if ((*f)[y][x] > 5)
603 		    (*f)[y][x] = rand()%5 + 1;
604 	    }
605 	}
606 
607     } else if (*type == 'c') {
608 	memmove((*f)[1], (*f)[0], FIELD_WIDTH*(FIELD_HEIGHT-1));
609 	memset((*f)[0], 0, FIELD_WIDTH);
610 
611     } else if (*type == 'g') {
612 	for (x = 0; x < FIELD_WIDTH; x++) {
613 	    y = FIELD_HEIGHT-1;
614 	    while (y > 0) {
615 		if ((*f)[y][x] == 0) {
616 		    int y2, allclear = 1;
617 		    for (y2 = y-1; allclear && y2 >= 0; y2--) {
618 			if ((*f)[y2][x])
619 			    allclear = 0;
620 		    }
621 		    if (allclear)
622 			break;
623 		    for (y2 = y-1; y2 >= 0; y2--)
624 			(*f)[y2+1][x] = (*f)[y2][x];
625 		    (*f)[0][x] = 0;
626 		} else
627 		    y--;
628 	    }
629 	}
630 	clear_lines(0);
631 
632     } else if (*type == 'n') {
633 	memset(*f, 0, FIELD_WIDTH*FIELD_HEIGHT);
634 
635     } else if (*type == 'o') {
636 	int tries, x2, y2, xnew, ynew;
637 
638 	for (y = 0; y < FIELD_HEIGHT; y++) {
639 	    for (x = 0; x < FIELD_WIDTH; x++) {
640 		if ((*f)[y][x] != 6 + SPECIAL_O)
641 		    continue;
642 		(*f)[y][x] = 0;
643 		for (y2 = y-1; y2 <= y+1; y2++) {
644 		    if (y2 < 0 || y2 >= FIELD_HEIGHT)
645 			continue;
646 		    for (x2 = x-1; x2 <= x+1; x2++) {
647 			if (x2 < 0 || x2 >= FIELD_WIDTH)
648 			    continue;
649 			if (!windows_mode && !(*f)[y2][x2])
650 			    continue;
651 			tries = 10;
652 			while (tries--) {
653 			    xnew = random() % FIELD_WIDTH;
654 			    ynew = FIELD_HEIGHT-1 - random()%16;
655 			    if (windows_mode || !(*f)[ynew][xnew]) {
656 				(*f)[ynew][xnew] = (*f)[y2][x2];
657 				break;
658 			    }
659 			}
660 			(*f)[y2][x2] = 0;
661 		    }
662 		}
663 	    }
664 	}
665 	clear_lines(0);
666 
667     } else if (*type == 'q') {
668 	for (y = 0; y < FIELD_HEIGHT; y++) {
669 	    int r = rand()%3 - 1;
670 	    if (r < 0) {
671 		int save = (*f)[y][0];
672 		memmove((*f)[y], (*f)[y]+1, FIELD_WIDTH-1);
673 		if (windows_mode)
674 		    (*f)[y][FIELD_WIDTH-1] = 0;
675 		else
676 		    (*f)[y][FIELD_WIDTH-1] = save;
677 	    } else if (r > 0) {
678 		int save = (*f)[y][FIELD_WIDTH-1];
679 		memmove((*f)[y]+1, (*f)[y], FIELD_WIDTH-1);
680 		if (windows_mode)
681 		    (*f)[y][0] = 0;
682 		else
683 		    (*f)[y][0] = save;
684 	    }
685 	}
686 
687     } else if (*type == 'r') {
688 	int i;
689 
690 	for (i = 0; i < 10; i++) {
691 	    x = rand() % FIELD_WIDTH;
692 	    y = rand() % FIELD_HEIGHT;
693 	    if ((*f)[y][x] != 0) {
694 		(*f)[y][x] = 0;
695 		break;
696 	    }
697 	}
698 
699     } else if (*type == 's') {
700 	Field temp;
701 
702 	memcpy(temp, fields[from-1], sizeof(Field));
703 	memcpy(fields[from-1], fields[to-1], sizeof(Field));
704 	memcpy(fields[to-1], temp, sizeof(Field));
705 	if (from == my_playernum || to == my_playernum)
706 	    memset(fields[my_playernum-1], 0, 6*FIELD_WIDTH);
707 	if (from != my_playernum)
708 	    io->draw_other_field(from);
709 	if (to != my_playernum)
710 	    io->draw_other_field(to);
711 
712     }
713 
714     send_field(&oldfield);
715 
716     if (!piece_waiting) {
717 	while (piece_overlaps(-1, -1, -1))
718 	    current_y--;
719 	draw_piece(1);
720     }
721     io->draw_own_field();
722 }
723 
724 /*************************************************************************/
725 /*************************************************************************/
726 
727 /* Deal with the in-game message input buffer. */
728 
729 static char gmsg_buffer[512];
730 static int gmsg_pos;
731 
732 #define curpos	(gmsg_buffer+gmsg_pos)
733 
734 /*************************************************************************/
735 
gmsg_input(int c)736 static void gmsg_input(int c)
737 {
738     if (gmsg_pos < sizeof(gmsg_buffer) - 1) {
739 	memmove(curpos+1, curpos, strlen(curpos)+1);
740 	gmsg_buffer[gmsg_pos++] = c;
741 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
742     }
743 }
744 
745 /*************************************************************************/
746 
gmsg_delete(void)747 static void gmsg_delete(void)
748 {
749     if (gmsg_buffer[gmsg_pos]) {
750 	memmove(curpos, curpos+1, strlen(curpos)-1+1);
751 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
752     }
753 }
754 
755 /*************************************************************************/
756 
gmsg_backspace(void)757 static void gmsg_backspace(void)
758 {
759     if (gmsg_pos > 0) {
760 	gmsg_pos--;
761 	gmsg_delete();
762     }
763 }
764 
765 /*************************************************************************/
766 
gmsg_kill(void)767 static void gmsg_kill(void)
768 {
769     gmsg_pos = 0;
770     *gmsg_buffer = 0;
771     io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
772 }
773 
774 /*************************************************************************/
775 
gmsg_move(int how)776 static void gmsg_move(int how)
777 {
778     if (how == -2) {
779 	gmsg_pos = 0;
780 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
781     } else if (how == -1 && gmsg_pos > 0) {
782 	gmsg_pos--;
783 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
784     } else if (how == 1 && gmsg_buffer[gmsg_pos]) {
785 	gmsg_pos++;
786 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
787     } else if (how == 2) {
788 	gmsg_pos = strlen(gmsg_buffer);
789 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
790     }
791 }
792 
793 /*************************************************************************/
794 
gmsg_enter(void)795 static void gmsg_enter(void)
796 {
797     if (*gmsg_buffer) {
798 	if (strncasecmp(gmsg_buffer, "/me ", 4) == 0)
799 	    sockprintf(server_sock, "gmsg * %s %s", players[my_playernum-1], gmsg_buffer+4);
800 	else
801 	    sockprintf(server_sock, "gmsg <%s> %s", players[my_playernum-1], gmsg_buffer);
802 	gmsg_pos = 0;
803 	*gmsg_buffer = 0;
804 	io->clear_gmsg_input();
805     }
806 }
807 
808 #undef curpos
809 
810 /*************************************************************************/
811 /*************************************************************************/
812 
813 /* Set up for a new game. */
814 
new_game(void)815 void new_game(void)
816 {
817     int n;
818 
819     gettimeofday(&timeout, NULL);
820     timeout.tv_usec += 1200000;
821     timeout.tv_sec += timeout.tv_usec / 1000000;
822     timeout.tv_usec %= 1000000;
823     piece_waiting = 1;
824     n = rand() % 100;
825     next_piece = 0;
826     while (n >= piecefreq[next_piece] && next_piece < 6) {
827 	n -= piecefreq[next_piece];
828 	next_piece++;
829     }
830 }
831 
832 /*************************************************************************/
833 
834 /* Return the number of milliseconds until we want to do something. */
835 
tetris_timeout(void)836 int tetris_timeout(void)
837 {
838     struct timeval tv;
839     int t;
840 
841     gettimeofday(&tv, NULL);
842     t = (timeout.tv_sec - tv.tv_sec) * 1000
843       + (timeout.tv_usec-tv.tv_usec) / 1000;
844     return t<0 ? 0 : t;
845 }
846 
847 /*************************************************************************/
848 
849 /* Do something when we hit a timeout. */
850 
tetris_timeout_action(void)851 void tetris_timeout_action(void)
852 {
853     if (piece_waiting)
854 	new_piece();
855     else
856 	step_down();
857 }
858 
859 /*************************************************************************/
860 
861 /* Do something with a character of input. */
862 
863 static const char special_chars[] = "acnrsbgqo";
864 
tetris_input(int c)865 void tetris_input(int c)
866 {
867     PieceData *pd = &piecedata[current_piece][current_rotation];
868     int x = current_x - pd->hot_x;
869     int y = current_y - pd->hot_y;
870     int rnew, ynew;
871     static int gmsg_active = 0;
872 
873     if (gmsg_active) {
874 	if (c == 8 || c == 127)   /* Backspace or Delete */
875 	    gmsg_backspace();
876 	else if (c == 4)    /* Ctrl-D */
877 	    gmsg_delete();
878 	else if (c == 21)   /* Ctrl-U */
879 	    gmsg_kill();
880 	else if (c == K_LEFT)
881 	    gmsg_move(-1);
882 	else if (c == K_RIGHT)
883 	    gmsg_move(1);
884 	else if (c == 1)    /* Ctrl-A */
885 	    gmsg_move(-2);
886 	else if (c == 5)    /* Ctrl-E */
887 	    gmsg_move(2);
888 	else if (c == '\r' || c == '\n') {
889 	    gmsg_enter();
890 	    gmsg_active = 0;
891 	} else if (c == 27) {  /* Escape */
892 	    io->clear_gmsg_input();
893 	    gmsg_active = 0;
894 	} else if (c >= 1 && c <= 0xFF)
895 	    gmsg_input(c);
896 	return;
897     }
898 
899     if (c != 't' && (!playing_game || game_paused))
900 	return;
901 
902     switch (c) {
903       case K_UP:	/* Rotate clockwise */
904       case 'x':
905 	if (piece_waiting)
906 	    break;
907 	rnew = (current_rotation+1) % 4;
908 	pd = &piecedata[current_piece][current_rotation];
909 	x = current_x - pd->hot_x;
910 	y = current_y - pd->hot_y;
911 	if (x + pd->left < 0 || x + pd->right >= FIELD_WIDTH
912 	 || y + pd->bottom >= FIELD_HEIGHT)
913 	    break;
914 	draw_piece(0);
915 	if (!piece_overlaps(-1, -1, rnew)) {
916 	    current_rotation = rnew;
917 	    draw_piece(1);
918 	    io->draw_own_field();
919 	} else {
920 	    draw_piece(1);
921 	}
922 	break;
923 
924       case 'z':		/* Rotate counterclockwise */
925 	if (piece_waiting)
926 	    break;
927 	rnew = (current_rotation+3) % 4;
928 	pd = &piecedata[current_piece][current_rotation];
929 	x = current_x - pd->hot_x;
930 	y = current_y - pd->hot_y;
931 	if (x + pd->left < 0 || x + pd->right >= FIELD_WIDTH
932 	 || y + pd->bottom >= FIELD_HEIGHT)
933 	    break;
934 	draw_piece(0);
935 	if (!piece_overlaps(-1, -1, rnew)) {
936 	    current_rotation = rnew;
937 	    draw_piece(1);
938 	    io->draw_own_field();
939 	} else {
940 	    draw_piece(1);
941 	}
942 	break;
943 
944       case K_LEFT:	/* Move left */
945 	if (piece_waiting)
946 	    break;
947 	if (x + pd->left > 0) {
948 	    draw_piece(0);
949 	    if (!piece_overlaps(current_x-1, -1, -1)) {
950 		current_x--;
951 		draw_piece(1);
952 		io->draw_own_field();
953 	    } else {
954 		draw_piece(1);
955 	    }
956 	}
957 	break;
958 
959       case K_RIGHT:	/* Move right */
960 	if (piece_waiting)
961 	    break;
962 	if (x + pd->right < FIELD_WIDTH-1) {
963 	    draw_piece(0);
964 	    if (!piece_overlaps(current_x+1, -1, -1)) {
965 		current_x++;
966 		draw_piece(1);
967 		io->draw_own_field();
968 	    } else {
969 		draw_piece(1);
970 	    }
971 	}
972 	break;
973 
974       case K_DOWN:	/* Down one space */
975 	if (piece_waiting)
976 	    break;
977 	step_down();
978 	break;
979 
980       case ' ':		/* Down until the piece hits something */
981 	if (piece_waiting)
982 	    break;
983 	draw_piece(0);
984 	ynew = current_y+1;
985 	while (y + pd->bottom < FIELD_HEIGHT && !piece_overlaps(-1,ynew,-1)) {
986 	    ynew++;
987 	    y++;
988 	}
989 	ynew--;
990 	if (ynew != current_y) {
991 	    current_y = ynew-1;
992 	    if (noslide)
993 		current_y++;	/* Don't allow sliding */
994 	    step_down();
995 	} else {
996 	    draw_piece(1);
997 	}
998 	break;
999 
1000       case 'd':
1001 	if (specials[0] == -1)
1002 	    break;
1003 	if (special_capacity > 1)
1004 	    memmove(specials, specials+1, special_capacity-1);
1005 	specials[special_capacity-1] = -1;
1006 	io->draw_specials();
1007 	break;
1008 
1009       case '1':
1010       case '2':
1011       case '3':
1012       case '4':
1013       case '5':
1014       case '6': {
1015 	char buf[2];
1016 
1017 	c -= '0';
1018 	if (!players[c-1])
1019 	    break;
1020 	if (specials[0] == -1)
1021 	    break;
1022 	sockprintf(server_sock, "sb %d %c %d",
1023 			c, special_chars[(int) specials[0]], my_playernum);
1024 	buf[0] = special_chars[(int) specials[0]];
1025 	buf[1] = 0;
1026 	do_special(buf, my_playernum, c);
1027 	if (special_capacity > 1)
1028 	    memmove(specials, specials+1, special_capacity-1);
1029 	specials[special_capacity-1] = -1;
1030 	io->draw_specials();
1031 	break;
1032       }
1033 
1034       case 't':
1035 	gmsg_active = 1;
1036 	io->draw_gmsg_input(gmsg_buffer, gmsg_pos);
1037 	break;
1038 
1039     } /* switch (c) */
1040 }
1041 
1042 /*************************************************************************/
1043 
1044 #endif	/* !SERVER_ONLY */
1045 
1046 /*************************************************************************/
1047