version.c
*.o
netris
+server
sr
--- /dev/null
+---- done: -------------------------------------------------------------------
+
+ -- v0.6 ---------- 31.VII.02
+
+ * -D enables instant-drop (classic drop), original -D is now -d
+ * addition key for rotating pieces counterclockwise
+ * displays number of pieces dropped and lines made
+
+ -- v0.6.81 -------
+
+ * shows next piece
+ * displays elapsed time instead of clock
+ * shows ppm, apm and yield
+ * uses arrow keys by default (linux workaround, doesn't work on all systems)
+
+ -- v0.6.82 -------
+
+ * counts score (as in gameboy version)
+ * reads default parameters from netris.conf (or other file specified with -f)
+
+ -- v0.6.83 -------
+
+ * level up every 10 lines (speed x1.2)
+
+ -- v0.6.84 -------
+
+ * same handler for configfile/parameters
+ * linedraw characters unless --ascii specified
+ * levelup handeled correctly
+ * handicap with --level (affects yourself only, unlike --speed)
+ * some variables moved and altered
+ * displays name+host above opponent field
+
+ -- v0.6.85 -------
+
+ * titlebar somewhat improved
+ * pause stops time
+ * junklines doesn't move pieces up (unless inside ground)
+ * improved (insta)drop handling
+ * drop/down at bottom forces drop
+ * updated help messages (-[hH])
+
+ -- v0.6.86 -------
+
+ * server doesn't play
+
+ -- v0.6.87 -------
+
+ * multiplay can handle over 2 players!
+
+ -- v0.6.88 -------
+
+ * player 1 always leftmost
+ * server seperate program
+
+ -- v0.6.89 -------
+
+ * server receive fixed (checked nonexisting sock)
+ * host generates and distributes player's host string
+ * handle sigint correctly (not just exit(0))
+ * fix multiplay g/o (close connection at g/o or server signal)
+ * spy=n0 in configfile disables spying for player n
+
+
+---- near-future: ------------------------------------------------------------
+
+ * teams
+ * send game options
+ * fix multplay pause
+ * server continuously acceping new connections, and immediate handshake
+ * fix g/o (server should count, maybe reorder players)
+ * everybody start paused?
+ * show n fields (improved spy parameter)
+
+
+---- asap: -------------------------------------------------------------------
+
+ * fix -f
+ * midgame join option
+ * optional enemy field resize
+ * multiplayer stats
+ * pause message over player's field
+
+
+---- distant future: ---------------------------------------------------------
+
+ * special blocks
+ * tetrinet compatible?
+
+
+------------------------------------------------------------------------------
#
CC="gcc"
-COPT="-g -O"
+COPT="-O -m486"
CEXTRA=""
LEXTRA=""
CURSES_HACK=false
shift
case "$opt" in
-g)
- COPT="-g"
- CEXTRA="-Wall -Wstrict-prototypes"
+ COPT="-g -O0"
+# CEXTRA="-Wall -Wstrict-prototypes"
;;
-O*)
COPT="$opt"
SRCS="`echo $SOURCES | sed -e s/-/.c/g`"
OBJS="`echo $SOURCES | sed -e s/-/.o/g`"
-DISTFILES="README FAQ COPYING VERSION Configure netris.h sr.c robot_desc"
+DISTFILES="README FAQ COPYING VERSION Configure netris.h sr.c server.c robot_desc"
DISTFILES="$DISTFILES `echo $ORIG_SOURCES | sed -e s/-/.c/g`"
echo > .depend
OBJS = -OBJS-
DISTFILES = -DISTFILES-
-all: Makefile config.h proto.h $(PROG) sr
+all: Makefile config.h proto.h $(PROG) sr server
$(PROG): $(OBJS)
- $(CC) -o $(PROG) $(OBJS) $(LFLAGS)
+ $(CC) -o $(PROG) $(OBJS) $(LFLAGS) $(CFLAGS)
sr: sr.o
- $(CC) -o sr sr.o $(LFLAGS)
+ $(CC) -o sr sr.o $(LFLAGS) $(CFLAGS)
+
+server: server.o
+ $(CC) -o server server.o $(LFLAGS) $(CFLAGS)
.c.o:
$(CC) $(CFLAGS) -c $<
tar -cvzof $$dir.tar.gz $$dir
clean:
- rm -f proto.h proto.chg $(PROG) $(OBJS) version.c test.c a.out sr sr.o
+ rm -f proto.h proto.chg $(PROG) $(OBJS) version.c test.c a.out sr sr.o server server.o
cleandir: clean
rm -f .depend Makefile config.h
static int falling[MAX_SCREENS][MAX_BOARD_WIDTH];
static int oldFalling[MAX_SCREENS][MAX_BOARD_WIDTH];
-ExtFunc void InitBoard(int scr)
-{
- boardHeight[scr] = MAX_BOARD_HEIGHT;
- boardVisible[scr] = 20;
- boardWidth[scr] = 10;
- InitScreen(scr);
-}
-
ExtFunc void CleanupBoard(int scr)
{
CleanupScreen(scr);
ExtFunc BlockType GetBlock(int scr, int y, int x)
{
- if (y < 0 || x < 0 || x >= boardWidth[scr])
+ if (y < 0 || x < 0 || x >= Players[scr].boardWidth)
return BT_wall;
- else if (y >= boardHeight[scr])
+ else if (y >= Players[scr].boardHeight)
return BT_none;
else
return abs(board[scr][y][x]);
ExtFunc void SetBlock(int scr, int y, int x, BlockType type)
{
- if (y >= 0 && y < boardHeight[scr] && x >= 0 && x < boardWidth[scr]) {
- if (y < boardVisible[scr])
+ if (y >= 0 && y < Players[scr].boardHeight &&
+ x >= 0 && x < Players[scr].boardWidth) {
+ if (y < Players[scr].boardVisible)
falling[scr][x] += (type < 0) - (board[scr][y][x] < 0);
board[scr][y][x] = type;
changed[scr][y] |= 1 << x;
unsigned int c;
BlockType b;
- for (y = boardVisible[scr] - 1; y >= 0; --y)
+ for (y = Players[scr].boardVisible - 1; y >= 0; --y)
if ((c = changed[scr][y])) {
if (robotEnable) {
RobotCmd(0, "RowUpdate %d %d", scr, y);
- for (x = 0; x < boardWidth[scr]; ++x) {
+ for (x = 0; x < Players[scr].boardWidth; ++x) {
b = board[scr][y][x];
if (fairRobot)
b = abs(b);
}
if (robotEnable)
RobotTimeStamp();
- for (x = 0; x < boardWidth[scr]; ++x)
+ for (x = 0; x < Players[scr].boardWidth; ++x)
if (oldFalling[scr][x] != !!falling[scr][x]) {
oldFalling[scr][x] = !!falling[scr][x];
PlotUnderline(scr, x, oldFalling[scr][x]);
ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data)
{
- PlotBlock1(scr, y, x, type);
+ PlotBlock1(scr, 20 - y, x * 2, type);
return 0;
}
ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data)
{
- return (y >= 0 && y < boardVisible[scr] && x >= 0 && x < boardWidth[scr]);
+ return (y >= 0 && y < Players[scr].boardVisible &&
+ x >= 0 && x < Players[scr].boardWidth);
}
ExtFunc void PlotShape(Shape *shape, int scr, int y, int x, int falling)
{
int result;
- EraseShape(curShape[scr], scr, curY[scr], curX[scr]);
- result = ShapeFits(curShape[scr], scr, curY[scr] + deltaY,
- curX[scr] + deltaX);
+ EraseShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX);
+ result = ShapeFits(Players[scr].curShape, scr, Players[scr].curY + deltaY,
+ Players[scr].curX + deltaX);
if (result) {
- curY[scr] += deltaY;
- curX[scr] += deltaX;
+ Players[scr].curY += deltaY;
+ Players[scr].curX += deltaX;
}
- PlotShape(curShape[scr], scr, curY[scr], curX[scr], 1);
+ PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, 1);
return result;
}
{
int result;
- EraseShape(curShape[scr], scr, curY[scr], curX[scr]);
- result = ShapeFits(dir ? curShape[scr]->rotateTo : curShape[scr]->rotateFrom,
- scr, curY[scr], curX[scr]);
+ EraseShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX);
+ result = ShapeFits(dir ? Players[scr].curShape->rotateTo
+ : Players[scr].curShape->rotateFrom,
+ scr, Players[scr].curY, Players[scr].curX);
if (result)
- curShape[scr] = dir ? curShape[scr]->rotateTo : curShape[scr]->rotateFrom;
- PlotShape(curShape[scr], scr, curY[scr], curX[scr], 1);
+ Players[scr].curShape = dir ? Players[scr].curShape->rotateTo
+ : Players[scr].curShape->rotateFrom;
+ PlotShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX, 1);
return result;
}
{
int count = 0;
- EraseShape(curShape[scr], scr, curY[scr], curX[scr]);
- while (ShapeFits(curShape[scr], scr, curY[scr] - 1, curX[scr])) {
- --curY[scr];
+ EraseShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX);
+ while (ShapeFits(Players[scr].curShape, scr,
+ Players[scr].curY - 1, Players[scr].curX)) {
+ --Players[scr].curY;
++count;
}
- PlotShape(curShape[scr], scr, curY[scr], curX[scr], 1);
+ PlotShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX, 1);
return count;
}
{
int x;
- for (x = 0; x < boardWidth[scr]; ++x)
+ for (x = 0; x < Players[scr].boardWidth; ++x)
if (GetBlock(scr, y, x) == BT_none)
return 0;
return 1;
int x;
if (from != to)
- for (x = 0; x < boardWidth[scr]; ++x)
+ for (x = 0; x < Players[scr].boardWidth; ++x)
SetBlock(scr, to, x, GetBlock(scr, from, x));
}
int from, to;
from = to = 0;
- while (to < boardHeight[scr]) {
+ while (to < Players[scr].boardHeight) {
while (LineIsFull(scr, from))
++from;
CopyLine(scr, from++, to++);
int y, x;
BlockType type;
- for (y = 0; y < boardHeight[scr]; ++y)
- for (x = 0; x < boardWidth[scr]; ++x)
+ for (y = 0; y < Players[scr].boardHeight; ++y)
+ for (x = 0; x < Players[scr].boardWidth; ++x)
if ((type = board[scr][y][x]) < 0)
SetBlock(scr, y, x, -type);
}
{
int y, x;
- for (y = boardHeight[scr] - count - 1; y >= 0; --y)
+ EraseShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX);
+ for (y = Players[scr].boardHeight - count - 1; y >= 0; --y)
CopyLine(scr, y, y + count);
for (y = 0; y < count; ++y)
- for (x = 0; x < boardWidth[scr]; ++x)
+ for (x = 0; x < Players[scr].boardWidth; ++x)
SetBlock(scr, y, x, (x == column) ? BT_none : BT_white);
- curY[scr] += count;
+ Players[scr].curY += count; //move piece up..
+ for (y = 0; y < count; ++y)
+ if (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX))
+ Players[scr].curY--; //..and down as far as possible
+ else break;
+ PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX, 1);
}
/*
#endif
#ifdef HAVE_NCURSES
- haveColor = colorEnable && has_colors();
- if (haveColor)
- {
+ haveColor = Game.color && has_colors();
+ if (haveColor) {
int i = 0;
start_color();
OutputTermStr(term_vi, 0);
AddEventGen(&keyGen);
- move(0, 0);
- addstr("Netris ");
+ move(0, 1);
+ addstr("NETRIS ");
addstr(version_string);
- addstr(" (C) 1994-1996,1999 Mark H. Weaver "
- "\"netris -h\" for more info");
+ {
+ int rows, cols;
+
+ getmaxyx(stdscr, rows, cols);
+ move(0, cols - 48);
+ addstr("(C)1994-1996,1999 Mark H. Weaver, (C)2002 Shiar");
+// addstr(" \"netris -h\" for more info");
+ }
statusYPos = 22;
statusXPos = 0;
}
}
}
-ExtFunc void InitScreen(int scr)
+ExtFunc void DrawField(int scr)
{
- int y, x;
+ {
+ int y, x;
+
+ for (y = Players[scr].boardVisible - 1; y >= 0; --y) {
+ mvaddch(boardYPos[scr] - y, boardXPos[scr] - 1,
+ Game.ascii ? '|' : ACS_VLINE); //left
+ mvaddch(boardYPos[scr] - y,
+ boardXPos[scr] + 2 * Players[scr].boardWidth,
+ Game.ascii ? '|' : ACS_VLINE); //right
+ }
+ move(2, boardXPos[scr] - 1); //top
+ addch(Game.ascii ? '+' : ACS_ULCORNER);
+ for (x = Players[scr].boardWidth * 2 - 1; x >= 0; --x)
+ addch(Game.ascii ? '-' : ACS_HLINE);
+ addch(Game.ascii ? '+' : ACS_URCORNER);
+ move(boardYPos[scr] + 1, boardXPos[scr] - 1); //bottom
+ addch(Game.ascii ? '+' : ACS_LLCORNER);
+ for (x = Players[scr].boardWidth * 2 - 1; x >= 0; --x)
+ addch(Game.ascii ? '-' : ACS_HLINE);
+ addch(Game.ascii ? '+' : ACS_LRCORNER);
+ } //draw field grid
- if (scr == 0)
- boardXPos[scr] = 1;
- else
- boardXPos[scr] = boardXPos[scr - 1] +
- 2 * boardWidth[scr - 1] + 3;
- if (scr == 1)
- boardXPos[scr] += 24;
- boardYPos[scr] = 22;
- statusXPos = 2 * boardWidth[0] + 3;
-// if (statusXPos < boardXPos[scr] + 2 * boardWidth[scr] + 3)
-// statusXPos = boardXPos[scr] + 2 * boardWidth[scr] + 3;
- for (y = boardVisible[scr] - 1; y >= 0; --y) {
- move(boardYPos[scr] - y, boardXPos[scr] - 1);
- addch('|');
- move(boardYPos[scr] - y, boardXPos[scr] + 2 * boardWidth[scr]);
- addch('|');
- }
- for (y = boardVisible[scr]; y >= -1; y -= boardVisible[scr] + 1) {
- move(boardYPos[scr] - y, boardXPos[scr] - 1);
- addch('+');
- for (x = boardWidth[scr] - 1; x >= 0; --x)
- addstr("--");
- addch('+');
+ {
+ char userstr[300];
+
+ sprintf(userstr, "%s <%s>", Players[scr].name, Players[scr].host);
+ userstr[20 - 7*((Players[scr].flags & SCF_usingRobot) != 0)
+ - 5*((Players[scr].flags & SCF_fairRobot) != 0)] = 0;
+ mvaddstr(1, boardXPos[scr], userstr);
+
+ if (Players[scr].flags & SCF_usingRobot) {
+ addstr((Players[scr].flags & SCF_fairRobot)
+ ? "(fair robot)" : "(robot)");
+ }
+ } //display playername/host
+} //DrawScreen
+
+ExtFunc void InitFields()
+{
+ int scr, prevscr;
+
+ boardXPos[me] = 1;
+ boardYPos[me] = 22;
+ prevscr = me;
+ for (scr = 1; scr <= totalPlayers + 1; scr++) if (scr != me) {
+ boardXPos[scr] =
+ boardXPos[prevscr] + 2 * Players[prevscr].boardWidth + 3;
+ if (prevscr == me)
+ boardXPos[scr] += 24; //scorebar
+ boardYPos[scr] = 22;
+ prevscr = scr;
}
-}
+ statusXPos = 2 * Players[me].boardWidth + 3;
+} //InitScreen
ExtFunc void CleanupScreen(int scr)
{
{
int colorIndex = abs(type);
- move(boardYPos[scr] - y, boardXPos[scr] + 2 * x);
+ move(y, x);
if (type == BT_none)
addstr(" ");
else
{
- if (standoutEnable)
+ if (Game.standout)
{
#ifdef HAVE_NCURSES
if (haveColor)
ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
{
- if (y >= 0 && y < boardVisible[scr] && x >= 0 && x < boardWidth[scr])
- PlotBlock1(scr, y, x, type);
+ if (y >= 0 && y < Players[scr].boardVisible &&
+ x >= 0 && x < Players[scr].boardWidth)
+ PlotBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
}
ExtFunc void PlotUnderline(int scr, int x, int flag)
{
- move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
+ move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
+ if (Game.ascii)
addstr(flag ? "==" : "--");
+ else {
+ addch(flag ? ACS_BTEE : ACS_HLINE);
+ addch(flag ? ACS_BTEE : ACS_HLINE);
+ }
}
ExtFunc void ShowDisplayInfo(void)
{
- move(statusYPos - 9, statusXPos);
- printw("Seed: %010d", initSeed);
- move(statusYPos - 8, statusXPos);
- printw("Speed: %dms ", speed / 1000);
- if (robotEnable) {
- move(statusYPos - 6, statusXPos);
- if (fairRobot)
- addstr("Controlled by a fair robot");
- else
- addstr("Controlled by a robot");
-// clrtoeol();
- }
- if (opponentFlags & SCF_usingRobot) {
- move(statusYPos - 5, statusXPos);
- if (opponentFlags & SCF_fairRobot)
- addstr("The opponent is a fair robot");
- else
- addstr("The opponent is a robot");
-// clrtoeol();
- }
+ move(statusYPos - 9, statusXPos);
+ printw("Seed: %010d", Game.seed);
+ // move(statusYPos - 8, statusXPos);
+ // printw("Speed: %dms ", speed / 1000);
+ if (robotEnable) {
+ move(statusYPos - 6, statusXPos);
+ if (fairRobot)
+ addstr("Controlled by a fair robot");
+ else
+ addstr("Controlled by a robot");
+ // clrtoeol();
+ }
+ if (Players[1].flags & SCF_usingRobot) {
+ move(statusYPos - 5, statusXPos);
+ if (Players[1].flags & SCF_fairRobot)
+ addstr("The opponent is a fair robot");
+ else
+ addstr("The opponent is a robot");
+ // clrtoeol();
+ }
}
-ExtFunc void ShowScore(int scr, int totalDrops, int totalLines, int totalAdds)
+ExtFunc void ShowScore(int scr, struct _Score score)
{
float timer;
- move(6, statusXPos); addstr("Next: ");
- move(7, statusXPos + 6); addstr(" ");
- ShapeIterate(nextShape[scr], scr,
- ShapeToNetNum(nextShape[scr]) == 15 ? 15 : 16, statusXPos/2 + 4,
- 1, GlanceFunc, NULL);
+
+ move(6, statusXPos); addstr("Next: ");
+ move(7, statusXPos + 7); addstr(" ");
+ ShapeIterate(Players[scr].nextShape, scr,
+ ShapeToNetNum(Players[scr].nextShape) == 15 ? 13 : 14,
+ statusXPos / 2 + 5, 1, GlanceFunc, NULL);
+ move(statusYPos - 21 + 1, statusXPos);
+ printw("Score:%6d level: %2d", score.score, score.level);
move(statusYPos - 20 + 1, statusXPos);
timer = CurTimeval() / 1e6;
- printw("Lines: %05d", totalLines);
- if (timer > 4)
- printw(" (%.1f ppm)", totalDrops * 60 / timer);
- move(statusYPos - 18, statusXPos);
- printw("apm: %.1f", totalAdds * 60 / timer);
- if (totalLines > 0)
- printw(" (%d%% yield) ", 100 * totalAdds / totalLines);
-}
-
-ExtFunc void UpdateOpponentDisplay(void)
-{
- move(1, 0);
- printw("Playing %s@%s", opponentName, opponentHost);
- clrtoeol();
+ printw("Lines:%6d", score.lines);
+ if (timer > 4) {
+ printw(" ppm:%5.1f", score.drops * 60 / timer);
+ move(statusYPos - 18, statusXPos);
+ if (score.lines > 0)
+ printw("yield: %3d%%", 100 * score.adds / score.lines);
+ else addstr(" ");
+ printw(" apm:%5.1f", score.adds * 60 / timer);
+ }
}
ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
clrtoeol();
}
-ExtFunc void RefreshScreen(void)
+ExtFunc void ShowTime(void)
{
-/*
- static char timeStr[2][32];
- time_t theTime;
-
- time(&theTime);
- strftime(timeStr[0], 30, "%I:%M %p", localtime(&theTime));
- // Just in case the local curses library sucks
- if (strcmp(timeStr[0], timeStr[1]))
- {
- move(statusYPos, statusXPos);
- addstr(timeStr[0]);
- strcpy(timeStr[1], timeStr[0]);
- }
- move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
- refresh();
-*/
move(statusYPos, statusXPos);
printw("Timer: %.0f ", CurTimeval() / 1e6);
- move(boardYPos[0] + 1, boardXPos[0] + 2 * boardWidth[0] + 1);
- refresh();
+ move(boardYPos[0] + 1, boardXPos[0] + 2 * Players[0].boardWidth + 1);
+// refresh();
}
ExtFunc void ScheduleFullRedraw(void)
#include <sys/types.h>
#include <netinet/in.h>
+static struct option options[] = {
+ { "ascii", 2, 0, 'a' },
+ { "connect", 1, 0, 'c' },
+ { "port", 1, 0, 'p' },
+ { "speed", 1, 0, 'i' },
+ { "level", 1, 0, 'l' },
+ { "spy", 1, 0, 1 },
+ { "seed", 1, 0, 's' },
+ { "robot", 1, 0, 'r' },
+ { "fair-robot", 0, 0, 'F' },
+ { "dropmode", 2, 0, 'd' },
+ { "instadrop", 2, 0, 'D' },
+ { "color", 2, 0, 'C' },
+ { "slowterm", 2, 0, 'S' },
+ { "keys", 1, 0, 'k' },
+ { "rules", 0, 0, 'R' },
+ { "info", 0, 0, 'H' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
enum { KT_left, KT_right, KT_rotright, KT_rotleft, KT_drop, KT_down,
- KT_toggleSpy, KT_pause, KT_faster, KT_redraw, KT_numKeys };
+ KT_toggleSpy, KT_pause, KT_faster, KT_redraw, KT_numKeys };
static char *keyNames[KT_numKeys+1] = {
"Left", "Right", "RotRight", "RotLeft", "Drop", "Down",
static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
static char keyTable[KT_numKeys+1];
-static int dropModeEnable = 0;
-static char *robotProg;
+
ExtFunc void MapKeys(char *newKeys)
{
}
if (errs)
exit(1);
-}
+} //MapKeys
+
+ExtFunc void WriteConf(void)
+{
+ FILE *file_out;
+
+ file_out = fopen(CONFIG_FILE, "w");
+ if (file_out == NULL)
+ die("Error writing config file");
+
+ fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string);
+
+ fclose(file_out);
+ fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
+} //WriteConf
+
+ExtFunc void HandleOption(char tag, char *value)
+{
+ switch (tag) {
+ case 'a': //ascii
+ if (value && !strcasecmp(value, "0")) Game.ascii = 0;
+ else Game.ascii = 1;
+ break;
+ case 'c': //connect
+ initConn = 1;
+ hostStr = value;
+ break;
+ case 'p': //port
+ portStr = value; break;
+ case 'i': //speed (of level 1)
+ Game.initspeed = atof(value) * 1e6;
+ break;
+ case 'l': //level
+ if ((Players[0].score.level = atof(value)) < 1)
+ Players[0].score.level = 1;
+ if (Players[0].score.level > 15)
+ Players[0].score.level = 15;
+ break;
+ case 1: //spy
+ {
+ int i;
+ i = atof(value);
+ Players[i / 10].spy = i % 10;
+ }
+ break;
+ case 's': //seed
+ Game.seed = atoi(value);
+ break;
+ case 'r': //robot
+ robotEnable = 1;
+ Players[0].flags |= SCF_usingRobot;
+ InitRobot(value);
+ break;
+ case 'F': //fair robot
+ fairRobot = 1;
+ Players[0].flags |= SCF_fairRobot;
+ break;
+ case 'd': //drop mode
+ if (value && !strcasecmp(value, "0")) Players[0].dropmode &= 254;
+ else Players[0].dropmode |= 1;
+ break;
+ case 'D': //instadrop
+ if (value && !strcasecmp(value, "0")) Players[0].dropmode &= 253;
+ else Players[0].dropmode |= 2;
+ break;
+ case 'C': //color
+ if (value && !strcasecmp(value, "1")) Game.color = 1;
+ else Game.color = 0;
+ break;
+ case 'S': //slowterm
+ if (value && !strcasecmp(value, "1")) Game.standout = 1;
+ else Game.standout = 0;
+ break;
+ case 'k': //keys
+ MapKeys(value); break;
+ case 'H': //info
+ DistInfo(); exit(0);
+ case 'R': //rules
+ Rules(); exit(0);
+ case 'h': //help
+ Usage(); exit(0);
+ default:
+ Usage(); exit(1);
+ }
+} //HandleParam
+
+ExtFunc void ReadConf(char *filename)
+{
+ FILE *file_in;
+ char buf[513];
+ int i;
+ char *ch;
+ char tag[81], value[81];
+
+ file_in = fopen(filename, "r");
+ if (file_in) {
+ while (fgets(buf, 512, file_in) != NULL) {
+ if ((ch = strchr(buf, '#')))
+ *ch = '\0'; // truncate string from # char
+ for (i = strlen(buf)-1; i >= 0; i--)
+ if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || buf[i] == 13)
+ buf[i] = '\0';
+ else break;
+
+ sscanf(buf, "%80[^= \t] = %80[^\n]", tag, value);
+ for (i = 0; options[i].name; i++){
+ if (!strcasecmp(options[i].name, tag)) {
+ HandleOption(options[i].val, value);
+ break;
+ }
+ }
+ }
+ fclose(file_in);
+ } //read file
+ else {
+ fprintf(stderr, "Unable to open config file %s.\n", filename);
+ } //defaults
+
+} //ReadConf
ExtFunc int StartNewPiece(int scr, Shape *shape)
{
- if (nextShape[scr]) {
- curShape[scr] = nextShape[scr];
- nextShape[scr] = shape;
+ if (Players[scr].nextShape) {
+ Players[scr].curShape = Players[scr].nextShape;
+ Players[scr].nextShape = shape;
}
else
- curShape[scr] = shape;
- curY[scr] = boardVisible[scr] + 4;
- curX[scr] = boardWidth[scr] / 2;
- while (!ShapeVisible(curShape[scr], scr, curY[scr], curX[scr]))
- --curY[scr];
- if (!ShapeFits(curShape[scr], scr, curY[scr], curX[scr]))
+ Players[scr].curShape = shape;
+ Players[scr].curY = Players[scr].boardVisible + 4;
+ Players[scr].curX = Players[scr].boardWidth / 2;
+ while (!ShapeVisible(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX))
+ Players[scr].curY--;
+ if (!ShapeFits(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX))
return 0;
- PlotShape(curShape[scr], scr, curY[scr], curX[scr], 1);
+ PlotShape(Players[scr].curShape, scr,
+ Players[scr].curY, Players[scr].curX, 1);
return 1;
}
-ExtFunc void OneGame(int scr, int scr2)
+ExtFunc void OneGame(int scr)
{
MyEvent event;
int linesCleared, changed = 0;
- int totalDrops = 0, totalLines = 0, totalAdds = 0;
- int spied = 0, spying = 0, dropMode = 0;
+ int spied = 0, dropMode = 0;
int oldPaused = 0, paused = 0, pausedByMe = 0, pausedByThem = 0;
long pauseTimeLeft;
int pieceCount = 0;
int key;
char *p, *cmd;
+ int linevalues[4] = { 40, 100, 400, 1200 }; //= 50*lines! - 10*(lines==1)
+ int i;
- speed = stepDownInterval;
+ Game.speed = Game.initspeed;
+ for (i = 1; i < Players[scr].score.level; i++)
+ Game.speed /= SPEEDINC;
+ if (Game.speed < SPEEDMINIMUM)
+ Game.speed = SPEEDMINIMUM;
ResetBaseTime();
- InitBoard(scr);
- if (scr2 >= 0) {
+ InitFields();
+ for (i = 1; i <= totalPlayers + 1; i++)
+ if (Players[i].spy) DrawField(i);
+ if (totalPlayers > 0) {
spied = 1;
- spying = 1;
- InitBoard(scr2);
- UpdateOpponentDisplay();
}
ShowDisplayInfo();
- SetITimer(speed, speed);
+ SetITimer(Game.speed, Game.speed);
if (robotEnable) {
RobotCmd(0, "GameType %s\n", gameNames[game]);
RobotCmd(0, "BoardSize 0 %d %d\n",
- boardVisible[scr], boardWidth[scr]);
- if (scr2 >= 0) {
- RobotCmd(0, "BoardSize 1 %d %d\n",
- boardVisible[scr2], boardWidth[scr2]);
- RobotCmd(0, "Opponent 1 %s %s\n", opponentName, opponentHost);
- if (opponentFlags & SCF_usingRobot)
- RobotCmd(0, "OpponentFlag 1 robot\n");
- if (opponentFlags & SCF_fairRobot)
- RobotCmd(0, "OpponentFlag 1 fairRobot\n");
+ Players[scr].boardVisible, Players[scr].boardWidth);
+ for (i = 1; i <= totalPlayers + 1; i++) {
+ RobotCmd(0, "BoardSize %d %d %d\n",
+ i, Players[i].boardVisible, Players[i].boardWidth);
+ RobotCmd(0, "Opponent %d %s %s\n",
+ i, Players[i].name, Players[i].host);
+ if (Players[i].flags & SCF_usingRobot)
+ RobotCmd(0, "OpponentFlag %d robot\n", i);
+ if (Players[i].flags & SCF_fairRobot)
+ RobotCmd(0, "OpponentFlag %d fairRobot\n", i);
}
- RobotCmd(0, "TickLength %.3f\n", speed / 1.0e6);
+ RobotCmd(0, "TickLength %.3f\n", Game.speed / 1.0e6);
RobotCmd(0, "BeginGame\n");
RobotTimeStamp();
}
- nextShape[scr] = ChooseOption(stdOptions);
+ Players[scr].nextShape = ChooseOption(stdOptions);
while (StartNewPiece(scr, ChooseOption(stdOptions))) {
- ShowScore(scr, totalDrops, totalLines, totalAdds);
+ ShowScore(scr, Players[scr].score);
if (robotEnable && !fairRobot)
RobotCmd(1, "NewPiece %d\n", ++pieceCount);
if (spied) {
short shapeNum;
netint2 data[1];
- shapeNum = ShapeToNetNum(curShape[scr]);
+ shapeNum = ShapeToNetNum(Players[scr].curShape);
data[0] = hton2(shapeNum);
SendPacket(scr, NP_newPiece, sizeof(data), data);
}
for (;;) {
changed = RefreshBoard(scr) || changed;
- if (spying)
- changed = RefreshBoard(scr2) || changed;
+ for (i = 1; i <= totalPlayers+1; i++) if (Players[i].spy && i != me)
+ changed = RefreshBoard(i) || changed;
if (changed) {
- RefreshScreen();
+ if (!paused) ShowTime();
+ refresh();
changed = 0;
}
CheckNetConn();
SendPacket(scr, NP_rotright, 0, NULL);
break;
case KT_down:
- if (MovePiece(scr, -1, 0) && spied)
- SendPacket(scr, NP_down, 0, NULL);
- SetITimer(speed, speed);
- break;
- case KT_toggleSpy:
- spying = (!spying) && (scr2 >= 0);
+ SetITimer(Game.speed, Game.speed);
+ if (MovePiece(scr, -1, 0)) {
+ if (spied) SendPacket(scr, NP_down, 0, NULL);
+ }
+ else goto nextPiece;
break;
case KT_drop:
- if (DropPiece(scr) > 0) {
- if (spied)
- SendPacket(scr, NP_drop, 0, NULL);
- if (dropModeEnable == 2)
- SetITimer(speed, 1); //instantdrop
- else
- SetITimer(speed, speed);
+ SetITimer(Game.speed, Game.speed);
+ if (DropPiece(scr)) {
+ if (spied) SendPacket(scr, NP_drop, 0, NULL);
+ if (Players[scr].dropmode == 2) goto nextPiece;
}
- dropMode = dropModeEnable;
+ else goto nextPiece;
+ dropMode = Players[scr].dropmode;
break;
case KT_pause:
pausedByMe = !pausedByMe;
case KT_faster:
if (game != GT_onePlayer)
break;
- speed = speed * 0.8;
- SetITimer(speed, SetITimer(0, 0));
- ShowDisplayInfo();
+ if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM)
+ Game.speed = SPEEDMINIMUM;
+ SetITimer(Game.speed, SetITimer(0, 0));
+ Players[scr].score.level++;
+ ShowScore(scr, Players[scr].score);
changed = 1;
break;
case KT_redraw:
ScheduleFullRedraw();
- if (paused)
- RefreshScreen();
+// if (paused)
+// RefreshScreen();
break;
}
if (dropMode && DropPiece(scr) > 0) {
+ SetITimer(Game.speed, Game.speed);
if (spied)
SendPacket(scr, NP_drop, 0, NULL);
- SetITimer(speed, speed);
}
break;
case E_robot:
short column;
memcpy(data, event.u.net.data, sizeof(data[0]));
- column = Random(0, boardWidth[scr]);
+ column = Random(0, Players[scr].boardWidth);
data[1] = hton2(column);
InsertJunk(scr, ntoh2(data[0]), column);
if (spied)
short shapeNum;
netint2 data[1];
- FreezePiece(scr2);
+ FreezePiece(event.u.net.uid);
memcpy(data, event.u.net.data, sizeof(data));
shapeNum = ntoh2(data[0]);
- StartNewPiece(scr2, NetNumToShape(shapeNum));
+ StartNewPiece(event.u.net.uid, NetNumToShape(shapeNum));
break;
}
case NP_down:
- MovePiece(scr2, -1, 0);
+ MovePiece(event.u.net.uid, -1, 0);
break;
case NP_left:
- MovePiece(scr2, 0, -1);
+ MovePiece(event.u.net.uid, 0, -1);
break;
case NP_right:
- MovePiece(scr2, 0, 1);
+ MovePiece(event.u.net.uid, 0, 1);
break;
case NP_rotleft:
- RotatePiece(scr2, 0);
+ RotatePiece(event.u.net.uid, 0);
break;
case NP_rotright:
- RotatePiece(scr2, 1);
+ RotatePiece(event.u.net.uid, 1);
break;
case NP_drop:
- DropPiece(scr2);
+ DropPiece(event.u.net.uid);
break;
case NP_clear:
- ClearFullLines(scr2);
+ ClearFullLines(event.u.net.uid);
break;
case NP_insertJunk:
{
netint2 data[2];
memcpy(data, event.u.net.data, sizeof(data));
- InsertJunk(scr2, ntoh2(data[0]), ntoh2(data[1]));
+ InsertJunk(event.u.net.uid, ntoh2(data[0]), ntoh2(data[1]));
break;
}
case NP_pause:
break;
}
if (paused != oldPaused) {
- if (paused)
+ if (paused) {
+ PauseTime();
pauseTimeLeft = SetITimer(0, 0);
- else
- SetITimer(speed, pauseTimeLeft);
+ }
+ else {
+ SetITimer(Game.speed, pauseTimeLeft);
+ ResumeTime();
+ }
oldPaused = paused;
}
}
nextPiece:
dropMode = 0;
FreezePiece(scr);
- totalDrops++;
+ Players[scr].score.drops++;
+ Players[scr].score.score++;
if ((linesCleared = ClearFullLines(scr)) > 0) {
- totalLines += linesCleared;
- totalAdds += linesCleared - (linesCleared < 4);
+ if (game == GT_onePlayer)
+ if ((Players[scr].score.lines / 10) <
+ ((Players[scr].score.lines + linesCleared) / 10)) {
+ if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM)
+ Game.speed = SPEEDMINIMUM;
+ SetITimer(Game.speed, SetITimer(0, 0));
+ Players[scr].score.level++;
+ } //level up
+ Players[scr].score.score += linevalues[linesCleared];
+ Players[scr].score.lines += linesCleared;
+ Players[scr].score.adds += linesCleared - (linesCleared < 4);
+ if (spied)
+ SendPacket(scr, NP_clear, 0, NULL);
}
- if (linesCleared > 0 && spied)
- SendPacket(scr, NP_clear, 0, NULL);
if (game == GT_classicTwo && linesCleared > 1) {
short junkLines;
netint2 data[1];
ExtFunc int main(int argc, char **argv)
{
- int initConn = 0, waitConn = 0, ch;
- char *hostStr = NULL, *portStr = NULL;
+ char ch;
- standoutEnable = colorEnable = 1;
- stepDownInterval = DEFAULT_INTERVAL;
+ Game.standout = Game.color = 1;
+ Game.initspeed = DEFAULT_INTERVAL;
MapKeys(DEFAULT_KEYS);
- while ((ch = getopt(argc, argv, "hHRs:r:Fk:c:wodDSCp:i:")) != -1)
- switch (ch) {
- case 'c':
- initConn = 1;
- hostStr = optarg;
- break;
- case 'w':
- waitConn = 1;
- break;
- case 'p':
- portStr = optarg;
- break;
- case 'i':
- stepDownInterval = atof(optarg) * 1e6;
- break;
- case 's':
- initSeed = atoi(optarg);
- myFlags |= SCF_setSeed;
- break;
- case 'r':
- robotEnable = 1;
- robotProg = optarg;
- myFlags |= SCF_usingRobot;
- break;
- case 'F':
- fairRobot = 1;
- myFlags |= SCF_fairRobot;
- break;
- case 'd':
- dropModeEnable = 1;
- break;
- case 'D':
- dropModeEnable = 2;
- break;
- case 'C':
- colorEnable = 0;
- break;
- case 'S':
- standoutEnable = 0;
- break;
- case 'k':
- MapKeys(optarg);
- break;
- case 'H':
- DistInfo();
- exit(0);
- case 'R':
- Rules();
- exit(0);
- case 'h':
- Usage();
- exit(0);
- default:
- Usage();
- exit(1);
- }
- if (optind < argc || (initConn && waitConn)) {
+ {
+ int i;
+ char *userName;
+
+ for (i = 0; i <= MAX_SCREENS; i++)
+ Players[i].score.level = Players[i].spy = 1;
+ if (!(userName = getenv("LOGNAME")) || !userName[0])
+ if (!(userName = getenv("USER")) || !userName[0])
+ userName = "Anonymous";
+ strncpy(Players[0].name, userName, 16); //sizeof(Player.name)
+ Players[0].name[16] = 0;
+ Players[0].boardWidth = 10;
+ Players[0].boardHeight = MAX_BOARD_HEIGHT;
+ Players[0].boardVisible = 20;
+ Players[0].spy = 1;
+ strcpy(Players[0].host, "localhost");
+ }
+
+// if (getopt(argc, argv, "f:") == 'f')
+// ReadConf(optarg);
+// else
+ ReadConf(CONFIG_FILE);
+ while ((ch = getopt_long(argc, argv,
+ "hHRs:r:Fk:c:odDSCap:i:l:", options, NULL)) != -1)
+ HandleOption(ch, optarg);
+ if (optind < argc) {
Usage();
exit(1);
}
if (fairRobot && !robotEnable)
fatal("You can't use the -F option without the -r option");
+// WriteConf();
+
InitUtil();
- if (robotEnable)
- InitRobot(robotProg);
- InitNet();
InitScreens();
- if (initConn || waitConn) {
- MyEvent event;
-
+ if (initConn) {
game = GT_classicTwo;
- if (initConn)
- InitiateConnection(hostStr, portStr);
- else if (waitConn)
- WaitForConnection(portStr);
- {
- netint4 data[2];
- int major;
-
- data[0] = hton4(MAJOR_VERSION);
- data[1] = hton4(PROTOCOL_VERSION);
- SendPacket(0, NP_version, sizeof(data), data);
- if (WaitMyEvent(&event, EM_net) != E_net)
- fatal("Network negotiation failed");
- memcpy(data, event.u.net.data, sizeof(data));
- major = ntoh4(data[0]);
- protocolVersion = ntoh4(data[1]);
- if (event.u.net.type != NP_version || major < MAJOR_VERSION)
- fatal("Your opponent is using an old, incompatible version\n"
- "of Netris. They should get the latest version.");
- if (major > MAJOR_VERSION)
- fatal("Your opponent is using an newer, incompatible version\n"
- "of Netris. Get the latest version.");
- if (protocolVersion > PROTOCOL_VERSION)
- protocolVersion = PROTOCOL_VERSION;
- }
- if (protocolVersion < 3 && stepDownInterval != DEFAULT_INTERVAL)
- fatal("Your opponent's version of Netris predates the -i option.\n"
- "For fairness, you shouldn't use the -i option either.");
- {
- netint4 data[3];
- int len;
- int seed;
-
- if (protocolVersion >= 3)
- len = sizeof(data);
- else
- len = sizeof(netint4[2]);
- if ((myFlags & SCF_setSeed))
- seed = initSeed;
- else
- seed = time(0);
- if (waitConn)
- SRandom(seed);
- data[0] = hton4(myFlags);
- data[1] = hton4(seed);
- data[2] = hton4(stepDownInterval);
- SendPacket(0, NP_startConn, len, data);
- if (WaitMyEvent(&event, EM_net) != E_net ||
- event.u.net.type != NP_startConn)
- fatal("Network negotiation failed");
- memcpy(data, event.u.net.data, len);
- opponentFlags = ntoh4(data[0]);
- seed = ntoh4(data[1]);
- if (initConn) {
- if ((opponentFlags & SCF_setSeed) != (myFlags & SCF_setSeed))
- fatal("If one player sets the random number seed, "
- "both must.");
- if ((myFlags & SCF_setSeed) && seed != initSeed)
- fatal("Both players have set the random number seed, "
- "and they are unequal.");
- if (protocolVersion >= 3 && stepDownInterval != ntoh4(data[2]))
- fatal("Your opponent is using a different step-down "
- "interval (-i).\nYou must both use the same one.");
- SRandom(seed);
- }
- }
- {
- char *userName;
- int len, i;
-
- userName = getenv("LOGNAME");
- if (!userName || !userName[0])
- userName = getenv("USER");
- if (!userName || !userName[0])
- strcpy(userName, "???");
- len = strlen(userName)+1;
- if (len > sizeof(opponentName))
- len = sizeof(opponentName);
- SendPacket(0, NP_userName, len, userName);
- if (WaitMyEvent(&event, EM_net) != E_net ||
- event.u.net.type != NP_userName)
- fatal("Network negotiation failed");
- strncpy(opponentName, event.u.net.data,
- sizeof(opponentName)-1);
- opponentName[sizeof(opponentName)-1] = 0;
- for (i = 0; opponentName[i]; ++i)
- if (!isprint(opponentName[i]))
- opponentName[i] = '?';
- for (i = 0; opponentHost[i]; ++i)
- if (!isprint(opponentHost[i]))
- opponentHost[i] = '?';
- }
- OneGame(0, 1);
- }
+ InitiateConnection(hostStr, portStr);
+ HandShake();
+ OneGame(me);
+ } //client
else {
game = GT_onePlayer;
- OneGame(0, -1);
- }
+ totalPlayers = 0;
+ me = 1;
+ memcpy(&Players[me], &Players[0], sizeof(Player));
+ OneGame(me);
+ } //singleplay
return 0;
}
#define HEADER_SIZE sizeof(netint2[2])
#define HEADER_SIZE3 sizeof(netint4[3])
-static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
-static int sock = -1;
-static EventGenRec netGen = { NULL, 0, FT_read, -1, NetGenFunc, EM_net };
+EventGenRec netGen[MAX_SCREENS] = {
+ { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE3 } };
-static char netBuf[64];
-static int netBufSize, netBufGoal = HEADER_SIZE3;
-static int isServer, lostConn, gotEndConn;
+//static char netBuf[64];
+//static int netBufSize, netBufGoal = HEADER_SIZE3;
-ExtFunc void InitNet(void)
+ExtFunc void make_netGen(void)
{
- AtExit(CloseNet);
-}
+ int i;
-ExtFunc int WaitForConnection(char *portStr)
-{
- struct sockaddr_in addr;
- struct hostent *host;
- int sockListen;
- int addrLen;
- short port;
- int val1;
- struct linger val2;
+ for (i = 1; i <= MAX_SCREENS; i++)
+ memcpy(netGen+i, &netGen[0], sizeof(EventGenRec));
+} //Make_netGen
- if (portStr)
- port = atoi(portStr); /* XXX Error checking */
- else
- port = DEFAULT_PORT;
- memset(&addr, 0, sizeof(addr));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = htonl(INADDR_ANY);
- addr.sin_port = htons(port);
- sockListen = socket(AF_INET, SOCK_STREAM, 0);
- if (sockListen < 0)
- die("socket");
- val1 = 1;
- setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
- (void *)&val1, sizeof(val1));
- if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
- die("bind");
- if (listen(sockListen, 1) < 0)
- die("listen");
-
- // while(1) {
- addrLen = sizeof(addr);
- if ((sock = accept(sockListen, (struct sockaddr *)&addr, &addrLen)) < 0)
- die("accept");
- fprintf(stderr, "Connection: %s\n", inet_ntoa(addr.sin_addr));
- // if (!fork()) {
- close(sockListen);
- val2.l_onoff = 1;
- val2.l_linger = 0;
- setsockopt(sock, SOL_SOCKET, SO_LINGER,
- (void *)&val2, sizeof(val2));
- netGen.fd = sock;
- strcpy(opponentHost, "???");
- if (addr.sin_family == AF_INET) {
- host = gethostbyaddr((void *)&addr.sin_addr,
- sizeof(struct in_addr), AF_INET);
- if (host) {
- strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
- opponentHost[sizeof(opponentHost)-1] = 0;
- }
- }
- AddEventGen(&netGen);
-// close(sock);
- // exit(0);
- // }
-// close(sock);
- // }
- isServer = 1;
- return 0;
-}
ExtFunc int InitiateConnection(char *hostStr, char *portStr)
-{
+{ //connect to host
struct sockaddr_in addr;
struct hostent *host;
short port;
- int mySock;
+// make_netGen();
+ AtExit(CloseNet);
if (portStr)
port = atoi(portStr); /* XXX Error checking */
else
if (!host)
die("gethostbyname");
assert(host->h_addrtype == AF_INET);
- strncpy(opponentHost, host->h_name, sizeof(opponentHost)-1);
- opponentHost[sizeof(opponentHost)-1] = 0;
again:
memset(&addr, 0, sizeof(addr));
addr.sin_family = host->h_addrtype;
memcpy(&addr.sin_addr, host->h_addr, host->h_length);
addr.sin_port = htons(port);
- mySock = socket(AF_INET, SOCK_STREAM, 0);
- if (mySock < 0)
+ if ((netGen[0].fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
die("socket");
- if (connect(mySock, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
+ if (connect(netGen[0].fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
if (errno != ECONNREFUSED)
die("connect");
- close(mySock);
+ close(netGen[0].fd);
sleep(1);
goto again;
}
- netGen.fd = sock = mySock;
- AddEventGen(&netGen);
+ AddEventGen(&netGen[0]);
+ totalPlayers = 0;
return 0;
+} //InitiateConnection
+
+ExtFunc void HandShake(void)
+{ //talk to your host
+ MyEvent event;
+
+ {
+ netint4 versiondata[2];
+ versiondata[0] = hton4(MAJOR_VERSION);
+ versiondata[1] = hton4(PROTOCOL_VERSION);
+ SendPacket(0, NP_hello, sizeof(versiondata), versiondata);
+ }
+
+ do {
+ if (WaitMyEvent(&event, EM_net) == E_net)
+ switch (event.u.net.type) {
+ case NP_hello:
+ {
+ me = event.u.net.uid;
+ memcpy(&Players[me], &Players[0], sizeof(Player));
+ fprintf(stderr, "Accepted (%s) as #%d (%s)\n",
+ event.u.net.data, me, Players[me].name);
+ SendPacket(0, NP_newPlayer,
+ sizeof(Player) - sizeof(Players[me].host) - sizeof(Players[me].spy),
+ &Players[me]);
+ break;
+ }
+ case NP_gamedata:
+ {
+ fprintf(stderr, ": %d\n", event.type);
+ break;
+ }
+ case NP_newPlayer:
+ {
+ totalPlayers++;
+ memcpy(&Players[event.u.net.uid],
+ event.u.net.data, event.u.net.size);
+ fprintf(stderr, "Receiving player #%d (%s)\n",
+ event.u.net.uid, Players[event.u.net.uid].name);
+ break;
+ }
+ case NP_error:
+ {
+ fprintf(stderr, "Rejected by server: %s\n", event.u.net.data);
+ exit(1);
+ }
+ default:
+ break;
+ }
+ else
+ fatal("Hm, the party apparantly ended prematurely.");
+ }
+ while (event.u.net.type != NP_goAhead);
+
+ // send Players[0]
+ // receive seed, initspeed
+ // receive #players
+ // receive Players[*]
+
+ /*
+ {
+ netint4 data[3];
+ int len;
+ int seed;
+
+ if (protocolVersion >= 3)
+ len = sizeof(data);
+ else
+ len = sizeof(netint4[2]);
+ if ((Players[0].flags & SCF_setSeed))
+ seed = Game.seed;
+ else
+ seed = time(0);
+ if (waitConn)
+ SRandom(seed);
+ data[0] = hton4(Players[0].flags);
+ data[1] = hton4(seed);
+ data[2] = hton4(Game.initspeed);
+ SendPackets(0, NP_startConn, len, data);
+ if (WaitMyEvent(&event, EM_net) != E_net ||
+ event.u.net.type != NP_startConn)
+ fatal("Network negotiation failed");
+ memcpy(data, event.u.net.data, len);
+ Players[1].flags = ntoh4(data[0]);
+ seed = ntoh4(data[1]);
+ if (initConn) {
+ if ((Players[0].flags & SCF_setSeed) != (Players[1].flags & SCF_setSeed))
+ fatal("If one player sets the random number seed, "
+ "both must.");
+ if ((Players[0].flags & SCF_setSeed) && seed != Game.seed)
+ fatal("Both players have set the random number seed, "
+ "and they are unequal.");
+ if (protocolVersion >= 3 && Game.initspeed != ntoh4(data[2]))
+ fatal("Your opponent is using a different step-down "
+ "interval (-i).\nYou must both use the same one.");
+ SRandom(seed);
+ }
+ }
+ */
+// SendPackets(0, NP_initData, strlen(Players[0].name) + 1, Players[0].name);
+
+/*
+ if (WaitMyEvent(&event, EM_net) != E_net ||
+ event.u.net.type != NP_userName)
+ fatal("Network negotiation failed");
+ strncpy(Players[1].name, event.u.net.data,
+ sizeof(Players[1].name) - 1);
+ Players[1].name[sizeof(Players[1].name)-1] = 0;
+ for (i = 0; Players[1].name[i]; ++i)
+ if (!isprint(Players[1].name[i]))
+ Players[1].name[i] = '?';
+ for (i = 0; Players[1].host[i]; ++i)
+ if (!isprint(Players[1].host[i]))
+ Players[1].host[i] = '?';
+*/
+} //HandShake
+
+ExtFunc void CheckNetConn(void)
+{ //am I necessary?
}
-static MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
-{
+
+ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
+{ //receive
int result;
short uid, type, size;
- netint4 data[3];
+ netint4 *data = (netint4*)&(gen->buf);
- result = MyRead(sock, netBuf + netBufSize, netBufGoal - netBufSize);
+ result = MyRead(gen->fd, gen->buf + gen->bufSize,
+ gen->bufGoal - gen->bufSize);
if (result < 0) {
- lostConn = 1;
+ close(gen->fd);
+ gen->fd = -1;
return E_lostConn;
}
- netBufSize += result;
- if (netBufSize < netBufGoal)
+ gen->bufSize += result;
+ if (gen->bufSize < gen->bufGoal)
return E_none;
- memcpy(data, netBuf, sizeof(data));
+ // *ugly* memcpy(data, gen->buf, sizeof(data));
uid = ntoh4(data[0]);
type = ntoh4(data[1]);
size = ntoh4(data[2]);
- netBufGoal = size;
- if (netBufSize < netBufGoal)
+ gen->bufGoal = size;
+ if (gen->bufSize < gen->bufGoal)
return E_none;
- netBufSize = 0;
- netBufGoal = HEADER_SIZE3;
+ gen->bufSize = 0;
+ gen->bufGoal = HEADER_SIZE3;
+ event->u.net.sender = gen->player;
+ event->u.net.uid = uid;
event->u.net.type = type;
event->u.net.size = size - HEADER_SIZE3;
- event->u.net.data = netBuf + HEADER_SIZE3;
+ event->u.net.data = gen->buf + HEADER_SIZE3;
if (type == NP_endConn) {
- gotEndConn = 1;
- return E_lostConn;
- }
- else if (type == NP_byeBye) {
- lostConn = 1;
+ fprintf(stderr, "Close connection\n");
return E_lostConn;
}
return E_net;
-}
-
-ExtFunc void CheckNetConn(void)
-{
-}
+} //NetGenFunc
ExtFunc void SendPacket(short uid, NetPacketType type, int size, void *data)
-{
+{ //send shit to server
netint4 header[3];
header[0] = hton4(uid);
header[1] = hton4(type);
header[2] = hton4(size + HEADER_SIZE3);
- if (MyWrite(sock, header, HEADER_SIZE3) != HEADER_SIZE3)
+ if (MyWrite(netGen[0].fd, header, HEADER_SIZE3) != HEADER_SIZE3)
+ die("write (header)");
+ if (size > 0 && data && MyWrite(netGen[0].fd, data, size) != size)
die("write");
- if (size > 0 && data && MyWrite(sock, data, size) != size)
- die("write");
-}
+} //SendPacket
ExtFunc void CloseNet(void)
-{
+{ //kick some connection's ass!
MyEvent event;
- if (sock >= 0) {
- if (!lostConn) {
- SendPacket(0, NP_endConn, 0, NULL);
- if (isServer) {
- while (!lostConn)
- WaitMyEvent(&event, EM_net);
- }
- else {
- while (!gotEndConn)
- WaitMyEvent(&event, EM_net);
- SendPacket(0, NP_byeBye, 0, NULL);
- }
- }
- close(sock);
- sock = -1;
+ if (netGen[0].fd >= 0) {
+ SendPacket(0, NP_endConn, 0, NULL);
+ close(netGen[0].fd);
+ netGen[0].fd = -1;
}
- if (netGen.next)
- RemoveEventGen(&netGen);
-}
+ if (netGen[0].next)
+ RemoveEventGen(&netGen[0]);
+} //CloseNet
/*
* vi: ts=4 ai
--- /dev/null
+### NETRIS 0.5.82 Config file ###
+
+Keys = 4685 2
+Color = 1
+InstaDrop
+Handicap= 1
+ascii = 0
+#spy = 10
+#spy = 20
# define IN(a)
#endif
-#ifndef NULL
-# define NULL ((void *)0)
-#endif
+/*#ifndef NULL
+ # define NULL ((void *)0)
+ #endif*/
#ifdef HAS_SIGPROCMASK
typedef sigset_t MySigSet;
#define hton2(x) htons(x)
#define hton4(x) htonl(x)
-
#define ntoh2(x) ntohs(x)
#define ntoh4(x) ntohl(x)
+/* Protocol versions */
+#define MAJOR_VERSION 1
+#define PROTOCOL_VERSION 4
+#define ROBOT_VERSION 1
+
#define DEFAULT_PORT 9284 /* Very arbitrary */
+#define CONFIG_FILE "netris.conf"
+
//#define DEFAULT_KEYS "hlkj mspf^l"
//#define DEFAULT_KEYS "4685 2spf^l"
#define DEFAULT_KEYS "dcaf b^sp^f^l"
-/* Protocol versions */
-#define MAJOR_VERSION 1
-#define PROTOCOL_VERSION 4
-#define ROBOT_VERSION 1
-
#define MAX_BOARD_WIDTH 32
#define MAX_BOARD_HEIGHT 64
-#define MAX_SCREENS 2
-
-#define DEFAULT_INTERVAL 300000 /* Step-down interval in microseconds */
-
-/* NP_startConn flags */
-#define SCF_usingRobot 000001
-#define SCF_fairRobot 000002
-#define SCF_setSeed 000004
+#define MAX_SCREENS 5
/* Event masks */
#define EM_alarm 000001
#define EM_any 000777
typedef enum _GameType { GT_onePlayer, GT_classicTwo, GT_len } GameType;
-typedef enum _BlockTypeA { BT_none, BT_white, BT_blue, BT_magenta,
- BT_cyan, BT_yellow, BT_green, BT_red,
- BT_wall, BT_len } BlockTypeA;
+typedef enum _BlockTypeA {
+ BT_none, BT_white, BT_blue, BT_magenta, BT_cyan, BT_yellow, BT_green,
+ BT_red, BT_wall, BT_len
+} BlockTypeA;
typedef enum _Dir { D_down, D_right, D_up, D_left } Dir;
typedef enum _Cmd { C_end, C_forw, C_back, C_left, C_right, C_plot } Cmd;
typedef enum _FDType { FT_read, FT_write, FT_except, FT_len } FDType;
-typedef enum _MyEventType { E_none, E_alarm, E_key, E_net,
- E_lostConn, E_robot, E_lostRobot } MyEventType;
-typedef enum _NetPacketType { NP_endConn, NP_giveJunk, NP_newPiece,
- NP_down, NP_left, NP_right,
- NP_rotright, NP_rotleft, NP_drop, NP_clear,
- NP_insertJunk, NP_startConn,
- NP_userName, NP_pause, NP_version,
- NP_byeBye } NetPacketType;
+typedef enum _MyEventType {
+ E_none, E_alarm, E_key, E_net, E_lostConn, E_robot, E_lostRobot
+} MyEventType;
+typedef enum _NetPacketType {
+ NP_endConn, NP_byeBye,
+ NP_error, NP_hello, NP_gamedata, NP_newPlayer, NP_goAhead,
+ NP_pause, NP_giveJunk, NP_newPiece, NP_down, NP_left, NP_right,
+ NP_rotright, NP_rotleft, NP_drop, NP_clear, NP_insertJunk
+} NetPacketType;
typedef signed char BlockType;
union {
char key;
struct {
+ short sender, uid;
NetPacketType type;
int size;
void *data;
int fd;
EventGenFunc func;
int mask;
+ short player;
+ char buf[512];
+ int bufSize, bufGoal;
} EventGenRec;
+extern EventGenRec netGen[MAX_SCREENS];
+
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
typedef struct _Shape {
struct _Shape *rotateTo, *rotateFrom;
typedef int (*ShapeDrawFunc)(int scr, int y, int x,
BlockType type, void *data);
+/* NP_startConn flags */
+#define SCF_usingRobot 000001
+#define SCF_fairRobot 000002
+#define SCF_setSeed 000004
+
+EXT int totalPlayers;
+
+typedef struct _Player {
+ char name[16];
+ int flags;
+ int dropmode;
+ int boardHeight, boardWidth, boardVisible;
+ int curX, curY;
+ Shape *curShape, *nextShape;
+ struct _Score {
+ short level;
+ long score;
+ int drops, lines, adds;
+ } score;
+ char host[256];
+ int spy;
+} Player;
+EXT Player Players[MAX_SCREENS];
+EXT short me;
+
+#define DEFAULT_INTERVAL 1000000 /* Step-down interval in microseconds */
+#define SPEEDINC 1.2
+#define SPEEDMINIMUM 40000
+
+typedef struct __Game {
+ long seed;
+ long initspeed, speed;
+ int standout, color, ascii;
+} _Game;
+EXT _Game Game;
+
EXT GameType game;
-EXT int boardHeight[MAX_SCREENS];
-EXT int boardVisible[MAX_SCREENS], boardWidth[MAX_SCREENS];
-EXT Shape *curShape[MAX_SCREENS], *nextShape[MAX_SCREENS];
-EXT int curY[MAX_SCREENS], curX[MAX_SCREENS];
-EXT char opponentName[16], opponentHost[256];
-EXT int standoutEnable, colorEnable;
EXT int robotEnable, robotVersion, fairRobot;
EXT int protocolVersion;
-EXT long initSeed;
-EXT long stepDownInterval, speed;
-
-EXT int myFlags, opponentFlags;
+EXT int initConn, waitConn;
+EXT char *hostStr, *portStr;
EXT char scratch[1024];
--- /dev/null
+/*
+ * Netris -- A free networked version of T*tris
+ * Copyright (C) 1994,1995,1996 Mark H. Weaver <mhw@netris.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * $Id: game.c,v 1.39 1999/05/16 06:56:27 mhw Exp $
+ */
+
+#define NOEXT
+#include "netris.h"
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <setjmp.h>
+
+#define HEADER_SIZE sizeof(netint4[3])
+#define MAX_CONNECTIONS 3
+
+char *version_string = "0.5.89";
+
+static struct option options[] = {
+ { "wait", 0, 0, 'w' },
+ { "port", 1, 0, 'p' },
+ { "speed", 1, 0, 'i' },
+ { "seed", 1, 0, 's' },
+ { "info", 0, 0, 'H' },
+ { "help", 0, 0, 'h' },
+ { 0, 0, 0, 0 }
+};
+
+static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
+
+ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+
+EventGenRec netGen[MAX_SCREENS] = {
+ { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE } };
+
+static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
+static EventGenRec alarmGen =
+ { &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
+static EventGenRec *nextGen = &alarmGen;
+
+static sigjmp_buf close_env;
+
+ExtFunc volatile void die(char *msg)
+{
+ perror(msg);
+ exit(1);
+} //die
+
+ExtFunc int MyRead(int fd, void *data, int len)
+{
+ int result, left;
+
+ left = len;
+ while (left > 0) {
+ result = read(fd, data, left);
+ if (result > 0) {
+ data = ((char *)data) + result;
+ left -= result;
+ }
+ else if (errno != EINTR)
+ return result;
+ }
+ return len;
+} //MyRead
+
+ExtFunc int MyWrite(int fd, void *data, int len)
+{
+ int result, left;
+
+ left = len;
+ while (left > 0) {
+ result = write(fd, data, left);
+ if (result > 0) {
+ data = ((char *)data) + result;
+ left -= result;
+ }
+ else if (errno != EINTR)
+ return result;
+ }
+ return len;
+} //MyWrite
+
+static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
+{
+ return E_alarm;
+}
+
+ExtFunc void AddEventGen(EventGenRec *gen)
+{
+ assert(gen->next == NULL);
+ assert(nextGen->next != (void*)0xffffffff);
+ gen->next = nextGen->next;
+ nextGen->next = gen;
+} //AddEventGen
+
+ExtFunc void RemoveEventGen(EventGenRec *gen)
+{
+ // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
+ if (gen->next) {
+ while (nextGen->next != gen)
+ nextGen = nextGen->next;
+ nextGen->next = gen->next;
+ gen->next = NULL;
+ }
+} //RemoveEventGen
+
+ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
+{ //poll
+ int i, retry = 0;
+ fd_set fds[FT_len];
+ EventGenRec *gen;
+ int result, anyReady, anySet;
+ struct timeval tv;
+
+ for (;;) {
+ for (i = 0; i < FT_len; ++i)
+ FD_ZERO(&fds[i]);
+ anyReady = anySet = 0;
+ gen = nextGen;
+ do {
+ if (gen->mask & mask) {
+ if (gen->ready)
+ anyReady = 1;
+ if (gen->fd >= 0) {
+ FD_SET(gen->fd, &fds[gen->fdType]);
+ anySet = 1;
+ }
+ }
+ gen = gen->next;
+ } while (gen != nextGen);
+ if (anySet) {
+ tv.tv_sec = 0;
+ tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
+ result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
+ &fds[FT_except], anyReady ? &tv : NULL);
+ }
+ else {
+ if (retry && !anyReady)
+ sleep(1);
+ result = 0;
+ }
+ gen = nextGen;
+ do {
+ if ((gen->mask & mask)
+ && (gen->ready || (result > 0 && gen->fd >= 0
+ && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
+ gen->ready = 0;
+ event->type = gen->func(gen, event);
+ if (event->type != E_none) {
+ nextGen = gen->next;
+ return event->type;
+ }
+ }
+ gen = gen->next;
+ } while (gen != nextGen);
+ retry = 1;
+ }
+} //WaitMyEvent
+
+ExtFunc void ByeClient(int playa)
+{ //client went away
+ fprintf(stderr, "Close connection #%d\n", playa);
+ close(netGen[playa].fd);
+ netGen[playa].fd = -1;
+} //ByeClient
+
+ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
+{ //receive
+ int result;
+ short uid, type, size;
+ netint4 *data = (netint4*)&(gen->buf);
+
+ result = MyRead(gen->fd, gen->buf + gen->bufSize,
+ gen->bufGoal - gen->bufSize);
+ if (result < 0) {
+ ByeClient(gen->player);
+ type = NP_endConn;
+ return E_net;
+ }
+ gen->bufSize += result;
+ if (gen->bufSize < gen->bufGoal)
+ return E_none;
+ // *ugly* memcpy(data, gen->buf, sizeof(data));
+ uid = ntoh4(data[0]);
+ type = ntoh4(data[1]);
+ size = ntoh4(data[2]);
+ gen->bufGoal = size;
+ if (gen->bufSize < gen->bufGoal)
+ return E_none;
+ gen->bufSize = 0;
+ gen->bufGoal = HEADER_SIZE;
+ event->u.net.sender = gen->player;
+ event->u.net.uid = uid;
+ event->u.net.type = type;
+ event->u.net.size = size - HEADER_SIZE;
+ event->u.net.data = gen->buf + HEADER_SIZE;
+ if (type == NP_endConn)
+ ByeClient(gen->player);
+ return E_net;
+} //NetGenFunc
+
+ExtFunc void SendPacketTo(short playa, short uid, NetPacketType type, int size, void *data)
+{ //send to someone
+ netint4 header[3];
+
+ if (netGen[playa].fd >= 0) {
+ header[0] = hton4(uid);
+ header[1] = hton4(type);
+ header[2] = hton4(size + HEADER_SIZE);
+ if (MyWrite(netGen[playa].fd, header, HEADER_SIZE) != HEADER_SIZE)
+ die("write (header)");
+ if (size > 0 && data && MyWrite(netGen[playa].fd, data, size) != size)
+ die("write");
+ }
+} //SendPacketTo
+
+
+ExtFunc void AtExit(void (*handler)(void))
+{
+#ifdef HAS_ON_EXIT
+ on_exit((void *)handler, NULL);
+#else
+ atexit(handler);
+#endif
+}
+
+ExtFunc void SCloseNet(short playa)
+{ //kick some connection's ass!
+ MyEvent event;
+
+ if (netGen[playa].fd >= 0) {
+ SendPacketTo(playa, 0, NP_endConn, 0, NULL);
+ do{} while (WaitMyEvent(&event, EM_net) != E_lostConn);
+ close(netGen[playa].fd);
+ netGen[playa].fd = -1;
+ }
+ if (netGen[playa].next)
+ RemoveEventGen(&netGen[playa]);
+} //SCloseNet
+
+ExtFunc void CloseNets(void)
+{ //nou oogjes dicht en snaveltjes toe
+ int i;
+
+ for (i = 1; i <= totalPlayers; i++)
+ SCloseNet(i);
+} //CloseNets
+
+ExtFunc int WaitForConnection(short port)
+{
+ struct sockaddr_in addr;
+ struct hostent *host;
+ int sockListen;
+ int addrLen;
+ int val1;
+ struct linger val2;
+ int i;
+
+ AtExit(CloseNets);
+ for (i = 1; i < MAX_SCREENS; i++)
+ memcpy(&netGen[i], &netGen[0], sizeof(EventGenRec));
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+ if ((sockListen = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+ die("socket");
+ val1 = 1;
+ setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&val1, sizeof(val1));
+ if (bind(sockListen, (struct sockaddr *)&addr, sizeof(addr)) < 0)
+ die("bind");
+ if (listen(sockListen, 1) < 0)
+ die("listen");
+
+ addrLen = sizeof(addr);
+ for (i = 1; i <= MAX_CONNECTIONS; i++) {
+ if ((netGen[i].fd = accept(sockListen, (struct sockaddr *)&addr, &addrLen)) < 0)
+ die("accept");
+ fprintf(stderr, "Connection: %s\n", inet_ntoa(addr.sin_addr));
+ val2.l_onoff = 1;
+ val2.l_linger = 0;
+ setsockopt(netGen[i].fd, SOL_SOCKET, SO_LINGER, (void *)&val2, sizeof(val2));
+ sprintf(Players[i].host, "%s", inet_ntoa(addr.sin_addr));
+ if (addr.sin_family == AF_INET) {
+ host = gethostbyaddr((void *)&addr.sin_addr,
+ sizeof(struct in_addr), AF_INET);
+ if (host) {
+ strncpy(Players[i].host, host->h_name, sizeof(Players[i].host) - 1);
+ Players[i].host[sizeof(Players[i].host) - 1] = 0;
+ }
+ }
+ AddEventGen(&netGen[i]);
+ netGen[i].player = i;
+ totalPlayers++;
+ {
+ MyEvent event;
+
+ do {} while ((WaitMyEvent(&event, EM_net) != E_net) ||
+ (event.u.net.sender != i));
+ if (event.u.net.type != NP_hello) ByeClient(i);
+ else {
+ netint4 versiondata[2];
+ char data[255];
+ int major;
+ memcpy(versiondata, event.u.net.data, sizeof(versiondata));
+ major = ntoh4(versiondata[0]);
+ protocolVersion = ntoh4(versiondata[1]);
+ if (major != MAJOR_VERSION || protocolVersion != PROTOCOL_VERSION) {
+ snprintf(data, sizeof(data), "Version mismatch: received %d.%d",
+ major, protocolVersion);
+ fprintf(stderr, "Byebye client #%d (%s)\n",
+ event.u.net.sender, data);
+ SendPacketTo(event.u.net.sender, 0, NP_error, strlen(data)+1, data);
+ SCloseNet(event.u.net.sender);
+ } //version mismatch
+ fprintf(stderr, "Accepted #%d\n", event.u.net.sender);
+ } //NP_hello
+ }
+ }
+ close(sockListen);
+ return 0;
+} //WaitForConnection
+
+ExtFunc int StartServer(char *portStr)
+{
+ MyEvent event;
+ char serverdata[255];
+ int playercount;
+ int i;
+
+ {
+ short port;
+
+ if (portStr)
+ port = atoi(portStr); /* XXX Error checking */
+ else
+ port = DEFAULT_PORT;
+ WaitForConnection(port);
+ }
+
+ playercount = MAX_CONNECTIONS;
+
+ for (i = 1; i <= playercount; i++) {
+ sprintf(serverdata, "Netris server %s", version_string);
+ SendPacketTo(i, i, NP_hello, strlen(serverdata)+1, serverdata);
+ }
+
+ while(1) {
+ if (WaitMyEvent(&event, EM_net) == E_net) {
+// fprintf(stderr, "in %d: %d\n",
+// netGen[event.u.net.sender].fd, event.u.net.type);
+ switch(event.u.net.type) {
+ case NP_endConn:
+ { //client went away :(
+ //tell the others! :)
+ break;
+ } //NP_endConn
+ case NP_hello:
+ break;
+ case NP_newPlayer:
+ { //receive player details and return other players
+ memcpy(&Players[event.u.net.sender],
+ event.u.net.data, event.u.net.size);
+ fprintf(stderr, "player %d: %s <%s>\n", event.u.net.sender,
+ event.u.net.data, //Players[event.u.net.sender].name
+ Players[event.u.net.sender].host);
+ for (i = 1; i <= totalPlayers; i++)
+ if (i != event.u.net.sender)
+ SendPacketTo(i, event.u.net.sender, event.u.net.type,
+ sizeof(Player) - sizeof(Players[0].spy),
+ &Players[event.u.net.sender]);
+ if (--playercount == 0) {
+ fprintf(stderr, "Starting game\n");
+ for (i = 1; i <= totalPlayers; i++)
+ SendPacketTo(i, 0, NP_goAhead, 0, NULL);
+ playercount++;
+ } //give go ahead
+ break;
+ } //NP_playerdata
+ default:
+ { //relay data to all players
+ // if (event.u.net.type >= NP_pause)
+ for (i = 1; i <= totalPlayers; i++)
+ if (i != event.u.net.sender)
+ SendPacketTo(i, event.u.net.sender, event.u.net.type,
+ event.u.net.size, event.u.net.data);
+ break;
+ }
+ } //E_net
+ }
+ } //loop
+} //StartServer
+
+
+ExtFunc void Header(void)
+{
+ fprintf(stderr,
+ "NETRIS Server %s\t(c) 2002 Shiar <shiar@shiar.org>\n\n",
+ version_string);
+} //Header
+
+ExtFunc void Usage(void)
+{
+ Header();
+ fprintf(stderr,
+ "Usage: netris <options>\n"
+ "\n"
+ " -h, --help\t\tPrint this usage information\n"
+ " -H, --info\t\tShow distribution and warranty information\n"
+ "\n"
+ " -p, --port <port>\tSet port number (default is %d)\n"
+ "\n"
+ " -s, --seed <seed>\tStart with given random seed\n"
+ " -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
+ "\n", DEFAULT_PORT);
+}
+
+ExtFunc void DistInfo(void)
+{
+ Header();
+ fprintf(stderr,
+ "This program is free software; you can redistribute it and/or modify\n"
+ "it under the terms of the GNU General Public License as published by\n"
+ "the Free Software Foundation; either version 2 of the License, or\n"
+ "(at your option) any later version.\n"
+ "\n"
+ "This program is distributed in the hope that it will be useful,\n"
+ "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+ "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
+ "GNU General Public License for more details.\n"
+ "\n"
+ "You should have received a copy of the GNU General Public License\n"
+ "along with this program; if not, write to the Free Software\n"
+ "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
+ "\n");
+} //DistInfo
+
+ExtFunc void WriteConf(void)
+{
+ FILE *file_out;
+
+ file_out = fopen(CONFIG_FILE, "w");
+ if (file_out == NULL) {
+ perror("Error writing config file");
+ exit(1);
+ }
+
+ fprintf(file_out, "### NETRIS %s Config file ###\n\n", version_string);
+
+ fclose(file_out);
+ fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
+} //WriteConf
+
+ExtFunc void HandleOption(char tag, char *value)
+{
+ switch (tag) {
+ case 'p': //port
+ portStr = value; break;
+ case 'i': //speed (of level 1)
+ Game.initspeed = atof(value) * 1e6;
+ break;
+ case 's': //seed
+ Game.seed = atoi(value);
+ Players[0].flags |= SCF_setSeed;
+ break;
+ case 'H': //info
+ DistInfo(); exit(0);
+ case 'h': //help
+ Usage(); exit(0);
+ default:
+ break;
+ }
+} //HandleParam
+
+ExtFunc void ReadConf(char *filename)
+{
+ FILE *file_in;
+ char buf[513];
+ int i;
+ char *ch;
+ char tag[81], value[81];
+
+ file_in = fopen(filename, "r");
+ if (file_in) {
+ while (fgets(buf, 512, file_in) != NULL) {
+ if ((ch = strchr(buf, '#')))
+ *ch = '\0'; // truncate string from # char
+ for (i = strlen(buf)-1; i >= 0; i--)
+ if (buf[i] == ' ' || buf[i] == '\n' || buf[i] == '\t' || buf[i] == 13)
+ buf[i] = '\0';
+ else break;
+
+ sscanf(buf, "%80[^= \t] = %80[^\n]", tag, value);
+ for (i = 0; options[i].name; i++){
+ if (!strcasecmp(options[i].name, tag)) {
+ HandleOption(options[i].val, value);
+ break;
+ }
+ }
+ }
+ fclose(file_in);
+ } //read file
+ else {
+ fprintf(stderr, "Unable to open config file %s.\n", filename);
+ } //defaults
+
+} //ReadConf
+
+ExtFunc void CatchInt(int sig)
+{
+ siglongjmp(close_env, 1);
+}
+
+ExtFunc int main(int argc, char **argv)
+{
+ char ch;
+
+ if (sigsetjmp(close_env, 1)) exit(0);
+ signal(SIGINT, CatchInt);
+ Game.standout = Game.color = 1;
+ Game.initspeed = DEFAULT_INTERVAL;
+
+// if (getopt(argc, argv, "f:") == 'f')
+// ReadConf(optarg);
+// else
+ ReadConf(CONFIG_FILE);
+ while ((ch = getopt_long(argc, argv,
+ "hHp:i:s:", options, NULL)) != -1)
+ HandleOption(ch, optarg);
+ if (optind < argc) {
+ Usage();
+ exit(1);
+ }
+// WriteConf();
+
+ Header();
+ StartServer(portStr);
+ return 0;
+}
+
+/*
+ * vi: ts=4 ai
+ * vim: noai si
+ */
}
ExtFunc int ShapeIterate(Shape *s, int scr, int y, int x, int falling,
-ExtFunc ShapeDrawFunc func, void *data)
+ExtFunc ShapeDrawFunc func, void *data)
{
int i, mirror, result;
Dir dir;
}
if (pieceState == 1) { /* Decided */
if (memcmp(piece, pieceDest, sizeof(piece))) {
- WriteLine("Rotate %d\n", pieceCount);
+ WriteLine("RotRight %d\n", pieceCount);
pieceState = 2;
}
else if (pieceLeft != leftDest) {
#include <sys/time.h>
#include <netdb.h>
#include <errno.h>
+#include <setjmp.h>
static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
{ &alarmGen, 0, FT_read, -1, AlarmGenFunc, EM_alarm };
static EventGenRec *nextGen = &alarmGen;
-static myRandSeed = 1;
+static sigjmp_buf close_env;
-static struct timeval baseTimeval;
+static int myRandSeed = 1;
-ExtFunc void InitUtil(void)
-{
- if (initSeed)
- SRandom(initSeed);
- else
- SRandom(time(0));
- signal(SIGINT, CatchInt);
- ResetBaseTime();
-}
-
-ExtFunc void ResetBaseTime(void)
-{
- gettimeofday(&baseTimeval, NULL);
-}
+static long baseTimeval;
ExtFunc void AtExit(void (*handler)(void))
{
#endif
}
+///////////// HELP MESSAGES /////////////
+
+ExtFunc void Header(void)
+{
+ fprintf(stderr,
+ "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
+ " \t(c) 2002 Shiar <shiar@shiar.org>\n\n",
+ version_string);
+} //Header
+
ExtFunc void Usage(void)
{
+ Header();
fprintf(stderr,
- "Netris version %s (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
"Usage: netris <options>\n"
- " -h Print usage information\n"
- " -w Wait for connection\n"
- " -c <host> Initiate connection\n"
- " -p <port> Set port number (default is %d)\n"
- " -k <keys> Remap keys. The argument is a prefix of the string\n"
- " containing the keys in order: left, rotate, right, drop,\n"
- " down-faster, toggle-spying, pause, faster, redraw.\n"
- " \"^\" prefixes controls. (default is \"%s\")\n"
- " -i <sec> Set the step-down interval, in seconds\n"
- " -r <robot> Execute <robot> (a command) as a robot controlling\n"
- " the game instead of the keyboard\n"
- " -F Use fair robot interface\n"
- " -s <seed> Start with given random seed\n"
- " -d Drops go into drop mode\n"
- " This means that sliding off a cliff after a drop causes\n"
- " another drop automatically\n"
- " -D Instant drop\n"
- " -S Disable inverse/bold/color for slow terminals\n"
- " -C Disable color\n"
- " -H Show distribution and warranty information\n"
- " -R Show rules\n",
- version_string, DEFAULT_PORT, DEFAULT_KEYS);
+ "\n"
+ " -h, --help\t\tPrint this usage information\n"
+ " -H, --info\t\tShow distribution and warranty information\n"
+ " -R, --rules\t\tShow game rules\n"
+ "\n"
+ " -S, --slowterm\tDisable inverse/bold/color for slow terminals\n"
+ " -a, --ascii\t\tUse ascii characters\n"
+ " -C, --color=0\t\tDisable color\n"
+ "\n"
+ " -w, --wait\t\tWait for connection\n"
+ " -c, --connect <host>\tInitiate connection\n"
+ " -p, --port <port>\tSet port number (default is %d)\n"
+ "\n"
+ " -s, --seed <seed>\tStart with given random seed\n"
+ " -i, --speed <sec>\tSet the initial step-down interval, in seconds\n"
+ " -l, --level <lvl>\tBegin at a higher level (can be used as handicap)\n"
+ " -k, --keys <keys>\tRemap keys (default is \"%s\" for cursors)\n"
+ " -d, --dropmode\tDrops go into drop mode\n"
+ " -D, --instadrop\tInstant drop\n"
+ "\n"
+ " -r, --robot <cmd>\tExecute program to control the game instead of keyboard\n"
+ " -F, --fair-robot\tUse fair robot interface\n"
+ "\n", DEFAULT_PORT, DEFAULT_KEYS);
}
ExtFunc void DistInfo(void)
{
+ Header();
fprintf(stderr,
- "Netris version %s (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
- "\n"
"This program is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
"the Free Software Foundation; either version 2 of the License, or\n"
"\n"
"You should have received a copy of the GNU General Public License\n"
"along with this program; if not, write to the Free Software\n"
- "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n",
- version_string);
-}
+ "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
+ "\n");
+} //DistInfo
ExtFunc void Rules(void)
{
+ Header();
fprintf(stderr,
- "Netris version %s rules\n"
+ "One player mode\n"
+ "---------------\n"
+ "Good old Tetris. Scoring is like on the GameBoy version (so try to\n"
+ "remove as many lines at once as you can). After removing ten lines\n"
+ "you go to the next level, which will be faster thus making the game\n"
+ "harder to play.\n"
"\n"
"Two player mode\n"
"---------------\n"
"It's just like normal T*tris except that when you clear more than\n"
- "one row with a single piece, the other player's board is moved up\n"
- "and junk rows are added to the bottom. If you clear 2, 3 or 4\n"
- "rows, 1, 2 or 4 junk rows are added to your opponent's board,\n"
- "respectively. The junk rows have exactly one empty column.\n"
- "For each group of junk rows given, the empty columns will line\n"
- "up. This is intentional.\n"
+ "one row with a single piece, the other player receives penalty lines\n"
+ "For clearing 2, 3 or 4 rows, respectively 1, 2 or 4 junk rows will\n"
+ "be added to the bottom of your opponent's board respectively.\n"
+ "The junk rows have exactly one empty column, which will line up for\n"
+ "multiple rows.\n"
"\n"
"The longest surviving player wins the game.\n"
- "\n"
- "One player mode\n"
- "---------------\n"
- "This mode is currently very boring, because there's no scoring\n"
- "and it never gets any faster. This will be rectified at some point.\n"
- "I'm not very motivated to do it right now because I'm sick of one\n"
- "player T*tris. For now, use the \"f\" key (by default) to make the\n"
- "game go faster. Speedups cannot be reversed for the remainder of\n"
- "the game.\n",
- version_string);
-}
+ "\n");
+} //Rules
+
+///////////// RANDOM /////////////
+
+ExtFunc void InitUtil(void)
+{
+ if (Game.seed)
+ SRandom(Game.seed);
+ else
+ SRandom(time(0));
+ if (sigsetjmp(close_env, 1)) exit(0);
+ signal(SIGINT, CatchInt);
+ ResetBaseTime();
+} //InitUtil
/*
* My really crappy random number generator follows
*/
ExtFunc void SRandom(int seed)
{
- initSeed = seed;
+ Game.seed = seed;
myRandSeed = seed % 31751 + 1;
-}
+} //SRandom
ExtFunc int Random(int min, int max1)
{
myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
return myRandSeed % (max1 - min) + min;
-}
+} //Random
+
+///////////// I/O /////////////
ExtFunc int MyRead(int fd, void *data, int len)
{
return result;
}
return len;
-}
+} //MyRead
ExtFunc int MyWrite(int fd, void *data, int len)
{
return result;
}
return len;
-}
+} //MyWrite
+
+///////////// TIME /////////////
ExtFunc void NormalizeTime(struct timeval *tv)
{
ExtFunc void CatchInt(int sig)
{
- exit(0);
+ siglongjmp(close_env, 1);
}
ExtFunc void CatchAlarm(int sig)
return E_alarm;
}
-ExtFunc long CurTimeval(void)
+ExtFunc void SetTimeval(struct timeval *tv, long usec)
+{
+ tv->tv_sec = usec / 1000000;
+ tv->tv_usec = usec % 1000000;
+} //SetTimeval
+
+ExtFunc long GetTimeval(struct timeval *tv)
+{
+ return tv->tv_sec * 1000000 + tv->tv_usec;
+} //GetTimeval
+
+ExtFunc long AbsTimeval(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
- tv.tv_sec -= baseTimeval.tv_sec;
- tv.tv_usec -= baseTimeval.tv_usec;
return GetTimeval(&tv);
-}
+} //CurTimeval
-ExtFunc void SetTimeval(struct timeval *tv, long usec)
+ExtFunc void ResetBaseTime(void)
{
- tv->tv_sec = usec / 1000000;
- tv->tv_usec = usec % 1000000;
-}
+ baseTimeval = AbsTimeval();
+} //ResetBaseTime
-ExtFunc long GetTimeval(struct timeval *tv)
+ExtFunc void PauseTime(void)
{
- return tv->tv_sec * 1000000 + tv->tv_usec;
-}
+ baseTimeval -= AbsTimeval();
+} //PauseTime
+
+ExtFunc void ResumeTime(void)
+{
+ baseTimeval += AbsTimeval();
+} //ResumeTime
+
+ExtFunc long CurTimeval(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return GetTimeval(&tv) - baseTimeval;
+} //CurTimeval
static long SetITimer1(long interval, long value)
{
return old;
}
+///////////// ... /////////////
+
ExtFunc volatile void die(char *msg)
{
perror(msg);
#endif
}
+///////////// EVENTS /////////////
+
ExtFunc void AddEventGen(EventGenRec *gen)
{
assert(gen->next == NULL);
gen->next = nextGen->next;
nextGen->next = gen;
-}
+} //AddEventGen
ExtFunc void RemoveEventGen(EventGenRec *gen)
{
- /* assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
+ // assert(gen->next != NULL); /* Be more forgiving, for SIGINTs */
if (gen->next) {
while (nextGen->next != gen)
nextGen = nextGen->next;
nextGen->next = gen->next;
gen->next = NULL;
}
-}
+} //RemoveEventGen
ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
-{
+{ //poll
int i, retry = 0;
fd_set fds[FT_len];
EventGenRec *gen;
int result, anyReady, anySet;
struct timeval tv;
- /* XXX In certain circumstances, this routine does polling */
for (;;) {
for (i = 0; i < FT_len; ++i)
FD_ZERO(&fds[i]);
} while (gen != nextGen);
retry = 1;
}
-}
+} //WaitMyEvent
/*
* vi: ts=4 ai