ChangeLog update
[tetrinet/clach04.git] / tetrinet.c
blob5a9a0fca79378c61f4400d7a989a431f077236e3
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 /* Parse a line from the server. Destroys the buffer it's given as a side
52 * effect.
55 void parse(char *buf)
57 char *cmd, *s, *t;
59 cmd = strtok(buf, " ");
61 if (!cmd) {
62 return;
64 } else if (strcmp(cmd, "noconnecting") == 0) {
65 s = strtok(NULL, "");
66 if (!s)
67 s = "Unknown";
68 /* XXX not to stderr, please! -- we need to stay running w/o server */
69 fprintf(stderr, "Server error: %s\n", s);
70 exit(1);
72 } else if (strcmp(cmd, "winlist") == 0) {
73 int i = 0;
75 while (i < MAXWINLIST && (s = strtok(NULL, " "))) {
76 t = strchr(s, ';');
77 if (!t)
78 break;
79 *t++ = 0;
80 if (*s == 't')
81 winlist[i].team = 1;
82 else
83 winlist[i].team = 0;
84 s++;
85 strncpy(winlist[i].name, s, sizeof(winlist[i].name)-1);
86 winlist[i].name[sizeof(winlist[i].name)] = 0;
87 winlist[i].points = atoi(t);
88 if ((t = strchr(t, ';')) != NULL)
89 winlist[i].games = atoi(t+1);
90 i++;
92 if (i < MAXWINLIST)
93 winlist[i].name[0] = 0;
94 if (dispmode == MODE_WINLIST)
95 io->setup_winlist();
97 } else if (strcmp(cmd, tetrifast ? ")#)(!@(*3" : "playernum") == 0) {
98 if ((s = strtok(NULL, " ")))
99 my_playernum = atoi(s);
100 /* Note: players[my_playernum-1] is set in init() */
101 /* But that doesn't work when joining other channel. */
102 players[my_playernum-1] = strdup(my_nick);
104 } else if (strcmp(cmd, "playerjoin") == 0) {
105 int player;
106 char buf[1024];
108 s = strtok(NULL, " ");
109 t = strtok(NULL, "");
110 if (!s || !t)
111 return;
112 player = atoi(s)-1;
113 if (player < 0 || player > 5)
114 return;
115 players[player] = strdup(t);
116 if (teams[player]) {
117 free(teams[player]);
118 teams[player] = NULL;
120 snprintf(buf, sizeof(buf), "*** %s is Now Playing", t);
121 io->draw_text(BUFFER_PLINE, buf);
122 if (dispmode == MODE_FIELDS)
123 io->setup_fields();
125 } else if (strcmp(cmd, "playerleave") == 0) {
126 int player;
127 char buf[1024];
129 s = strtok(NULL, " ");
130 if (!s)
131 return;
132 player = atoi(s)-1;
133 if (player < 0 || player > 5 || !players[player])
134 return;
135 snprintf(buf, sizeof(buf), "*** %s has Left", players[player]);
136 io->draw_text(BUFFER_PLINE, buf);
137 free(players[player]);
138 players[player] = NULL;
139 if (dispmode == MODE_FIELDS)
140 io->setup_fields();
142 } else if (strcmp(cmd, "team") == 0) {
143 int player;
144 char buf[1024];
146 s = strtok(NULL, " ");
147 t = strtok(NULL, "");
148 if (!s)
149 return;
150 player = atoi(s)-1;
151 if (player < 0 || player > 5 || !players[player])
152 return;
153 if (teams[player])
154 free(teams[player]);
155 if (t)
156 teams[player] = strdup(t);
157 else
158 teams[player] = NULL;
159 if (t)
160 snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[player], t);
161 else
162 snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[player]);
163 io->draw_text(BUFFER_PLINE, buf);
165 } else if (strcmp(cmd, "pline") == 0) {
166 int playernum;
167 char buf[1024], *name;
169 s = strtok(NULL, " ");
170 t = strtok(NULL, "");
171 if (!s)
172 return;
173 if (!t)
174 t = "";
175 playernum = atoi(s)-1;
176 if (playernum == -1) {
177 name = "Server";
178 } else {
179 if (playernum < 0 || playernum > 5 || !players[playernum])
180 return;
181 name = players[playernum];
183 snprintf(buf, sizeof(buf), "<%s> %s", name, t);
184 io->draw_text(BUFFER_PLINE, buf);
186 } else if (strcmp(cmd, "plineact") == 0) {
187 int playernum;
188 char buf[1024], *name;
190 s = strtok(NULL, " ");
191 t = strtok(NULL, "");
192 if (!s)
193 return;
194 if (!t)
195 t = "";
196 playernum = atoi(s)-1;
197 if (playernum == -1) {
198 name = "Server";
199 } else {
200 if (playernum < 0 || playernum > 5 || !players[playernum])
201 return;
202 name = players[playernum];
204 snprintf(buf, sizeof(buf), "* %s %s", name, t);
205 io->draw_text(BUFFER_PLINE, buf);
207 } else if (strcmp(cmd, tetrifast ? "*******" : "newgame") == 0) {
208 int i;
210 if ((s = strtok(NULL, " ")))
211 /* stack height */;
212 if ((s = strtok(NULL, " ")))
213 initial_level = atoi(s);
214 if ((s = strtok(NULL, " ")))
215 lines_per_level = atoi(s);
216 if ((s = strtok(NULL, " ")))
217 level_inc = atoi(s);
218 if ((s = strtok(NULL, " ")))
219 special_lines = atoi(s);
220 if ((s = strtok(NULL, " ")))
221 special_count = atoi(s);
222 if ((s = strtok(NULL, " "))) {
223 special_capacity = atoi(s);
224 if (special_capacity > MAX_SPECIALS)
225 special_capacity = MAX_SPECIALS;
227 if ((s = strtok(NULL, " "))) {
228 memset(piecefreq, 0, sizeof(piecefreq));
229 while (*s) {
230 i = *s - '1';
231 if (i >= 0 && i < 7)
232 piecefreq[i]++;
233 s++;
236 if ((s = strtok(NULL, " "))) {
237 memset(specialfreq, 0, sizeof(specialfreq));
238 while (*s) {
239 i = *s - '1';
240 if (i >= 0 && i < 9)
241 specialfreq[i]++;
242 s++;
245 if ((s = strtok(NULL, " ")))
246 level_average = atoi(s);
247 if ((s = strtok(NULL, " ")))
248 old_mode = atoi(s);
249 lines = 0;
250 for (i = 0; i < 6; i++)
251 levels[i] = initial_level;
252 memset(&fields[my_playernum-1], 0, sizeof(Field));
253 specials[0] = -1;
254 io->clear_text(BUFFER_GMSG);
255 io->clear_text(BUFFER_ATTDEF);
256 new_game();
257 playing_game = 1;
258 game_paused = 0;
259 io->draw_text(BUFFER_PLINE, "*** The Game Has Started");
261 } else if (strcmp(cmd, "ingame") == 0) {
262 /* Sent when a player connects in the middle of a game */
263 int x, y;
264 char buf[1024], *s;
266 s = buf + sprintf(buf, "f %d ", my_playernum);
267 for (y = 0; y < FIELD_HEIGHT; y++) {
268 for (x = 0; x < FIELD_WIDTH; x++) {
269 fields[my_playernum-1][y][x] = rand()%5 + 1;
270 *s++ = '0' + fields[my_playernum-1][y][x];
273 *s = 0;
274 sputs(buf, server_sock);
275 playing_game = 0;
276 not_playing_game = 1;
278 } else if (strcmp(cmd, "pause") == 0) {
279 if ((s = strtok(NULL, " ")))
280 game_paused = atoi(s);
281 if (game_paused) {
282 io->draw_text(BUFFER_PLINE, "*** The Game Has Been Paused");
283 io->draw_text(BUFFER_GMSG, "*** The Game Has Been Paused");
284 } else {
285 io->draw_text(BUFFER_PLINE, "*** The Game Has Been Unpaused");
286 io->draw_text(BUFFER_GMSG, "*** The Game Has Been Unpaused");
289 } else if (strcmp(cmd, "endgame") == 0) {
290 playing_game = 0;
291 not_playing_game = 0;
292 memset(fields, 0, sizeof(fields));
293 specials[0] = -1;
294 io->clear_text(BUFFER_ATTDEF);
295 io->draw_text(BUFFER_PLINE, "*** The Game Has Ended");
296 if (dispmode == MODE_FIELDS) {
297 int i;
298 io->draw_own_field();
299 for (i = 1; i <= 6; i++) {
300 if (i != my_playernum)
301 io->draw_other_field(i);
305 } else if (strcmp(cmd, "playerwon") == 0) {
306 /* Syntax: playerwon # -- sent when all but one player lose */
308 } else if (strcmp(cmd, "playerlost") == 0) {
309 /* Syntax: playerlost # -- sent after playerleave on disconnect
310 * during a game, or when a player loses (sent by the losing
311 * player and from the server to all other players */
313 } else if (strcmp(cmd, "f") == 0) { /* field */
314 int player, x, y, tile;
316 /* This looks confusing, but what it means is, ignore this message
317 * if a game isn't going on. */
318 if (!playing_game && !not_playing_game)
319 return;
320 if (!(s = strtok(NULL, " ")))
321 return;
322 player = atoi(s);
323 player--;
324 if (!(s = strtok(NULL, "")))
325 return;
326 if (*s >= '0') {
327 /* Set field directly */
328 char *ptr = (char *) fields[player];
329 while (*s) {
330 if (*s <= '5')
331 *ptr++ = (*s++) - '0';
332 else switch (*s++) {
333 case 'a': *ptr++ = 6 + SPECIAL_A; break;
334 case 'b': *ptr++ = 6 + SPECIAL_B; break;
335 case 'c': *ptr++ = 6 + SPECIAL_C; break;
336 case 'g': *ptr++ = 6 + SPECIAL_G; break;
337 case 'n': *ptr++ = 6 + SPECIAL_N; break;
338 case 'o': *ptr++ = 6 + SPECIAL_O; break;
339 case 'q': *ptr++ = 6 + SPECIAL_Q; break;
340 case 'r': *ptr++ = 6 + SPECIAL_R; break;
341 case 's': *ptr++ = 6 + SPECIAL_S; break;
344 } else {
345 /* Set specific locations on field */
346 tile = 0;
347 while (*s) {
348 if (*s < '0') {
349 tile = *s - '!';
350 } else {
351 x = *s - '3';
352 y = (*++s) - '3';
353 fields[player][y][x] = tile;
355 s++;
358 if (player == my_playernum-1)
359 io->draw_own_field();
360 else
361 io->draw_other_field(player+1);
362 } else if (strcmp(cmd, "lvl") == 0) {
363 int player;
365 if (!(s = strtok(NULL, " ")))
366 return;
367 player = atoi(s)-1;
368 if (!(s = strtok(NULL, "")))
369 return;
370 levels[player] = atoi(s);
372 } else if (strcmp(cmd, "sb") == 0) {
373 int from, to;
374 char *type;
376 if (!(s = strtok(NULL, " ")))
377 return;
378 to = atoi(s);
379 if (!(type = strtok(NULL, " ")))
380 return;
381 if (!(s = strtok(NULL, " ")))
382 return;
383 from = atoi(s);
384 do_special(type, from, to);
386 } else if (strcmp(cmd, "gmsg") == 0) {
387 if (!(s = strtok(NULL, "")))
388 return;
389 io->draw_text(BUFFER_GMSG, s);
394 /*************************************************************************/
395 /*************************************************************************/
397 static char partyline_buffer[512];
398 static int partyline_pos = 0;
400 #define curpos (partyline_buffer+partyline_pos)
402 /*************************************************************************/
404 /* Add a character to the partyline buffer. */
406 void partyline_input(int c)
408 if (partyline_pos < sizeof(partyline_buffer) - 1) {
409 memmove(curpos+1, curpos, strlen(curpos)+1);
410 partyline_buffer[partyline_pos++] = c;
411 io->draw_partyline_input(partyline_buffer, partyline_pos);
415 /*************************************************************************/
417 /* Delete the current character from the partyline buffer. */
419 void partyline_delete(void)
421 if (partyline_buffer[partyline_pos]) {
422 memmove(curpos, curpos+1, strlen(curpos)-1+1);
423 io->draw_partyline_input(partyline_buffer, partyline_pos);
427 /*************************************************************************/
429 /* Backspace a character from the partyline buffer. */
431 void partyline_backspace(void)
433 if (partyline_pos > 0) {
434 partyline_pos--;
435 partyline_delete();
439 /*************************************************************************/
441 /* Kill the entire partyline input buffer. */
443 void partyline_kill(void)
445 partyline_pos = 0;
446 *partyline_buffer = 0;
447 io->draw_partyline_input(partyline_buffer, partyline_pos);
450 /*************************************************************************/
452 /* Move around the input buffer. Sign indicates direction; absolute value
453 * of 1 means one character, 2 means the whole line.
456 void partyline_move(int how)
458 if (how == -2) {
459 partyline_pos = 0;
460 io->draw_partyline_input(partyline_buffer, partyline_pos);
461 } else if (how == -1 && partyline_pos > 0) {
462 partyline_pos--;
463 io->draw_partyline_input(partyline_buffer, partyline_pos);
464 } else if (how == 1 && partyline_buffer[partyline_pos]) {
465 partyline_pos++;
466 io->draw_partyline_input(partyline_buffer, partyline_pos);
467 } else if (how == 2) {
468 partyline_pos = strlen(partyline_buffer);
469 io->draw_partyline_input(partyline_buffer, partyline_pos);
473 /*************************************************************************/
475 /* Send the input line to the server. */
477 void partyline_enter(void)
479 char buf[1024];
481 if (*partyline_buffer) {
482 if (strncasecmp(partyline_buffer, "/me ", 4) == 0) {
483 sockprintf(server_sock, "plineact %d %s", my_playernum, partyline_buffer+4);
484 snprintf(buf, sizeof(buf), "* %s %s", players[my_playernum-1], partyline_buffer+4);
485 io->draw_text(BUFFER_PLINE, buf);
486 } else if (strcasecmp(partyline_buffer, "/start") == 0) {
487 sockprintf(server_sock, "startgame 1 %d", my_playernum);
488 } else if (strcasecmp(partyline_buffer, "/end") == 0) {
489 sockprintf(server_sock, "startgame 0 %d", my_playernum);
490 } else if (strcasecmp(partyline_buffer, "/pause") == 0) {
491 sockprintf(server_sock, "pause 1 %d", my_playernum);
492 } else if (strcasecmp(partyline_buffer, "/unpause") == 0) {
493 sockprintf(server_sock, "pause 0 %d", my_playernum);
494 } else if (strncasecmp(partyline_buffer, "/team", 5) == 0) {
495 if (strlen(partyline_buffer) == 5)
496 strcpy(partyline_buffer+5, " "); /* make it "/team " */
497 sockprintf(server_sock, "team %d %s", my_playernum, partyline_buffer+6);
498 if (partyline_buffer[6]) {
499 if (teams[my_playernum-1])
500 free(teams[my_playernum-1]);
501 teams[my_playernum-1] = strdup(partyline_buffer+6);
502 snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[my_playernum-1], partyline_buffer+6);
503 io->draw_text(BUFFER_PLINE, buf);
504 } else {
505 if (teams[my_playernum-1])
506 free(teams[my_playernum-1]);
507 teams[my_playernum-1] = NULL;
508 snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[my_playernum-1]);
509 io->draw_text(BUFFER_PLINE, buf);
511 } else {
512 sockprintf(server_sock, "pline %d %s", my_playernum, partyline_buffer);
513 if (*partyline_buffer != '/'
514 || partyline_buffer[1] == 0 || partyline_buffer[1] == ' ') {
515 /* We do not show server-side commands. */
516 snprintf(buf, sizeof(buf), "<%s> %s", players[my_playernum-1], partyline_buffer);
517 io->draw_text(BUFFER_PLINE, buf);
520 partyline_pos = 0;
521 *partyline_buffer = 0;
522 io->draw_partyline_input(partyline_buffer, partyline_pos);
526 #undef curpos
528 /*************************************************************************/
529 /*************************************************************************/
531 void help()
533 fprintf(stderr,
534 "Tetrinet " VERSION " - Text-mode tetrinet client\n"
535 "\n"
536 "Usage: tetrinet [OPTION]... NICK SERVER\n"
537 "\n"
538 "Options (see README for details):\n"
539 " -fancy Use \"fancy\" TTY graphics.\n"
540 " -fast Connect to the server in the tetrifast mode.\n"
541 " -log <file> Log network traffic to the given file.\n"
542 " -noshadow Do not make the pieces cast shadow.\n"
543 " -noslide Do not allow pieces to \"slide\" after being dropped\n"
544 " with the spacebar.\n"
545 " -server Start the server instead of the client.\n"
546 " -shadow Make the pieces cast shadow. Can speed up gameplay\n"
547 " considerably, but it can be considered as cheating by\n"
548 " some people since some other tetrinet clients lack this.\n"
549 " -slide Opposite of -noslide; allows pieces to \"slide\" after\n"
550 " being dropped. If both -slide and -noslide are given,\n"
551 " -slide takes precedence.\n"
552 " -windows Behave as much like the Windows version of Tetrinet as\n"
553 " possible. Implies -noslide and -noshadow.\n"
557 int init(int ac, char **av)
559 int i;
560 char *nick = NULL, *server = NULL;
561 char buf[1024];
562 char nickmsg[1024];
563 unsigned char ip[4];
564 char iphashbuf[32];
565 int len;
566 #ifdef BUILTIN_SERVER
567 int start_server = 0; /* Start the server? (-server) */
568 #endif
569 int slide = 0; /* Do we definitely want to slide? (-slide) */
572 /* If there's a DISPLAY variable set in the environment, default to
573 * Xwindows I/O, else default to terminal I/O. */
574 if (getenv("DISPLAY"))
575 io = &xwin_interface;
576 else
577 io = &tty_interface;
578 io=&tty_interface; /* because Xwin isn't done yet */
580 srand(time(NULL));
581 init_shapes();
583 for (i = 1; i < ac; i++) {
584 if (*av[i] == '-') {
585 #ifdef BUILTIN_SERVER
586 if (strcmp(av[i], "-server") == 0) {
587 start_server = 1;
588 } else
589 #endif
590 if (strcmp(av[i], "-fancy") == 0) {
591 fancy = 1;
592 } else if (strcmp(av[i], "-log") == 0) {
593 log = 1;
594 i++;
595 if (i >= ac) {
596 fprintf(stderr, "Option -log requires an argument\n");
597 return 1;
599 logname = av[i];
600 } else if (strcmp(av[i], "-noslide") == 0) {
601 noslide = 1;
602 } else if (strcmp(av[i], "-noshadow") == 0) {
603 cast_shadow = 0;
604 } else if (strcmp(av[i], "-shadow") == 0) {
605 cast_shadow = 1;
606 } else if (strcmp(av[i], "-slide") == 0) {
607 slide = 1;
608 } else if (strcmp(av[i], "-windows") == 0) {
609 windows_mode = 1;
610 noslide = 1;
611 cast_shadow = 0;
612 } else if (strcmp(av[i], "-fast") == 0) {
613 tetrifast = 1;
614 } else {
615 fprintf(stderr, "Unknown option %s\n", av[i]);
616 help();
617 return 1;
619 } else if (!nick) {
620 my_nick = nick = av[i];
621 } else if (!server) {
622 server = av[i];
623 } else {
624 help();
625 return 1;
628 if (slide)
629 noslide = 0;
630 #ifdef BUILTIN_SERVER
631 if (start_server)
632 exit(server_main());
633 #endif
634 if (!server) {
635 help();
636 return 1;
638 if (strlen(nick) > 63) /* put a reasonable limit on nick length */
639 nick[63] = 0;
641 if ((server_sock = conn(server, 31457, ip)) < 0) {
642 fprintf(stderr, "Couldn't connect to server %s: %s\n",
643 server, strerror(errno));
644 return 1;
646 sprintf(nickmsg, "tetri%s %s 1.13", tetrifast ? "faster" : "sstart", nick);
647 sprintf(iphashbuf, "%d", ip[0]*54 + ip[1]*41 + ip[2]*29 + ip[3]*17);
648 /* buf[0] does not need to be initialized for this algorithm */
649 len = strlen(nickmsg);
650 for (i = 0; i < len; i++)
651 buf[i+1] = (((buf[i]&0xFF) + (nickmsg[i]&0xFF)) % 255) ^ iphashbuf[i % strlen(iphashbuf)];
652 len++;
653 for (i = 0; i < len; i++)
654 sprintf(nickmsg+i*2, "%02X", buf[i] & 0xFF);
655 sputs(nickmsg, server_sock);
657 do {
658 if (!sgets(buf, sizeof(buf), server_sock)) {
659 fprintf(stderr, "Server %s closed connection\n", server);
660 disconn(server_sock);
661 return 1;
663 parse(buf);
664 } while (my_playernum < 0);
665 sockprintf(server_sock, "team %d ", my_playernum);
667 players[my_playernum-1] = strdup(nick);
668 dispmode = MODE_PARTYLINE;
669 io->screen_setup();
670 io->setup_partyline();
672 return 0;
675 /*************************************************************************/
677 int main(int ac, char **av)
679 int i;
681 if ((i = init(ac, av)) != 0)
682 return i;
684 for (;;) {
685 int timeout;
686 if (playing_game && !game_paused)
687 timeout = tetris_timeout();
688 else
689 timeout = -1;
690 i = io->wait_for_input(timeout);
691 if (i == -1) {
692 char buf[1024];
693 if (sgets(buf, sizeof(buf), server_sock))
694 parse(buf);
695 else {
696 io->draw_text(BUFFER_PLINE, "*** Disconnected from Server");
697 break;
699 } else if (i == -2) {
700 tetris_timeout_action();
701 } else if (i == 12) { /* Ctrl-L */
702 io->screen_redraw();
703 } else if (i == K_F10) {
704 break; /* out of main loop */
705 } else if (i == K_F1) {
706 if (dispmode != MODE_FIELDS) {
707 dispmode = MODE_FIELDS;
708 io->setup_fields();
710 } else if (i == K_F2) {
711 if (dispmode != MODE_PARTYLINE) {
712 dispmode = MODE_PARTYLINE;
713 io->setup_partyline();
715 } else if (i == K_F3) {
716 if (dispmode != MODE_WINLIST) {
717 dispmode = MODE_WINLIST;
718 io->setup_winlist();
720 } else if (dispmode == MODE_FIELDS) {
721 tetris_input(i);
722 } else if (dispmode == MODE_PARTYLINE) {
723 if (i == 8 || i == 127) /* Backspace or Delete */
724 partyline_backspace();
725 else if (i == 4) /* Ctrl-D */
726 partyline_delete();
727 else if (i == 21) /* Ctrl-U */
728 partyline_kill();
729 else if (i == '\r' || i == '\n')
730 partyline_enter();
731 else if (i == K_LEFT)
732 partyline_move(-1);
733 else if (i == K_RIGHT)
734 partyline_move(1);
735 else if (i == 1) /* Ctrl-A */
736 partyline_move(-2);
737 else if (i == 5) /* Ctrl-E */
738 partyline_move(2);
739 else if (i >= 1 && i <= 0xFF)
740 partyline_input(i);
744 disconn(server_sock);
745 return 0;
748 /*************************************************************************/
750 #endif /* !SERVER_ONLY */
752 /*************************************************************************/