Support for server text attributes in messages. No more ugly control codes. Mixed...
[tetrinet.git] / tetrinet.c
blob0c0c0a934742ad155a6aec90c906ac861e48f106
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");
319 } else if (strcmp(cmd, "ingame") == 0) {
320 /* Sent when a player connects in the middle of a game */
321 int x, y;
322 char buf[1024], *s;
324 s = buf + sprintf(buf, "f %d ", my_playernum);
325 for (y = 0; y < FIELD_HEIGHT; y++) {
326 for (x = 0; x < FIELD_WIDTH; x++) {
327 fields[my_playernum-1][y][x] = rand()%5 + 1;
328 *s++ = '0' + fields[my_playernum-1][y][x];
331 *s = 0;
332 sputs(buf, server_sock);
333 playing_game = 0;
334 not_playing_game = 1;
336 } else if (strcmp(cmd, "pause") == 0) {
337 if ((s = strtok(NULL, " ")))
338 game_paused = atoi(s);
339 if (game_paused) {
340 msg_text(BUFFER_PLINE, "*** The Game Has Been Paused");
341 msg_text(BUFFER_GMSG, "*** The Game Has Been Paused");
342 } else {
343 msg_text(BUFFER_PLINE, "*** The Game Has Been Unpaused");
344 msg_text(BUFFER_GMSG, "*** The Game Has Been Unpaused");
347 } else if (strcmp(cmd, "endgame") == 0) {
348 playing_game = 0;
349 not_playing_game = 0;
350 memset(fields, 0, sizeof(fields));
351 specials[0] = -1;
352 io->clear_text(BUFFER_ATTDEF);
353 msg_text(BUFFER_PLINE, "*** The Game Has Ended");
354 if (dispmode == MODE_FIELDS) {
355 int i;
356 io->draw_own_field();
357 for (i = 1; i <= 6; i++) {
358 if (i != my_playernum)
359 io->draw_other_field(i);
363 } else if (strcmp(cmd, "playerwon") == 0) {
364 /* Syntax: playerwon # -- sent when all but one player lose */
366 } else if (strcmp(cmd, "playerlost") == 0) {
367 /* Syntax: playerlost # -- sent after playerleave on disconnect
368 * during a game, or when a player loses (sent by the losing
369 * player and from the server to all other players */
371 } else if (strcmp(cmd, "f") == 0) { /* field */
372 int player, x, y, tile;
374 /* This looks confusing, but what it means is, ignore this message
375 * if a game isn't going on. */
376 if (!playing_game && !not_playing_game)
377 return;
378 if (!(s = strtok(NULL, " ")))
379 return;
380 player = atoi(s);
381 player--;
382 if (!(s = strtok(NULL, "")))
383 return;
384 if (*s >= '0') {
385 /* Set field directly */
386 char *ptr = (char *) fields[player];
387 while (*s) {
388 if (*s <= '5')
389 *ptr++ = (*s++) - '0';
390 else switch (*s++) {
391 case 'a': *ptr++ = 6 + SPECIAL_A; break;
392 case 'b': *ptr++ = 6 + SPECIAL_B; break;
393 case 'c': *ptr++ = 6 + SPECIAL_C; break;
394 case 'g': *ptr++ = 6 + SPECIAL_G; break;
395 case 'n': *ptr++ = 6 + SPECIAL_N; break;
396 case 'o': *ptr++ = 6 + SPECIAL_O; break;
397 case 'q': *ptr++ = 6 + SPECIAL_Q; break;
398 case 'r': *ptr++ = 6 + SPECIAL_R; break;
399 case 's': *ptr++ = 6 + SPECIAL_S; break;
402 } else {
403 /* Set specific locations on field */
404 tile = 0;
405 while (*s) {
406 if (*s < '0') {
407 tile = *s - '!';
408 } else {
409 x = *s - '3';
410 y = (*++s) - '3';
411 fields[player][y][x] = tile;
413 s++;
416 if (player == my_playernum-1)
417 io->draw_own_field();
418 else
419 io->draw_other_field(player+1);
420 } else if (strcmp(cmd, "lvl") == 0) {
421 int player;
423 if (!(s = strtok(NULL, " ")))
424 return;
425 player = atoi(s)-1;
426 if (!(s = strtok(NULL, "")))
427 return;
428 levels[player] = atoi(s);
430 } else if (strcmp(cmd, "sb") == 0) {
431 int from, to;
432 char *type;
434 if (!(s = strtok(NULL, " ")))
435 return;
436 to = atoi(s);
437 if (!(type = strtok(NULL, " ")))
438 return;
439 if (!(s = strtok(NULL, " ")))
440 return;
441 from = atoi(s);
442 do_special(type, from, to);
444 } else if (strcmp(cmd, "gmsg") == 0) {
445 if (!(s = strtok(NULL, "")))
446 return;
447 msg_text(BUFFER_GMSG, s);
452 /*************************************************************************/
453 /*************************************************************************/
455 static char partyline_buffer[512];
456 static int partyline_pos = 0;
458 #define curpos (partyline_buffer+partyline_pos)
460 /*************************************************************************/
462 /* Add a character to the partyline buffer. */
464 void partyline_input(int c)
466 if (partyline_pos < sizeof(partyline_buffer) - 1) {
467 memmove(curpos+1, curpos, strlen(curpos)+1);
468 partyline_buffer[partyline_pos++] = c;
469 io->draw_partyline_input(partyline_buffer, partyline_pos);
473 /*************************************************************************/
475 /* Delete the current character from the partyline buffer. */
477 void partyline_delete(void)
479 if (partyline_buffer[partyline_pos]) {
480 memmove(curpos, curpos+1, strlen(curpos)-1+1);
481 io->draw_partyline_input(partyline_buffer, partyline_pos);
485 /*************************************************************************/
487 /* Backspace a character from the partyline buffer. */
489 void partyline_backspace(void)
491 if (partyline_pos > 0) {
492 partyline_pos--;
493 partyline_delete();
497 /*************************************************************************/
499 /* Kill the entire partyline input buffer. */
501 void partyline_kill(void)
503 partyline_pos = 0;
504 *partyline_buffer = 0;
505 io->draw_partyline_input(partyline_buffer, partyline_pos);
508 /*************************************************************************/
510 /* Move around the input buffer. Sign indicates direction; absolute value
511 * of 1 means one character, 2 means the whole line.
514 void partyline_move(int how)
516 if (how == -2) {
517 partyline_pos = 0;
518 io->draw_partyline_input(partyline_buffer, partyline_pos);
519 } else if (how == -1 && partyline_pos > 0) {
520 partyline_pos--;
521 io->draw_partyline_input(partyline_buffer, partyline_pos);
522 } else if (how == 1 && partyline_buffer[partyline_pos]) {
523 partyline_pos++;
524 io->draw_partyline_input(partyline_buffer, partyline_pos);
525 } else if (how == 2) {
526 partyline_pos = strlen(partyline_buffer);
527 io->draw_partyline_input(partyline_buffer, partyline_pos);
531 /*************************************************************************/
533 /* Send the input line to the server. */
535 void partyline_enter(void)
537 char buf[1024];
539 if (*partyline_buffer) {
540 if (strncasecmp(partyline_buffer, "/me ", 4) == 0) {
541 sockprintf(server_sock, "plineact %d %s", my_playernum, partyline_buffer+4);
542 snprintf(buf, sizeof(buf), "* %s %s", players[my_playernum-1], partyline_buffer+4);
543 msg_text(BUFFER_PLINE, buf);
544 } else if (strcasecmp(partyline_buffer, "/start") == 0) {
545 sockprintf(server_sock, "startgame 1 %d", my_playernum);
546 } else if (strcasecmp(partyline_buffer, "/end") == 0) {
547 sockprintf(server_sock, "startgame 0 %d", my_playernum);
548 } else if (strcasecmp(partyline_buffer, "/pause") == 0) {
549 sockprintf(server_sock, "pause 1 %d", my_playernum);
550 } else if (strcasecmp(partyline_buffer, "/unpause") == 0) {
551 sockprintf(server_sock, "pause 0 %d", my_playernum);
552 } else if (strncasecmp(partyline_buffer, "/team", 5) == 0) {
553 if (strlen(partyline_buffer) == 5)
554 strcpy(partyline_buffer+5, " "); /* make it "/team " */
555 sockprintf(server_sock, "team %d %s", my_playernum, partyline_buffer+6);
556 if (partyline_buffer[6]) {
557 if (teams[my_playernum-1])
558 free(teams[my_playernum-1]);
559 teams[my_playernum-1] = strdup(partyline_buffer+6);
560 snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[my_playernum-1], partyline_buffer+6);
561 msg_text(BUFFER_PLINE, buf);
562 } else {
563 if (teams[my_playernum-1])
564 free(teams[my_playernum-1]);
565 teams[my_playernum-1] = NULL;
566 snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[my_playernum-1]);
567 msg_text(BUFFER_PLINE, buf);
569 } else {
570 sockprintf(server_sock, "pline %d %s", my_playernum, partyline_buffer);
571 if (*partyline_buffer != '/'
572 || partyline_buffer[1] == 0 || partyline_buffer[1] == ' ') {
573 /* We do not show server-side commands. */
574 snprintf(buf, sizeof(buf), "<%s> %s", players[my_playernum-1], partyline_buffer);
575 msg_text(BUFFER_PLINE, buf);
578 partyline_pos = 0;
579 *partyline_buffer = 0;
580 io->draw_partyline_input(partyline_buffer, partyline_pos);
584 #undef curpos
586 /*************************************************************************/
587 /*************************************************************************/
589 void help()
591 fprintf(stderr,
592 "Tetrinet " VERSION " - Text-mode tetrinet client\n"
593 "\n"
594 "Usage: tetrinet [OPTION]... NICK SERVER\n"
595 "\n"
596 "Options (see README for details):\n"
597 " -fancy Use \"fancy\" TTY graphics.\n"
598 " -fast Connect to the server in the tetrifast mode.\n"
599 " -log <file> Log network traffic to the given file.\n"
600 " -noshadow Do not make the pieces cast shadow.\n"
601 " -noslide Do not allow pieces to \"slide\" after being dropped\n"
602 " with the spacebar.\n"
603 " -server Start the server instead of the client.\n"
604 " -shadow Make the pieces cast shadow. Can speed up gameplay\n"
605 " considerably, but it can be considered as cheating by\n"
606 " some people since some other tetrinet clients lack this.\n"
607 " -slide Opposite of -noslide; allows pieces to \"slide\" after\n"
608 " being dropped. If both -slide and -noslide are given,\n"
609 " -slide takes precedence.\n"
610 " -windows Behave as much like the Windows version of Tetrinet as\n"
611 " possible. Implies -noslide and -noshadow.\n"
615 int init(int ac, char **av)
617 int i;
618 char *nick = NULL, *server = NULL;
619 char buf[1024];
620 char nickmsg[1024];
621 unsigned char ip[4];
622 char iphashbuf[32];
623 int len;
624 #ifdef BUILTIN_SERVER
625 int start_server = 0; /* Start the server? (-server) */
626 #endif
627 int slide = 0; /* Do we definitely want to slide? (-slide) */
630 /* If there's a DISPLAY variable set in the environment, default to
631 * Xwindows I/O, else default to terminal I/O. */
632 /* if (getenv("DISPLAY"))
633 io = &xwin_interface;
634 else
635 io = &tty_interface; */
636 io=&tty_interface; /* because Xwin isn't done yet */
638 srand(time(NULL));
639 init_shapes();
641 for (i = 1; i < ac; i++) {
642 if (*av[i] == '-') {
643 #ifdef BUILTIN_SERVER
644 if (strcmp(av[i], "-server") == 0) {
645 start_server = 1;
646 } else
647 #endif
648 if (strcmp(av[i], "-fancy") == 0) {
649 fancy = 1;
650 } else if (strcmp(av[i], "-log") == 0) {
651 log = 1;
652 i++;
653 if (i >= ac) {
654 fprintf(stderr, "Option -log requires an argument\n");
655 return 1;
657 logname = av[i];
658 } else if (strcmp(av[i], "-noslide") == 0) {
659 noslide = 1;
660 } else if (strcmp(av[i], "-noshadow") == 0) {
661 cast_shadow = 0;
662 } else if (strcmp(av[i], "-shadow") == 0) {
663 cast_shadow = 1;
664 } else if (strcmp(av[i], "-slide") == 0) {
665 slide = 1;
666 } else if (strcmp(av[i], "-windows") == 0) {
667 windows_mode = 1;
668 noslide = 1;
669 cast_shadow = 0;
670 } else if (strcmp(av[i], "-fast") == 0) {
671 tetrifast = 1;
672 } else {
673 fprintf(stderr, "Unknown option %s\n", av[i]);
674 help();
675 return 1;
677 } else if (!nick) {
678 my_nick = nick = av[i];
679 } else if (!server) {
680 server = av[i];
681 } else {
682 help();
683 return 1;
686 if (slide)
687 noslide = 0;
688 #ifdef BUILTIN_SERVER
689 if (start_server)
690 exit(server_main());
691 #endif
692 if (!server) {
693 help();
694 return 1;
696 if (strlen(nick) > 63) /* put a reasonable limit on nick length */
697 nick[63] = 0;
699 if ((server_sock = conn(server, 31457, ip)) < 0) {
700 fprintf(stderr, "Couldn't connect to server %s: %s\n",
701 server, strerror(errno));
702 return 1;
704 sprintf(nickmsg, "tetri%s %s 1.13", tetrifast ? "faster" : "sstart", nick);
705 sprintf(iphashbuf, "%d", ip[0]*54 + ip[1]*41 + ip[2]*29 + ip[3]*17);
706 /* buf[0] does not need to be initialized for this algorithm */
707 len = strlen(nickmsg);
708 for (i = 0; i < len; i++)
709 buf[i+1] = (((buf[i]&0xFF) + (nickmsg[i]&0xFF)) % 255) ^ iphashbuf[i % strlen(iphashbuf)];
710 len++;
711 for (i = 0; i < len; i++)
712 sprintf(nickmsg+i*2, "%02X", buf[i] & 0xFF);
713 sputs(nickmsg, server_sock);
715 do {
716 if (!sgets(buf, sizeof(buf), server_sock)) {
717 fprintf(stderr, "Server %s closed connection\n", server);
718 disconn(server_sock);
719 return 1;
721 parse(buf);
722 } while (my_playernum < 0);
723 sockprintf(server_sock, "team %d ", my_playernum);
725 players[my_playernum-1] = strdup(nick);
726 dispmode = MODE_PARTYLINE;
727 io->screen_setup();
728 io->setup_partyline();
730 return 0;
733 /*************************************************************************/
735 int main(int ac, char **av)
737 int i;
739 if ((i = init(ac, av)) != 0)
740 return i;
742 for (;;) {
743 int timeout;
744 if (playing_game && !game_paused)
745 timeout = tetris_timeout();
746 else
747 timeout = -1;
748 i = io->wait_for_input(timeout);
749 if (i == -1) {
750 char buf[1024];
751 if (sgets(buf, sizeof(buf), server_sock))
752 parse(buf);
753 else {
754 msg_text(BUFFER_PLINE, "*** Disconnected from Server");
755 break;
757 } else if (i == -2) {
758 tetris_timeout_action();
759 } else if (i == 12) { /* Ctrl-L */
760 io->screen_redraw();
761 } else if (i == K_F10) {
762 break; /* out of main loop */
763 } else if (i == K_F1) {
764 if (dispmode != MODE_FIELDS) {
765 dispmode = MODE_FIELDS;
766 io->setup_fields();
768 } else if (i == K_F2) {
769 if (dispmode != MODE_PARTYLINE) {
770 dispmode = MODE_PARTYLINE;
771 io->setup_partyline();
773 } else if (i == K_F3) {
774 if (dispmode != MODE_WINLIST) {
775 dispmode = MODE_WINLIST;
776 io->setup_winlist();
778 } else if (dispmode == MODE_FIELDS) {
779 tetris_input(i);
780 } else if (dispmode == MODE_PARTYLINE) {
781 if (i == 8 || i == 127) /* Backspace or Delete */
782 partyline_backspace();
783 else if (i == 4) /* Ctrl-D */
784 partyline_delete();
785 else if (i == 21) /* Ctrl-U */
786 partyline_kill();
787 else if (i == '\r' || i == '\n')
788 partyline_enter();
789 else if (i == K_LEFT)
790 partyline_move(-1);
791 else if (i == K_RIGHT)
792 partyline_move(1);
793 else if (i == 1) /* Ctrl-A */
794 partyline_move(-2);
795 else if (i == 5) /* Ctrl-E */
796 partyline_move(2);
797 else if (i >= 1 && i <= 0xFF)
798 partyline_input(i);
802 disconn(server_sock);
803 return 0;
806 /*************************************************************************/
808 #endif /* !SERVER_ONLY */
810 /*************************************************************************/