Automagically switch from/to the playfield on game end/start.
[tetrinet.git] / tetrinet.c
blobc14285941ced687b62b950a319c0bd66c0efdd9f
1 /* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
2 * This program is public domain.
4 * Tetrinet main program.
5 */
7 /*************************************************************************/
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <time.h>
13 #include <errno.h>
14 #include "tetrinet.h"
15 #include "io.h"
16 #include "server.h"
17 #include "sockets.h"
18 #include "tetris.h"
19 #include "version.h"
21 /*************************************************************************/
23 int fancy = 0; /* Fancy TTY graphics? */
24 int log = 0; /* Log network traffic to file? */
25 char *logname; /* Log filename */
26 int windows_mode = 0; /* Try to be just like the Windows version? */
27 int noslide = 0; /* Disallow piece sliding? */
28 int tetrifast = 0; /* TetriFast mode? */
29 int cast_shadow = 1; /* Make pieces cast shadow? */
31 int my_playernum = -1; /* What player number are we? */
32 char *my_nick; /* And what is our nick? */
33 WinInfo winlist[MAXWINLIST]; /* Winners' list from server */
34 int server_sock; /* Socket for server communication */
35 int dispmode; /* Current display mode */
36 char *players[6]; /* Player names (NULL for no such player) */
37 char *teams[6]; /* Team names (NULL for not on a team) */
38 int playing_game; /* Are we currently playing a game? */
39 int not_playing_game; /* Are we currently watching people play a game? */
40 int game_paused; /* Is the game currently paused? */
42 Interface *io; /* Input/output routines */
44 /*************************************************************************/
45 /*************************************************************************/
47 #ifndef SERVER_ONLY
49 /*************************************************************************/
51 /* Output message to a message buffer, possibly decoding the text attributes
52 * tetrinet code. */
54 void msg_text(int bufnum, const unsigned char *s)
56 /* Stolen from gtetrinet: (leading space <=> undefined) */
57 static enum tattr map[32] = {
58 0, /* N/A */
59 TATTR_CBLACK,
60 TATTR_BOLD,
61 TATTR_CCYAN | TATTR_CXBRIGHT,
62 TATTR_CBLACK,
63 TATTR_CBLUE | TATTR_CXBRIGHT,
64 TATTR_CGREY,
65 TATTR_CBLACK,
66 TATTR_CMAGENTA,
67 TATTR_CBLACK,
68 TATTR_CBLACK,
69 TATTR_CBLACK | TATTR_CXBRIGHT,
70 TATTR_CGREEN,
71 TATTR_CBLACK,
72 TATTR_CGREEN | TATTR_CXBRIGHT,
73 TATTR_CGREY,
74 TATTR_CRED,
75 TATTR_CBLUE,
76 TATTR_CBROWN,
77 TATTR_CMAGENTA | TATTR_CXBRIGHT,
78 TATTR_CRED | TATTR_CXBRIGHT,
79 TATTR_CGREY,
80 TATTR_ITALIC,
81 TATTR_CCYAN,
82 TATTR_CGREY | TATTR_CXBRIGHT,
83 TATTR_CBROWN | TATTR_CXBRIGHT,
84 TATTR_CBLACK,
85 TATTR_CBLACK,
86 TATTR_CBLACK,
87 TATTR_CBLACK,
88 TATTR_CBLACK,
89 TATTR_UNDERLINE,
91 unsigned char tb[1024], *t;
93 for (t = tb; *s && t - tb < 1024; t++, s++) {
94 if (*s == 0xFF) {
95 *t = TATTR_RESET + 1;
96 } else if (*s < 32) {
97 *t = map[(int) *s] + 1;
98 } else {
99 *t = *s;
102 if (t - tb >= 1024) t = &tb[1023];
103 *t = 0;
105 io->draw_text(bufnum, tb);
109 /* Parse a line from the server. Destroys the buffer it's given as a side
110 * effect.
113 void parse(char *buf)
115 char *cmd, *s, *t;
117 cmd = strtok(buf, " ");
119 if (!cmd) {
120 return;
122 } else if (strcmp(cmd, "noconnecting") == 0) {
123 s = strtok(NULL, "");
124 if (!s)
125 s = "Unknown";
126 /* XXX not to stderr, please! -- we need to stay running w/o server */
127 fprintf(stderr, "Server error: %s\n", s);
128 exit(1);
130 } else if (strcmp(cmd, "winlist") == 0) {
131 int i = 0;
133 while (i < MAXWINLIST && (s = strtok(NULL, " "))) {
134 t = strchr(s, ';');
135 if (!t)
136 break;
137 *t++ = 0;
138 if (*s == 't')
139 winlist[i].team = 1;
140 else
141 winlist[i].team = 0;
142 s++;
143 strncpy(winlist[i].name, s, sizeof(winlist[i].name)-1);
144 winlist[i].name[sizeof(winlist[i].name)] = 0;
145 winlist[i].points = atoi(t);
146 if ((t = strchr(t, ';')) != NULL)
147 winlist[i].games = atoi(t+1);
148 i++;
150 if (i < MAXWINLIST)
151 winlist[i].name[0] = 0;
152 if (dispmode == MODE_WINLIST)
153 io->setup_winlist();
155 } else if (strcmp(cmd, tetrifast ? ")#)(!@(*3" : "playernum") == 0) {
156 if ((s = strtok(NULL, " ")))
157 my_playernum = atoi(s);
158 /* Note: players[my_playernum-1] is set in init() */
159 /* But that doesn't work when joining other channel. */
160 players[my_playernum-1] = strdup(my_nick);
162 } else if (strcmp(cmd, "playerjoin") == 0) {
163 int player;
164 char buf[1024];
166 s = strtok(NULL, " ");
167 t = strtok(NULL, "");
168 if (!s || !t)
169 return;
170 player = atoi(s)-1;
171 if (player < 0 || player > 5)
172 return;
173 players[player] = strdup(t);
174 if (teams[player]) {
175 free(teams[player]);
176 teams[player] = NULL;
178 snprintf(buf, sizeof(buf), "*** %s is Now Playing", t);
179 msg_text(BUFFER_PLINE, buf);
180 if (dispmode == MODE_FIELDS)
181 io->setup_fields();
183 } else if (strcmp(cmd, "playerleave") == 0) {
184 int player;
185 char buf[1024];
187 s = strtok(NULL, " ");
188 if (!s)
189 return;
190 player = atoi(s)-1;
191 if (player < 0 || player > 5 || !players[player])
192 return;
193 snprintf(buf, sizeof(buf), "*** %s has Left", players[player]);
194 msg_text(BUFFER_PLINE, buf);
195 free(players[player]);
196 players[player] = NULL;
197 if (dispmode == MODE_FIELDS)
198 io->setup_fields();
200 } else if (strcmp(cmd, "team") == 0) {
201 int player;
202 char buf[1024];
204 s = strtok(NULL, " ");
205 t = strtok(NULL, "");
206 if (!s)
207 return;
208 player = atoi(s)-1;
209 if (player < 0 || player > 5 || !players[player])
210 return;
211 if (teams[player])
212 free(teams[player]);
213 if (t)
214 teams[player] = strdup(t);
215 else
216 teams[player] = NULL;
217 if (t)
218 snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[player], t);
219 else
220 snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[player]);
221 msg_text(BUFFER_PLINE, buf);
223 } else if (strcmp(cmd, "pline") == 0) {
224 int playernum;
225 char buf[1024], *name;
227 s = strtok(NULL, " ");
228 t = strtok(NULL, "");
229 if (!s)
230 return;
231 if (!t)
232 t = "";
233 playernum = atoi(s)-1;
234 if (playernum == -1) {
235 name = "Server";
236 } else {
237 if (playernum < 0 || playernum > 5 || !players[playernum])
238 return;
239 name = players[playernum];
241 snprintf(buf, sizeof(buf), "<%s> %s", name, t);
242 msg_text(BUFFER_PLINE, buf);
244 } else if (strcmp(cmd, "plineact") == 0) {
245 int playernum;
246 char buf[1024], *name;
248 s = strtok(NULL, " ");
249 t = strtok(NULL, "");
250 if (!s)
251 return;
252 if (!t)
253 t = "";
254 playernum = atoi(s)-1;
255 if (playernum == -1) {
256 name = "Server";
257 } else {
258 if (playernum < 0 || playernum > 5 || !players[playernum])
259 return;
260 name = players[playernum];
262 snprintf(buf, sizeof(buf), "* %s %s", name, t);
263 msg_text(BUFFER_PLINE, buf);
265 } else if (strcmp(cmd, tetrifast ? "*******" : "newgame") == 0) {
266 int i;
268 if ((s = strtok(NULL, " ")))
269 /* stack height */;
270 if ((s = strtok(NULL, " ")))
271 initial_level = atoi(s);
272 if ((s = strtok(NULL, " ")))
273 lines_per_level = atoi(s);
274 if ((s = strtok(NULL, " ")))
275 level_inc = atoi(s);
276 if ((s = strtok(NULL, " ")))
277 special_lines = atoi(s);
278 if ((s = strtok(NULL, " ")))
279 special_count = atoi(s);
280 if ((s = strtok(NULL, " "))) {
281 special_capacity = atoi(s);
282 if (special_capacity > MAX_SPECIALS)
283 special_capacity = MAX_SPECIALS;
285 if ((s = strtok(NULL, " "))) {
286 memset(piecefreq, 0, sizeof(piecefreq));
287 while (*s) {
288 i = *s - '1';
289 if (i >= 0 && i < 7)
290 piecefreq[i]++;
291 s++;
294 if ((s = strtok(NULL, " "))) {
295 memset(specialfreq, 0, sizeof(specialfreq));
296 while (*s) {
297 i = *s - '1';
298 if (i >= 0 && i < 9)
299 specialfreq[i]++;
300 s++;
303 if ((s = strtok(NULL, " ")))
304 level_average = atoi(s);
305 if ((s = strtok(NULL, " ")))
306 old_mode = atoi(s);
307 lines = 0;
308 for (i = 0; i < 6; i++)
309 levels[i] = initial_level;
310 memset(&fields[my_playernum-1], 0, sizeof(Field));
311 specials[0] = -1;
312 io->clear_text(BUFFER_GMSG);
313 io->clear_text(BUFFER_ATTDEF);
314 new_game();
315 playing_game = 1;
316 game_paused = 0;
317 msg_text(BUFFER_PLINE, "*** The Game Has Started");
318 if (dispmode != MODE_FIELDS) {
319 dispmode = MODE_FIELDS;
320 io->setup_fields();
323 } else if (strcmp(cmd, "ingame") == 0) {
324 /* Sent when a player connects in the middle of a game */
325 int x, y;
326 char buf[1024], *s;
328 s = buf + sprintf(buf, "f %d ", my_playernum);
329 for (y = 0; y < FIELD_HEIGHT; y++) {
330 for (x = 0; x < FIELD_WIDTH; x++) {
331 fields[my_playernum-1][y][x] = rand()%5 + 1;
332 *s++ = '0' + fields[my_playernum-1][y][x];
335 *s = 0;
336 sputs(buf, server_sock);
337 playing_game = 0;
338 not_playing_game = 1;
340 } else if (strcmp(cmd, "pause") == 0) {
341 if ((s = strtok(NULL, " ")))
342 game_paused = atoi(s);
343 if (game_paused) {
344 msg_text(BUFFER_PLINE, "*** The Game Has Been Paused");
345 msg_text(BUFFER_GMSG, "*** The Game Has Been Paused");
346 } else {
347 msg_text(BUFFER_PLINE, "*** The Game Has Been Unpaused");
348 msg_text(BUFFER_GMSG, "*** The Game Has Been Unpaused");
351 } else if (strcmp(cmd, "endgame") == 0) {
352 playing_game = 0;
353 not_playing_game = 0;
354 memset(fields, 0, sizeof(fields));
355 specials[0] = -1;
356 io->clear_text(BUFFER_ATTDEF);
357 msg_text(BUFFER_PLINE, "*** The Game Has Ended");
358 if (dispmode == MODE_FIELDS) {
359 int i;
360 io->draw_own_field();
361 for (i = 1; i <= 6; i++) {
362 if (i != my_playernum)
363 io->draw_other_field(i);
366 if (dispmode != MODE_PARTYLINE) {
367 dispmode = MODE_PARTYLINE;
368 io->setup_partyline();
371 } else if (strcmp(cmd, "playerwon") == 0) {
372 /* Syntax: playerwon # -- sent when all but one player lose */
374 } else if (strcmp(cmd, "playerlost") == 0) {
375 /* Syntax: playerlost # -- sent after playerleave on disconnect
376 * during a game, or when a player loses (sent by the losing
377 * player and from the server to all other players */
379 } else if (strcmp(cmd, "f") == 0) { /* field */
380 int player, x, y, tile;
382 /* This looks confusing, but what it means is, ignore this message
383 * if a game isn't going on. */
384 if (!playing_game && !not_playing_game)
385 return;
386 if (!(s = strtok(NULL, " ")))
387 return;
388 player = atoi(s);
389 player--;
390 if (!(s = strtok(NULL, "")))
391 return;
392 if (*s >= '0') {
393 /* Set field directly */
394 char *ptr = (char *) fields[player];
395 while (*s) {
396 if (*s <= '5')
397 *ptr++ = (*s++) - '0';
398 else switch (*s++) {
399 case 'a': *ptr++ = 6 + SPECIAL_A; break;
400 case 'b': *ptr++ = 6 + SPECIAL_B; break;
401 case 'c': *ptr++ = 6 + SPECIAL_C; break;
402 case 'g': *ptr++ = 6 + SPECIAL_G; break;
403 case 'n': *ptr++ = 6 + SPECIAL_N; break;
404 case 'o': *ptr++ = 6 + SPECIAL_O; break;
405 case 'q': *ptr++ = 6 + SPECIAL_Q; break;
406 case 'r': *ptr++ = 6 + SPECIAL_R; break;
407 case 's': *ptr++ = 6 + SPECIAL_S; break;
410 } else {
411 /* Set specific locations on field */
412 tile = 0;
413 while (*s) {
414 if (*s < '0') {
415 tile = *s - '!';
416 } else {
417 x = *s - '3';
418 y = (*++s) - '3';
419 fields[player][y][x] = tile;
421 s++;
424 if (player == my_playernum-1)
425 io->draw_own_field();
426 else
427 io->draw_other_field(player+1);
428 } else if (strcmp(cmd, "lvl") == 0) {
429 int player;
431 if (!(s = strtok(NULL, " ")))
432 return;
433 player = atoi(s)-1;
434 if (!(s = strtok(NULL, "")))
435 return;
436 levels[player] = atoi(s);
438 } else if (strcmp(cmd, "sb") == 0) {
439 int from, to;
440 char *type;
442 if (!(s = strtok(NULL, " ")))
443 return;
444 to = atoi(s);
445 if (!(type = strtok(NULL, " ")))
446 return;
447 if (!(s = strtok(NULL, " ")))
448 return;
449 from = atoi(s);
450 do_special(type, from, to);
452 } else if (strcmp(cmd, "gmsg") == 0) {
453 if (!(s = strtok(NULL, "")))
454 return;
455 msg_text(BUFFER_GMSG, s);
460 /*************************************************************************/
461 /*************************************************************************/
463 static char partyline_buffer[512];
464 static int partyline_pos = 0;
466 #define curpos (partyline_buffer+partyline_pos)
468 /*************************************************************************/
470 /* Add a character to the partyline buffer. */
472 void partyline_input(int c)
474 if (partyline_pos < sizeof(partyline_buffer) - 1) {
475 memmove(curpos+1, curpos, strlen(curpos)+1);
476 partyline_buffer[partyline_pos++] = c;
477 io->draw_partyline_input(partyline_buffer, partyline_pos);
481 /*************************************************************************/
483 /* Delete the current character from the partyline buffer. */
485 void partyline_delete(void)
487 if (partyline_buffer[partyline_pos]) {
488 memmove(curpos, curpos+1, strlen(curpos)-1+1);
489 io->draw_partyline_input(partyline_buffer, partyline_pos);
493 /*************************************************************************/
495 /* Backspace a character from the partyline buffer. */
497 void partyline_backspace(void)
499 if (partyline_pos > 0) {
500 partyline_pos--;
501 partyline_delete();
505 /*************************************************************************/
507 /* Kill the entire partyline input buffer. */
509 void partyline_kill(void)
511 partyline_pos = 0;
512 *partyline_buffer = 0;
513 io->draw_partyline_input(partyline_buffer, partyline_pos);
516 /*************************************************************************/
518 /* Move around the input buffer. Sign indicates direction; absolute value
519 * of 1 means one character, 2 means the whole line.
522 void partyline_move(int how)
524 if (how == -2) {
525 partyline_pos = 0;
526 io->draw_partyline_input(partyline_buffer, partyline_pos);
527 } else if (how == -1 && partyline_pos > 0) {
528 partyline_pos--;
529 io->draw_partyline_input(partyline_buffer, partyline_pos);
530 } else if (how == 1 && partyline_buffer[partyline_pos]) {
531 partyline_pos++;
532 io->draw_partyline_input(partyline_buffer, partyline_pos);
533 } else if (how == 2) {
534 partyline_pos = strlen(partyline_buffer);
535 io->draw_partyline_input(partyline_buffer, partyline_pos);
539 /*************************************************************************/
541 /* Send the input line to the server. */
543 void partyline_enter(void)
545 char buf[1024];
547 if (*partyline_buffer) {
548 if (strncasecmp(partyline_buffer, "/me ", 4) == 0) {
549 sockprintf(server_sock, "plineact %d %s", my_playernum, partyline_buffer+4);
550 snprintf(buf, sizeof(buf), "* %s %s", players[my_playernum-1], partyline_buffer+4);
551 msg_text(BUFFER_PLINE, buf);
552 } else if (strcasecmp(partyline_buffer, "/start") == 0) {
553 sockprintf(server_sock, "startgame 1 %d", my_playernum);
554 } else if (strcasecmp(partyline_buffer, "/end") == 0) {
555 sockprintf(server_sock, "startgame 0 %d", my_playernum);
556 } else if (strcasecmp(partyline_buffer, "/pause") == 0) {
557 sockprintf(server_sock, "pause 1 %d", my_playernum);
558 } else if (strcasecmp(partyline_buffer, "/unpause") == 0) {
559 sockprintf(server_sock, "pause 0 %d", my_playernum);
560 } else if (strncasecmp(partyline_buffer, "/team", 5) == 0) {
561 if (strlen(partyline_buffer) == 5)
562 strcpy(partyline_buffer+5, " "); /* make it "/team " */
563 sockprintf(server_sock, "team %d %s", my_playernum, partyline_buffer+6);
564 if (partyline_buffer[6]) {
565 if (teams[my_playernum-1])
566 free(teams[my_playernum-1]);
567 teams[my_playernum-1] = strdup(partyline_buffer+6);
568 snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[my_playernum-1], partyline_buffer+6);
569 msg_text(BUFFER_PLINE, buf);
570 } else {
571 if (teams[my_playernum-1])
572 free(teams[my_playernum-1]);
573 teams[my_playernum-1] = NULL;
574 snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[my_playernum-1]);
575 msg_text(BUFFER_PLINE, buf);
577 } else {
578 sockprintf(server_sock, "pline %d %s", my_playernum, partyline_buffer);
579 if (*partyline_buffer != '/'
580 || partyline_buffer[1] == 0 || partyline_buffer[1] == ' ') {
581 /* We do not show server-side commands. */
582 snprintf(buf, sizeof(buf), "<%s> %s", players[my_playernum-1], partyline_buffer);
583 msg_text(BUFFER_PLINE, buf);
586 partyline_pos = 0;
587 *partyline_buffer = 0;
588 io->draw_partyline_input(partyline_buffer, partyline_pos);
592 #undef curpos
594 /*************************************************************************/
595 /*************************************************************************/
597 void help()
599 fprintf(stderr,
600 "Tetrinet " VERSION " - Text-mode tetrinet client\n"
601 "\n"
602 "Usage: tetrinet [OPTION]... NICK SERVER\n"
603 "\n"
604 "Options (see README for details):\n"
605 " -fancy Use \"fancy\" TTY graphics.\n"
606 " -fast Connect to the server in the tetrifast mode.\n"
607 " -log <file> Log network traffic to the given file.\n"
608 " -noshadow Do not make the pieces cast shadow.\n"
609 " -noslide Do not allow pieces to \"slide\" after being dropped\n"
610 " with the spacebar.\n"
611 " -server Start the server instead of the client.\n"
612 " -shadow Make the pieces cast shadow. Can speed up gameplay\n"
613 " considerably, but it can be considered as cheating by\n"
614 " some people since some other tetrinet clients lack this.\n"
615 " -slide Opposite of -noslide; allows pieces to \"slide\" after\n"
616 " being dropped. If both -slide and -noslide are given,\n"
617 " -slide takes precedence.\n"
618 " -windows Behave as much like the Windows version of Tetrinet as\n"
619 " possible. Implies -noslide and -noshadow.\n"
623 int init(int ac, char **av)
625 int i;
626 char *nick = NULL, *server = NULL;
627 char buf[1024];
628 char nickmsg[1024];
629 unsigned char ip[4];
630 char iphashbuf[32];
631 int len;
632 #ifdef BUILTIN_SERVER
633 int start_server = 0; /* Start the server? (-server) */
634 #endif
635 int slide = 0; /* Do we definitely want to slide? (-slide) */
638 /* If there's a DISPLAY variable set in the environment, default to
639 * Xwindows I/O, else default to terminal I/O. */
640 /* if (getenv("DISPLAY"))
641 io = &xwin_interface;
642 else
643 io = &tty_interface; */
644 io=&tty_interface; /* because Xwin isn't done yet */
646 srand(time(NULL));
647 init_shapes();
649 for (i = 1; i < ac; i++) {
650 if (*av[i] == '-') {
651 #ifdef BUILTIN_SERVER
652 if (strcmp(av[i], "-server") == 0) {
653 start_server = 1;
654 } else
655 #endif
656 if (strcmp(av[i], "-fancy") == 0) {
657 fancy = 1;
658 } else if (strcmp(av[i], "-log") == 0) {
659 log = 1;
660 i++;
661 if (i >= ac) {
662 fprintf(stderr, "Option -log requires an argument\n");
663 return 1;
665 logname = av[i];
666 } else if (strcmp(av[i], "-noslide") == 0) {
667 noslide = 1;
668 } else if (strcmp(av[i], "-noshadow") == 0) {
669 cast_shadow = 0;
670 } else if (strcmp(av[i], "-shadow") == 0) {
671 cast_shadow = 1;
672 } else if (strcmp(av[i], "-slide") == 0) {
673 slide = 1;
674 } else if (strcmp(av[i], "-windows") == 0) {
675 windows_mode = 1;
676 noslide = 1;
677 cast_shadow = 0;
678 } else if (strcmp(av[i], "-fast") == 0) {
679 tetrifast = 1;
680 } else {
681 fprintf(stderr, "Unknown option %s\n", av[i]);
682 help();
683 return 1;
685 } else if (!nick) {
686 my_nick = nick = av[i];
687 } else if (!server) {
688 server = av[i];
689 } else {
690 help();
691 return 1;
694 if (slide)
695 noslide = 0;
696 #ifdef BUILTIN_SERVER
697 if (start_server)
698 exit(server_main());
699 #endif
700 if (!server) {
701 help();
702 return 1;
704 if (strlen(nick) > 63) /* put a reasonable limit on nick length */
705 nick[63] = 0;
707 if ((server_sock = conn(server, 31457, ip)) < 0) {
708 fprintf(stderr, "Couldn't connect to server %s: %s\n",
709 server, strerror(errno));
710 return 1;
712 sprintf(nickmsg, "tetri%s %s 1.13", tetrifast ? "faster" : "sstart", nick);
713 sprintf(iphashbuf, "%d", ip[0]*54 + ip[1]*41 + ip[2]*29 + ip[3]*17);
714 /* buf[0] does not need to be initialized for this algorithm */
715 len = strlen(nickmsg);
716 for (i = 0; i < len; i++)
717 buf[i+1] = (((buf[i]&0xFF) + (nickmsg[i]&0xFF)) % 255) ^ iphashbuf[i % strlen(iphashbuf)];
718 len++;
719 for (i = 0; i < len; i++)
720 sprintf(nickmsg+i*2, "%02X", buf[i] & 0xFF);
721 sputs(nickmsg, server_sock);
723 do {
724 if (!sgets(buf, sizeof(buf), server_sock)) {
725 fprintf(stderr, "Server %s closed connection\n", server);
726 disconn(server_sock);
727 return 1;
729 parse(buf);
730 } while (my_playernum < 0);
731 sockprintf(server_sock, "team %d ", my_playernum);
733 players[my_playernum-1] = strdup(nick);
734 dispmode = MODE_PARTYLINE;
735 io->screen_setup();
736 io->setup_partyline();
738 return 0;
741 /*************************************************************************/
743 int main(int ac, char **av)
745 int i;
747 if ((i = init(ac, av)) != 0)
748 return i;
750 for (;;) {
751 int timeout;
752 if (playing_game && !game_paused)
753 timeout = tetris_timeout();
754 else
755 timeout = -1;
756 i = io->wait_for_input(timeout);
757 if (i == -1) {
758 char buf[1024];
759 if (sgets(buf, sizeof(buf), server_sock))
760 parse(buf);
761 else {
762 msg_text(BUFFER_PLINE, "*** Disconnected from Server");
763 break;
765 } else if (i == -2) {
766 tetris_timeout_action();
767 } else if (i == 12) { /* Ctrl-L */
768 io->screen_redraw();
769 } else if (i == K_F10) {
770 break; /* out of main loop */
771 } else if (i == K_F1) {
772 if (dispmode != MODE_FIELDS) {
773 dispmode = MODE_FIELDS;
774 io->setup_fields();
776 } else if (i == K_F2) {
777 if (dispmode != MODE_PARTYLINE) {
778 dispmode = MODE_PARTYLINE;
779 io->setup_partyline();
781 } else if (i == K_F3) {
782 if (dispmode != MODE_WINLIST) {
783 dispmode = MODE_WINLIST;
784 io->setup_winlist();
786 } else if (dispmode == MODE_FIELDS) {
787 tetris_input(i);
788 } else if (dispmode == MODE_PARTYLINE) {
789 if (i == 8 || i == 127) /* Backspace or Delete */
790 partyline_backspace();
791 else if (i == 4) /* Ctrl-D */
792 partyline_delete();
793 else if (i == 21) /* Ctrl-U */
794 partyline_kill();
795 else if (i == '\r' || i == '\n')
796 partyline_enter();
797 else if (i == K_LEFT)
798 partyline_move(-1);
799 else if (i == K_RIGHT)
800 partyline_move(1);
801 else if (i == 1) /* Ctrl-A */
802 partyline_move(-2);
803 else if (i == 5) /* Ctrl-E */
804 partyline_move(2);
805 else if (i >= 1 && i <= 0xFF)
806 partyline_input(i);
810 disconn(server_sock);
811 return 0;
814 /*************************************************************************/
816 #endif /* !SERVER_ONLY */
818 /*************************************************************************/