753 lines
20 KiB
C
753 lines
20 KiB
C
/* Tetrinet for Linux, by Andrew Church <achurch@achurch.org>
|
|
* This program is public domain.
|
|
*
|
|
* Tetrinet main program.
|
|
*/
|
|
|
|
/*************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <errno.h>
|
|
#include "tetrinet.h"
|
|
#include "io.h"
|
|
#include "server.h"
|
|
#include "sockets.h"
|
|
#include "tetris.h"
|
|
#include "version.h"
|
|
|
|
/*************************************************************************/
|
|
|
|
int fancy = 0; /* Fancy TTY graphics? */
|
|
int log = 0; /* Log network traffic to file? */
|
|
char *logname; /* Log filename */
|
|
int windows_mode = 0; /* Try to be just like the Windows version? */
|
|
int noslide = 0; /* Disallow piece sliding? */
|
|
int tetrifast = 0; /* TetriFast mode? */
|
|
int cast_shadow = 1; /* Make pieces cast shadow? */
|
|
|
|
int my_playernum = -1; /* What player number are we? */
|
|
char *my_nick; /* And what is our nick? */
|
|
WinInfo winlist[MAXWINLIST]; /* Winners' list from server */
|
|
int server_sock; /* Socket for server communication */
|
|
int dispmode; /* Current display mode */
|
|
char *players[6]; /* Player names (NULL for no such player) */
|
|
char *teams[6]; /* Team names (NULL for not on a team) */
|
|
int playing_game; /* Are we currently playing a game? */
|
|
int not_playing_game; /* Are we currently watching people play a game? */
|
|
int game_paused; /* Is the game currently paused? */
|
|
|
|
Interface *io; /* Input/output routines */
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
#ifndef SERVER_ONLY
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Parse a line from the server. Destroys the buffer it's given as a side
|
|
* effect.
|
|
*/
|
|
|
|
void parse(char *buf)
|
|
{
|
|
char *cmd, *s, *t;
|
|
|
|
cmd = strtok(buf, " ");
|
|
|
|
if (!cmd) {
|
|
return;
|
|
|
|
} else if (strcmp(cmd, "noconnecting") == 0) {
|
|
s = strtok(NULL, "");
|
|
if (!s)
|
|
s = "Unknown";
|
|
/* XXX not to stderr, please! -- we need to stay running w/o server */
|
|
fprintf(stderr, "Server error: %s\n", s);
|
|
exit(1);
|
|
|
|
} else if (strcmp(cmd, "winlist") == 0) {
|
|
int i = 0;
|
|
|
|
while (i < MAXWINLIST && (s = strtok(NULL, " "))) {
|
|
t = strchr(s, ';');
|
|
if (!t)
|
|
break;
|
|
*t++ = 0;
|
|
if (*s == 't')
|
|
winlist[i].team = 1;
|
|
else
|
|
winlist[i].team = 0;
|
|
s++;
|
|
strncpy(winlist[i].name, s, sizeof(winlist[i].name)-1);
|
|
winlist[i].name[sizeof(winlist[i].name)] = 0;
|
|
winlist[i].points = atoi(t);
|
|
if ((t = strchr(t, ';')) != NULL)
|
|
winlist[i].games = atoi(t+1);
|
|
i++;
|
|
}
|
|
if (i < MAXWINLIST)
|
|
winlist[i].name[0] = 0;
|
|
if (dispmode == MODE_WINLIST)
|
|
io->setup_winlist();
|
|
|
|
} else if (strcmp(cmd, tetrifast ? ")#)(!@(*3" : "playernum") == 0) {
|
|
if ((s = strtok(NULL, " ")))
|
|
my_playernum = atoi(s);
|
|
/* Note: players[my_playernum-1] is set in init() */
|
|
/* But that doesn't work when joining other channel. */
|
|
players[my_playernum-1] = strdup(my_nick);
|
|
|
|
} else if (strcmp(cmd, "playerjoin") == 0) {
|
|
int player;
|
|
char buf[1024];
|
|
|
|
s = strtok(NULL, " ");
|
|
t = strtok(NULL, "");
|
|
if (!s || !t)
|
|
return;
|
|
player = atoi(s)-1;
|
|
if (player < 0 || player > 5)
|
|
return;
|
|
players[player] = strdup(t);
|
|
if (teams[player]) {
|
|
free(teams[player]);
|
|
teams[player] = NULL;
|
|
}
|
|
snprintf(buf, sizeof(buf), "*** %s is Now Playing", t);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
if (dispmode == MODE_FIELDS)
|
|
io->setup_fields();
|
|
|
|
} else if (strcmp(cmd, "playerleave") == 0) {
|
|
int player;
|
|
char buf[1024];
|
|
|
|
s = strtok(NULL, " ");
|
|
if (!s)
|
|
return;
|
|
player = atoi(s)-1;
|
|
if (player < 0 || player > 5 || !players[player])
|
|
return;
|
|
snprintf(buf, sizeof(buf), "*** %s has Left", players[player]);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
free(players[player]);
|
|
players[player] = NULL;
|
|
if (dispmode == MODE_FIELDS)
|
|
io->setup_fields();
|
|
|
|
} else if (strcmp(cmd, "team") == 0) {
|
|
int player;
|
|
char buf[1024];
|
|
|
|
s = strtok(NULL, " ");
|
|
t = strtok(NULL, "");
|
|
if (!s)
|
|
return;
|
|
player = atoi(s)-1;
|
|
if (player < 0 || player > 5 || !players[player])
|
|
return;
|
|
if (teams[player])
|
|
free(teams[player]);
|
|
if (t)
|
|
teams[player] = strdup(t);
|
|
else
|
|
teams[player] = NULL;
|
|
if (t)
|
|
snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[player], t);
|
|
else
|
|
snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[player]);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
|
|
} else if (strcmp(cmd, "pline") == 0) {
|
|
int playernum;
|
|
char buf[1024], *name;
|
|
|
|
s = strtok(NULL, " ");
|
|
t = strtok(NULL, "");
|
|
if (!s)
|
|
return;
|
|
if (!t)
|
|
t = "";
|
|
playernum = atoi(s)-1;
|
|
if (playernum == -1) {
|
|
name = "Server";
|
|
} else {
|
|
if (playernum < 0 || playernum > 5 || !players[playernum])
|
|
return;
|
|
name = players[playernum];
|
|
}
|
|
snprintf(buf, sizeof(buf), "<%s> %s", name, t);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
|
|
} else if (strcmp(cmd, "plineact") == 0) {
|
|
int playernum;
|
|
char buf[1024], *name;
|
|
|
|
s = strtok(NULL, " ");
|
|
t = strtok(NULL, "");
|
|
if (!s)
|
|
return;
|
|
if (!t)
|
|
t = "";
|
|
playernum = atoi(s)-1;
|
|
if (playernum == -1) {
|
|
name = "Server";
|
|
} else {
|
|
if (playernum < 0 || playernum > 5 || !players[playernum])
|
|
return;
|
|
name = players[playernum];
|
|
}
|
|
snprintf(buf, sizeof(buf), "* %s %s", name, t);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
|
|
} else if (strcmp(cmd, tetrifast ? "*******" : "newgame") == 0) {
|
|
int i;
|
|
|
|
if ((s = strtok(NULL, " ")))
|
|
/* stack height */;
|
|
if ((s = strtok(NULL, " ")))
|
|
initial_level = atoi(s);
|
|
if ((s = strtok(NULL, " ")))
|
|
lines_per_level = atoi(s);
|
|
if ((s = strtok(NULL, " ")))
|
|
level_inc = atoi(s);
|
|
if ((s = strtok(NULL, " ")))
|
|
special_lines = atoi(s);
|
|
if ((s = strtok(NULL, " ")))
|
|
special_count = atoi(s);
|
|
if ((s = strtok(NULL, " "))) {
|
|
special_capacity = atoi(s);
|
|
if (special_capacity > MAX_SPECIALS)
|
|
special_capacity = MAX_SPECIALS;
|
|
}
|
|
if ((s = strtok(NULL, " "))) {
|
|
memset(piecefreq, 0, sizeof(piecefreq));
|
|
while (*s) {
|
|
i = *s - '1';
|
|
if (i >= 0 && i < 7)
|
|
piecefreq[i]++;
|
|
s++;
|
|
}
|
|
}
|
|
if ((s = strtok(NULL, " "))) {
|
|
memset(specialfreq, 0, sizeof(specialfreq));
|
|
while (*s) {
|
|
i = *s - '1';
|
|
if (i >= 0 && i < 9)
|
|
specialfreq[i]++;
|
|
s++;
|
|
}
|
|
}
|
|
if ((s = strtok(NULL, " ")))
|
|
level_average = atoi(s);
|
|
if ((s = strtok(NULL, " ")))
|
|
old_mode = atoi(s);
|
|
lines = 0;
|
|
for (i = 0; i < 6; i++)
|
|
levels[i] = initial_level;
|
|
memset(&fields[my_playernum-1], 0, sizeof(Field));
|
|
specials[0] = -1;
|
|
io->clear_text(BUFFER_GMSG);
|
|
io->clear_text(BUFFER_ATTDEF);
|
|
new_game();
|
|
playing_game = 1;
|
|
game_paused = 0;
|
|
io->draw_text(BUFFER_PLINE, "*** The Game Has Started");
|
|
|
|
} else if (strcmp(cmd, "ingame") == 0) {
|
|
/* Sent when a player connects in the middle of a game */
|
|
int x, y;
|
|
char buf[1024], *s;
|
|
|
|
s = buf + sprintf(buf, "f %d ", my_playernum);
|
|
for (y = 0; y < FIELD_HEIGHT; y++) {
|
|
for (x = 0; x < FIELD_WIDTH; x++) {
|
|
fields[my_playernum-1][y][x] = rand()%5 + 1;
|
|
*s++ = '0' + fields[my_playernum-1][y][x];
|
|
}
|
|
}
|
|
*s = 0;
|
|
sputs(buf, server_sock);
|
|
playing_game = 0;
|
|
not_playing_game = 1;
|
|
|
|
} else if (strcmp(cmd, "pause") == 0) {
|
|
if ((s = strtok(NULL, " ")))
|
|
game_paused = atoi(s);
|
|
if (game_paused) {
|
|
io->draw_text(BUFFER_PLINE, "*** The Game Has Been Paused");
|
|
io->draw_text(BUFFER_GMSG, "*** The Game Has Been Paused");
|
|
} else {
|
|
io->draw_text(BUFFER_PLINE, "*** The Game Has Been Unpaused");
|
|
io->draw_text(BUFFER_GMSG, "*** The Game Has Been Unpaused");
|
|
}
|
|
|
|
} else if (strcmp(cmd, "endgame") == 0) {
|
|
playing_game = 0;
|
|
not_playing_game = 0;
|
|
memset(fields, 0, sizeof(fields));
|
|
specials[0] = -1;
|
|
io->clear_text(BUFFER_ATTDEF);
|
|
io->draw_text(BUFFER_PLINE, "*** The Game Has Ended");
|
|
if (dispmode == MODE_FIELDS) {
|
|
int i;
|
|
io->draw_own_field();
|
|
for (i = 1; i <= 6; i++) {
|
|
if (i != my_playernum)
|
|
io->draw_other_field(i);
|
|
}
|
|
}
|
|
|
|
} else if (strcmp(cmd, "playerwon") == 0) {
|
|
/* Syntax: playerwon # -- sent when all but one player lose */
|
|
|
|
} else if (strcmp(cmd, "playerlost") == 0) {
|
|
/* Syntax: playerlost # -- sent after playerleave on disconnect
|
|
* during a game, or when a player loses (sent by the losing
|
|
* player and from the server to all other players */
|
|
|
|
} else if (strcmp(cmd, "f") == 0) { /* field */
|
|
int player, x, y, tile;
|
|
|
|
/* This looks confusing, but what it means is, ignore this message
|
|
* if a game isn't going on. */
|
|
if (!playing_game && !not_playing_game)
|
|
return;
|
|
if (!(s = strtok(NULL, " ")))
|
|
return;
|
|
player = atoi(s);
|
|
player--;
|
|
if (!(s = strtok(NULL, "")))
|
|
return;
|
|
if (*s >= '0') {
|
|
/* Set field directly */
|
|
char *ptr = (char *) fields[player];
|
|
while (*s) {
|
|
if (*s <= '5')
|
|
*ptr++ = (*s++) - '0';
|
|
else switch (*s++) {
|
|
case 'a': *ptr++ = 6 + SPECIAL_A; break;
|
|
case 'b': *ptr++ = 6 + SPECIAL_B; break;
|
|
case 'c': *ptr++ = 6 + SPECIAL_C; break;
|
|
case 'g': *ptr++ = 6 + SPECIAL_G; break;
|
|
case 'n': *ptr++ = 6 + SPECIAL_N; break;
|
|
case 'o': *ptr++ = 6 + SPECIAL_O; break;
|
|
case 'q': *ptr++ = 6 + SPECIAL_Q; break;
|
|
case 'r': *ptr++ = 6 + SPECIAL_R; break;
|
|
case 's': *ptr++ = 6 + SPECIAL_S; break;
|
|
}
|
|
}
|
|
} else {
|
|
/* Set specific locations on field */
|
|
tile = 0;
|
|
while (*s) {
|
|
if (*s < '0') {
|
|
tile = *s - '!';
|
|
} else {
|
|
x = *s - '3';
|
|
y = (*++s) - '3';
|
|
fields[player][y][x] = tile;
|
|
}
|
|
s++;
|
|
}
|
|
}
|
|
if (player == my_playernum-1)
|
|
io->draw_own_field();
|
|
else
|
|
io->draw_other_field(player+1);
|
|
} else if (strcmp(cmd, "lvl") == 0) {
|
|
int player;
|
|
|
|
if (!(s = strtok(NULL, " ")))
|
|
return;
|
|
player = atoi(s)-1;
|
|
if (!(s = strtok(NULL, "")))
|
|
return;
|
|
levels[player] = atoi(s);
|
|
|
|
} else if (strcmp(cmd, "sb") == 0) {
|
|
int from, to;
|
|
char *type;
|
|
|
|
if (!(s = strtok(NULL, " ")))
|
|
return;
|
|
to = atoi(s);
|
|
if (!(type = strtok(NULL, " ")))
|
|
return;
|
|
if (!(s = strtok(NULL, " ")))
|
|
return;
|
|
from = atoi(s);
|
|
do_special(type, from, to);
|
|
|
|
} else if (strcmp(cmd, "gmsg") == 0) {
|
|
if (!(s = strtok(NULL, "")))
|
|
return;
|
|
io->draw_text(BUFFER_GMSG, s);
|
|
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
static char partyline_buffer[512];
|
|
static int partyline_pos = 0;
|
|
|
|
#define curpos (partyline_buffer+partyline_pos)
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Add a character to the partyline buffer. */
|
|
|
|
void partyline_input(int c)
|
|
{
|
|
if (partyline_pos < sizeof(partyline_buffer) - 1) {
|
|
memmove(curpos+1, curpos, strlen(curpos)+1);
|
|
partyline_buffer[partyline_pos++] = c;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Delete the current character from the partyline buffer. */
|
|
|
|
void partyline_delete(void)
|
|
{
|
|
if (partyline_buffer[partyline_pos]) {
|
|
memmove(curpos, curpos+1, strlen(curpos)-1+1);
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Backspace a character from the partyline buffer. */
|
|
|
|
void partyline_backspace(void)
|
|
{
|
|
if (partyline_pos > 0) {
|
|
partyline_pos--;
|
|
partyline_delete();
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Kill the entire partyline input buffer. */
|
|
|
|
void partyline_kill(void)
|
|
{
|
|
partyline_pos = 0;
|
|
*partyline_buffer = 0;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Move around the input buffer. Sign indicates direction; absolute value
|
|
* of 1 means one character, 2 means the whole line.
|
|
*/
|
|
|
|
void partyline_move(int how)
|
|
{
|
|
if (how == -2) {
|
|
partyline_pos = 0;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
} else if (how == -1 && partyline_pos > 0) {
|
|
partyline_pos--;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
} else if (how == 1 && partyline_buffer[partyline_pos]) {
|
|
partyline_pos++;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
} else if (how == 2) {
|
|
partyline_pos = strlen(partyline_buffer);
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
}
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Send the input line to the server. */
|
|
|
|
void partyline_enter(void)
|
|
{
|
|
char buf[1024];
|
|
|
|
if (*partyline_buffer) {
|
|
if (strncasecmp(partyline_buffer, "/me ", 4) == 0) {
|
|
sockprintf(server_sock, "plineact %d %s", my_playernum, partyline_buffer+4);
|
|
snprintf(buf, sizeof(buf), "* %s %s", players[my_playernum-1], partyline_buffer+4);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
} else if (strcasecmp(partyline_buffer, "/start") == 0) {
|
|
sockprintf(server_sock, "startgame 1 %d", my_playernum);
|
|
} else if (strcasecmp(partyline_buffer, "/end") == 0) {
|
|
sockprintf(server_sock, "startgame 0 %d", my_playernum);
|
|
} else if (strcasecmp(partyline_buffer, "/pause") == 0) {
|
|
sockprintf(server_sock, "pause 1 %d", my_playernum);
|
|
} else if (strcasecmp(partyline_buffer, "/unpause") == 0) {
|
|
sockprintf(server_sock, "pause 0 %d", my_playernum);
|
|
} else if (strncasecmp(partyline_buffer, "/team", 5) == 0) {
|
|
if (strlen(partyline_buffer) == 5)
|
|
strcpy(partyline_buffer+5, " "); /* make it "/team " */
|
|
sockprintf(server_sock, "team %d %s", my_playernum, partyline_buffer+6);
|
|
if (partyline_buffer[6]) {
|
|
if (teams[my_playernum-1])
|
|
free(teams[my_playernum-1]);
|
|
teams[my_playernum-1] = strdup(partyline_buffer+6);
|
|
snprintf(buf, sizeof(buf), "*** %s is Now on Team %s", players[my_playernum-1], partyline_buffer+6);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
} else {
|
|
if (teams[my_playernum-1])
|
|
free(teams[my_playernum-1]);
|
|
teams[my_playernum-1] = NULL;
|
|
snprintf(buf, sizeof(buf), "*** %s is Now Alone", players[my_playernum-1]);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
}
|
|
} else {
|
|
sockprintf(server_sock, "pline %d %s", my_playernum, partyline_buffer);
|
|
if (*partyline_buffer != '/'
|
|
|| partyline_buffer[1] == 0 || partyline_buffer[1] == ' ') {
|
|
/* We do not show server-side commands. */
|
|
snprintf(buf, sizeof(buf), "<%s> %s", players[my_playernum-1], partyline_buffer);
|
|
io->draw_text(BUFFER_PLINE, buf);
|
|
}
|
|
}
|
|
partyline_pos = 0;
|
|
*partyline_buffer = 0;
|
|
io->draw_partyline_input(partyline_buffer, partyline_pos);
|
|
}
|
|
}
|
|
|
|
#undef curpos
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
void help()
|
|
{
|
|
fprintf(stderr,
|
|
"Tetrinet " VERSION " - Text-mode tetrinet client\n"
|
|
"\n"
|
|
"Usage: tetrinet [OPTION]... NICK SERVER\n"
|
|
"\n"
|
|
"Options (see README for details):\n"
|
|
" -fancy Use \"fancy\" TTY graphics.\n"
|
|
" -fast Connect to the server in the tetrifast mode.\n"
|
|
" -log <file> Log network traffic to the given file.\n"
|
|
" -noshadow Do not make the pieces cast shadow.\n"
|
|
" -noslide Do not allow pieces to \"slide\" after being dropped\n"
|
|
" with the spacebar.\n"
|
|
" -server Start the server instead of the client.\n"
|
|
" -shadow Make the pieces cast shadow. Can speed up gameplay\n"
|
|
" considerably, but it can be considered as cheating by\n"
|
|
" some people since some other tetrinet clients lack this.\n"
|
|
" -slide Opposite of -noslide; allows pieces to \"slide\" after\n"
|
|
" being dropped. If both -slide and -noslide are given,\n"
|
|
" -slide takes precedence.\n"
|
|
" -windows Behave as much like the Windows version of Tetrinet as\n"
|
|
" possible. Implies -noslide and -noshadow.\n"
|
|
);
|
|
}
|
|
|
|
int init(int ac, char **av)
|
|
{
|
|
int i;
|
|
char *nick = NULL, *server = NULL;
|
|
char buf[1024];
|
|
char nickmsg[1024];
|
|
unsigned char ip[4];
|
|
char iphashbuf[32];
|
|
int len;
|
|
#ifdef BUILTIN_SERVER
|
|
int start_server = 0; /* Start the server? (-server) */
|
|
#endif
|
|
int slide = 0; /* Do we definitely want to slide? (-slide) */
|
|
|
|
|
|
/* If there's a DISPLAY variable set in the environment, default to
|
|
* Xwindows I/O, else default to terminal I/O. */
|
|
if (getenv("DISPLAY"))
|
|
io = &xwin_interface;
|
|
else
|
|
io = &tty_interface;
|
|
io=&tty_interface; /* because Xwin isn't done yet */
|
|
|
|
srand(time(NULL));
|
|
init_shapes();
|
|
|
|
for (i = 1; i < ac; i++) {
|
|
if (*av[i] == '-') {
|
|
#ifdef BUILTIN_SERVER
|
|
if (strcmp(av[i], "-server") == 0) {
|
|
start_server = 1;
|
|
} else
|
|
#endif
|
|
if (strcmp(av[i], "-fancy") == 0) {
|
|
fancy = 1;
|
|
} else if (strcmp(av[i], "-log") == 0) {
|
|
log = 1;
|
|
i++;
|
|
if (i >= ac) {
|
|
fprintf(stderr, "Option -log requires an argument\n");
|
|
return 1;
|
|
}
|
|
logname = av[i];
|
|
} else if (strcmp(av[i], "-noslide") == 0) {
|
|
noslide = 1;
|
|
} else if (strcmp(av[i], "-noshadow") == 0) {
|
|
cast_shadow = 0;
|
|
} else if (strcmp(av[i], "-shadow") == 0) {
|
|
cast_shadow = 1;
|
|
} else if (strcmp(av[i], "-slide") == 0) {
|
|
slide = 1;
|
|
} else if (strcmp(av[i], "-windows") == 0) {
|
|
windows_mode = 1;
|
|
noslide = 1;
|
|
cast_shadow = 0;
|
|
} else if (strcmp(av[i], "-fast") == 0) {
|
|
tetrifast = 1;
|
|
} else {
|
|
fprintf(stderr, "Unknown option %s\n", av[i]);
|
|
help();
|
|
return 1;
|
|
}
|
|
} else if (!nick) {
|
|
my_nick = nick = av[i];
|
|
} else if (!server) {
|
|
server = av[i];
|
|
} else {
|
|
help();
|
|
return 1;
|
|
}
|
|
}
|
|
if (slide)
|
|
noslide = 0;
|
|
#ifdef BUILTIN_SERVER
|
|
if (start_server)
|
|
exit(server_main());
|
|
#endif
|
|
if (!server) {
|
|
help();
|
|
return 1;
|
|
}
|
|
if (strlen(nick) > 63) /* put a reasonable limit on nick length */
|
|
nick[63] = 0;
|
|
|
|
if ((server_sock = conn(server, 31457, ip)) < 0) {
|
|
fprintf(stderr, "Couldn't connect to server %s: %s\n",
|
|
server, strerror(errno));
|
|
return 1;
|
|
}
|
|
sprintf(nickmsg, "tetri%s %s 1.13", tetrifast ? "faster" : "sstart", nick);
|
|
sprintf(iphashbuf, "%d", ip[0]*54 + ip[1]*41 + ip[2]*29 + ip[3]*17);
|
|
/* buf[0] does not need to be initialized for this algorithm */
|
|
len = strlen(nickmsg);
|
|
for (i = 0; i < len; i++)
|
|
buf[i+1] = (((buf[i]&0xFF) + (nickmsg[i]&0xFF)) % 255) ^ iphashbuf[i % strlen(iphashbuf)];
|
|
len++;
|
|
for (i = 0; i < len; i++)
|
|
sprintf(nickmsg+i*2, "%02X", buf[i] & 0xFF);
|
|
sputs(nickmsg, server_sock);
|
|
|
|
do {
|
|
if (!sgets(buf, sizeof(buf), server_sock)) {
|
|
fprintf(stderr, "Server %s closed connection\n", server);
|
|
disconn(server_sock);
|
|
return 1;
|
|
}
|
|
parse(buf);
|
|
} while (my_playernum < 0);
|
|
sockprintf(server_sock, "team %d ", my_playernum);
|
|
|
|
players[my_playernum-1] = strdup(nick);
|
|
dispmode = MODE_PARTYLINE;
|
|
io->screen_setup();
|
|
io->setup_partyline();
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
int main(int ac, char **av)
|
|
{
|
|
int i;
|
|
|
|
if ((i = init(ac, av)) != 0)
|
|
return i;
|
|
|
|
for (;;) {
|
|
int timeout;
|
|
if (playing_game && !game_paused)
|
|
timeout = tetris_timeout();
|
|
else
|
|
timeout = -1;
|
|
i = io->wait_for_input(timeout);
|
|
if (i == -1) {
|
|
char buf[1024];
|
|
if (sgets(buf, sizeof(buf), server_sock))
|
|
parse(buf);
|
|
else {
|
|
io->draw_text(BUFFER_PLINE, "*** Disconnected from Server");
|
|
break;
|
|
}
|
|
} else if (i == -2) {
|
|
tetris_timeout_action();
|
|
} else if (i == 12) { /* Ctrl-L */
|
|
io->screen_redraw();
|
|
} else if (i == K_F10) {
|
|
break; /* out of main loop */
|
|
} else if (i == K_F1) {
|
|
if (dispmode != MODE_FIELDS) {
|
|
dispmode = MODE_FIELDS;
|
|
io->setup_fields();
|
|
}
|
|
} else if (i == K_F2) {
|
|
if (dispmode != MODE_PARTYLINE) {
|
|
dispmode = MODE_PARTYLINE;
|
|
io->setup_partyline();
|
|
}
|
|
} else if (i == K_F3) {
|
|
if (dispmode != MODE_WINLIST) {
|
|
dispmode = MODE_WINLIST;
|
|
io->setup_winlist();
|
|
}
|
|
} else if (dispmode == MODE_FIELDS) {
|
|
tetris_input(i);
|
|
} else if (dispmode == MODE_PARTYLINE) {
|
|
if (i == 8 || i == 127) /* Backspace or Delete */
|
|
partyline_backspace();
|
|
else if (i == 4) /* Ctrl-D */
|
|
partyline_delete();
|
|
else if (i == 21) /* Ctrl-U */
|
|
partyline_kill();
|
|
else if (i == '\r' || i == '\n')
|
|
partyline_enter();
|
|
else if (i == K_LEFT)
|
|
partyline_move(-1);
|
|
else if (i == K_RIGHT)
|
|
partyline_move(1);
|
|
else if (i == 1) /* Ctrl-A */
|
|
partyline_move(-2);
|
|
else if (i == 5) /* Ctrl-E */
|
|
partyline_move(2);
|
|
else if (i >= 1 && i <= 0xFF)
|
|
partyline_input(i);
|
|
}
|
|
}
|
|
|
|
disconn(server_sock);
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
#endif /* !SERVER_ONLY */
|
|
|
|
/*************************************************************************/
|