+ [][] [] [][][] [][][][] [][][] [][] [] [][][]
+ [][] [] [] [] [] [] [][] [][] []
+ [] [] [] [][][] []
+ [] [][] [] [][][][] [][] [] [] [][][][]
+ [] [] [] [] [] [] []
+ [] [][] [] [][] [] [][] [] [] [][]
+ [] [][] [][][] [] [] [] [] [][][] []
+
---- done: -------------------------------------------------------------------
-- v0.6 ---------- 31.VII.02
-- v0.6.83 -------
+ * conffile can have comments (#) and tabs instead of spaces
* level up every 10 lines (speed x1.2)
-- v0.6.84 -------
* fix multiplay g/o (close connection at g/o or server signal)
* spy=n0 in configfile disables spying for player n
+ -- v0.6.810 ------
----- near-future: ------------------------------------------------------------
+ * seed and initspeed given by server
+ * exits when only 1 player left (or 0 in singleplayer)
+ * version_string in netris.h
+ * fixed pause for multiple players
+ * paused message displayed over pausing player's field
+ * all players start paused in multiplayer
+ * your own hostname isn't displayed
- * 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)
+ -- v0.7 ---------- 10.VIII.02
+
+ * display game over over dead player's field
+ * number of connections can be set with server -c
+ * exiting client automatically goes game over
+ * dead players can't pause the game
+ * -t sets team. players in same team don't get junklines from each other
+ * client no longer displays seed
+ * doesn't display fields which don't fit on screen automatically
+ * quit key (q by default)
+
+
+---- near-future: ------------------------------------------------------------
---- asap: -------------------------------------------------------------------
* fix -f
+ * fix bot
+ * server continuously acceping new connections, and immediate handshake
* midgame join option
- * optional enemy field resize
+ * optional smaller enemy fields
* multiplayer stats
- * pause message over player's field
---- distant future: ---------------------------------------------------------
* special blocks
* tetrinet compatible?
+ * remove bot delay (make it humanplayer-like)
+ * new+better bot?
------------------------------------------------------------------------------
rm -f test.c test.o a.out
ORIG_SOURCES="game- curses- shapes- board- util- inet- robot-"
-GEN_SOURCES="version-"
-SOURCES="$ORIG_SOURCES $GEN_SOURCES"
+SOURCES="$ORIG_SOURCES"
SRCS="`echo $SOURCES | sed -e s/-/.c/g`"
OBJS="`echo $SOURCES | sed -e s/-/.o/g`"
@echo "Run ./Configure now"
@false
-version.c: VERSION
- @echo "Creating version.c"
- @sed -e 's/^\(.*\)$$/char *version_string = "\1";/' VERSION > $@
-
proto.h: $(SRCS)
@touch $@
@mv $@ $@.old
tar -cvzof $$dir.tar.gz $$dir
clean:
- rm -f proto.h proto.chg $(PROG) $(OBJS) version.c test.c a.out sr sr.o server server.o
+ rm -f proto.h proto.chg $(PROG) $(OBJS) test.c a.out sr sr.o server server.o
cleandir: clean
rm -f .depend Makefile config.h
[3] If I drop a piece and then slide it off a cliff, shouldn't
it automatically drop again?
- Try the -D option.
+ Try the -d option.
[4] When I try to play a networked game, it just hangs.
#endif
#ifdef HAVE_NCURSES
-static struct
-{
+static struct {
BlockType type;
short color;
-} myColorTable[] =
-{
+} myColorTable[] = {
{ BT_white, COLOR_WHITE },
{ BT_blue, COLOR_BLUE },
{ BT_magenta, COLOR_MAGENTA },
{ BT_yellow, COLOR_YELLOW },
{ BT_green, COLOR_GREEN },
{ BT_red, COLOR_RED },
- { BT_none, 0 }
+ { BT_none, 0 }
};
#endif
}
statusYPos = 22;
statusXPos = 0;
-}
+} //InitScreens
ExtFunc void CleanupScreens(void)
{
RemoveEventGen(&keyGen);
endwin();
OutputTermStr(term_ve, 1);
-}
+} //CleanupScreens
ExtFunc void GetTermcapInfo(void)
{
}
if (!term_vi || !term_ve)
term_vi = term_ve = NULL;
-}
+} //GetTermcapInfo
ExtFunc void OutputTermStr(char *str, int flush)
{
if (str) {
fputs(str, stdout);
- if (flush)
- fflush(stdout);
+ if (flush) fflush(stdout);
}
-}
+} //OutputTermStr
ExtFunc void DrawField(int scr)
-{
+{ //drow field for player scr
{
int y, x;
+ getmaxyx(stdscr, y, x);
+ if (x < boardXPos[scr] + 2 * Players[scr].boardWidth + 1) {
+ Players[scr].spy = 0;
+ return;
+ }
+
for (y = Players[scr].boardVisible - 1; y >= 0; --y) {
mvaddch(boardYPos[scr] - y, boardXPos[scr] - 1,
Game.ascii ? '|' : ACS_VLINE); //left
{
char userstr[300];
- sprintf(userstr, "%s <%s>", Players[scr].name, Players[scr].host);
+ if (Players[scr].host && Players[scr].host[0])
+ sprintf(userstr, "%s <%s>", Players[scr].name, Players[scr].host);
+ else sprintf(userstr, "%s", Players[scr].name);
userstr[20 - 7*((Players[scr].flags & SCF_usingRobot) != 0)
- 5*((Players[scr].flags & SCF_fairRobot) != 0)] = 0;
mvaddstr(1, boardXPos[scr], userstr);
? "(fair robot)" : "(robot)");
}
} //display playername/host
+
+ ShowPause(scr);
} //DrawScreen
ExtFunc void InitFields()
-{
+{ //place fields for all players
int scr, prevscr;
+ statusXPos = 2 * Players[me].boardWidth + 3;
boardXPos[me] = 1;
boardYPos[me] = 22;
prevscr = me;
boardYPos[scr] = 22;
prevscr = scr;
}
- statusXPos = 2 * Players[me].boardWidth + 3;
} //InitScreen
ExtFunc void CleanupScreen(int scr)
addstr(type ? "[]" : "$$");
standend();
}
-}
+} //PlotBlock1
ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
{
if (y >= 0 && y < Players[scr].boardVisible &&
x >= 0 && x < Players[scr].boardWidth)
PlotBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
-}
+} //PlotBlock
ExtFunc void PlotUnderline(int scr, int x, int flag)
{
addch(flag ? ACS_BTEE : ACS_HLINE);
addch(flag ? ACS_BTEE : ACS_HLINE);
}
-}
-
-ExtFunc void ShowDisplayInfo(void)
-{
- 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();
- }
-}
+} //PlotUnderline
ExtFunc void ShowScore(int scr, struct _Score score)
-{
+{ //show score stuff
float timer;
move(6, statusXPos); addstr("Next: ");
else addstr(" ");
printw(" apm:%5.1f", score.adds * 60 / timer);
}
-}
+} //ShowScore
+
+ExtFunc void FieldMessage(int playa, char *message)
+{ //put a message over playa's field
+ if (!Players[playa].spy) return;
+ if (message) {
+ char s[MAX_BOARD_WIDTH+1];
+ memset(s, ' ', MAX_BOARD_WIDTH);
+ memcpy(&s[Players[playa].boardWidth - strlen(message) / 2],
+ message, strlen(message));
+ s[Players[playa].boardWidth * 2] = 0;
+ if (Game.standout) standout();
+ mvprintw(boardYPos[playa] - Players[playa].boardVisible / 2,
+ boardXPos[playa], "%s", s);
+ standend();
+ } //display
+ else {
+ int x, y;
+ y = Players[playa].boardVisible / 2;
+ for (x = 0; x <= Players[playa].boardWidth; x++)
+ PlotBlock(playa, y, x, GetBlock(playa, y, x));
+ } //restore field
+} //FieldMessage
+
+ExtFunc void ShowPause(int playa)
+{ //put paused over player's field
+ if (Players[playa].flags & SCF_paused)
+ FieldMessage(playa, "P A U S E D");
+ else FieldMessage(playa, NULL);
+} //ShowPause
-ExtFunc void ShowPause(int pausedByMe, int pausedByThem)
-{
- move(statusYPos - 3, statusXPos);
- if (pausedByThem)
- addstr("Game paused by opponent");
- else
- addstr(" ");
- move(statusYPos - 2, statusXPos);
- if (pausedByMe)
- addstr("Game paused by you");
- else
- addstr(" ");
-}
ExtFunc void Message(char *s)
{
// move(statusYPos - 20 + line, statusXPos);
move(statusYPos + 2 + line, 1);
clrtoeol();
-}
+} //Message
ExtFunc void ShowTime(void)
-{
+{ //display timer
move(statusYPos, statusXPos);
printw("Timer: %.0f ", CurTimeval() / 1e6);
move(boardYPos[0] + 1, boardXPos[0] + 2 * Players[0].boardWidth + 1);
// refresh();
-}
+} //ShowTime
ExtFunc void ScheduleFullRedraw(void)
{
touchwin(stdscr);
-}
+} //ScheduleFullRedraw
static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
-{
+{ //read keypresses
if (MyRead(gen->fd, &event->u.key, 1))
return E_key;
else
return E_none;
-}
+} //KeyGenFunc
/*
* vi: ts=4 ai
{ "ascii", 2, 0, 'a' },
{ "connect", 1, 0, 'c' },
{ "port", 1, 0, 'p' },
- { "speed", 1, 0, 'i' },
{ "level", 1, 0, 'l' },
+ { "team", 1, 0, 't' },
{ "spy", 1, 0, 1 },
- { "seed", 1, 0, 's' },
{ "robot", 1, 0, 'r' },
{ "fair-robot", 0, 0, 'F' },
{ "dropmode", 2, 0, 'd' },
};
enum { KT_left, KT_right, KT_rotright, KT_rotleft, KT_drop, KT_down,
- KT_toggleSpy, KT_pause, KT_faster, KT_redraw, KT_numKeys };
+ KT_faster, KT_pause, KT_redraw, KT_quit, KT_numKeys };
static char *keyNames[KT_numKeys+1] = {
"Left", "Right", "RotRight", "RotLeft", "Drop", "Down",
- "ToggleSpy", "Pause", "Faster", "Redraw", NULL };
+ "Faster", "Pause", "Redraw", "Quit", NULL };
static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
static char keyTable[KT_numKeys+1];
+static char *hostStr;
+static int paused = 0;
+
ExtFunc void MapKeys(char *newKeys)
{
hostStr = value;
break;
case 'p': //port
- portStr = value; break;
+ port = atoi(value);
+ break;
case 'i': //speed (of level 1)
Game.initspeed = atof(value) * 1e6;
break;
if (Players[0].score.level > 15)
Players[0].score.level = 15;
break;
+ case 't': //team
+ Players[0].team = atoi(value);
+ break;
case 1: //spy
{
int i;
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;
return 1;
}
+ExtFunc void checkPaused(void)
+{ //check whether anyone paused the game
+ int i;
+
+ paused = 0;
+ for (i = 1; i <= totalPlayers; i++)
+ if (Players[i].alive)
+ paused |= Players[i].flags & SCF_paused;
+} //checkPaused
+
ExtFunc void OneGame(int scr)
{
MyEvent event;
int linesCleared, changed = 0;
int spied = 0, dropMode = 0;
- int oldPaused = 0, paused = 0, pausedByMe = 0, pausedByThem = 0;
+ int oldPaused = 0;
long pauseTimeLeft;
int pieceCount = 0;
int key;
char *p, *cmd;
+ int playercount;
int linevalues[4] = { 40, 100, 400, 1200 }; //= 50*lines! - 10*(lines==1)
int i;
Game.speed = SPEEDMINIMUM;
ResetBaseTime();
InitFields();
- for (i = 1; i <= totalPlayers + 1; i++)
+ for (i = 1; i <= totalPlayers; i++)
if (Players[i].spy) DrawField(i);
- if (totalPlayers > 0) {
+ if (totalPlayers > 1) {
spied = 1;
}
- ShowDisplayInfo();
SetITimer(Game.speed, Game.speed);
if (robotEnable) {
RobotCmd(0, "GameType %s\n", gameNames[game]);
RobotCmd(0, "BoardSize 0 %d %d\n",
Players[scr].boardVisible, Players[scr].boardWidth);
- for (i = 1; i <= totalPlayers + 1; i++) {
+ for (i = 1; i <= totalPlayers; i++) {
RobotCmd(0, "BoardSize %d %d %d\n",
i, Players[i].boardVisible, Players[i].boardWidth);
RobotCmd(0, "Opponent %d %s %s\n",
RobotTimeStamp();
}
Players[scr].nextShape = ChooseOption(stdOptions);
- while (StartNewPiece(scr, ChooseOption(stdOptions))) {
- ShowScore(scr, Players[scr].score);
- if (robotEnable && !fairRobot)
- RobotCmd(1, "NewPiece %d\n", ++pieceCount);
- if (spied) {
- short shapeNum;
- netint2 data[1];
-
- shapeNum = ShapeToNetNum(Players[scr].curShape);
- data[0] = hton2(shapeNum);
- SendPacket(scr, NP_newPiece, sizeof(data), data);
+ while (1) {
+ if (Players[scr].alive) {
+ if (!StartNewPiece(scr, ChooseOption(stdOptions))) {
+ netint4 data[4];
+ Players[scr].alive = 0;
+ FieldMessage(scr, "G A M E O V E R");
+ changed = 1;
+ if (game == GT_classicTwo)
+ SendPacket(scr, NP_argghhh,
+ sizeof(Players[0].alive), &Players[scr].alive);
+ } //die
+ else {
+ ShowScore(scr, Players[scr].score);
+ if (robotEnable && !fairRobot)
+ RobotCmd(1, "NewPiece %d\n", ++pieceCount);
+ if (spied) {
+ short shapeNum;
+ netint2 data[1];
+
+ shapeNum = ShapeToNetNum(Players[scr].curShape);
+ data[0] = hton2(shapeNum);
+ SendPacket(scr, NP_newPiece, sizeof(data), data);
+ } //send new piece
+ }
}
for (;;) {
- changed = RefreshBoard(scr) || changed;
- for (i = 1; i <= totalPlayers+1; i++) if (Players[i].spy && i != me)
- changed = RefreshBoard(i) || changed;
+ for (i = 1; i <= totalPlayers; i++) if (Players[i].spy)
+ changed |= RefreshBoard(i);
if (changed) {
if (!paused) ShowTime();
refresh();
changed = 0;
}
+ playercount = 0;
+ for (i = 1; i <= totalPlayers; i++)
+ if (Players[i].alive) playercount++;
+ if (playercount < game + 1) goto gameOver;
CheckNetConn();
switch (WaitMyEvent(&event, EM_any)) {
case E_alarm:
- if (!MovePiece(scr, -1, 0))
- goto nextPiece;
- else if (spied)
- SendPacket(scr, NP_down, 0, NULL);
+ if (Players[scr].alive)
+ if (!MovePiece(scr, -1, 0))
+ goto nextPiece;
+ else if (spied)
+ SendPacket(scr, NP_down, 0, NULL);
break;
case E_key:
p = strchr(keyTable, tolower(event.u.key));
(int)(unsigned char)event.u.key,
p ? keyNames[key] : "?");
break;
- }
- if (!p)
- break;
+ } //let robot handle keypress
+ if (!p) break;
keyEvent:
- if (paused && (key != KT_pause) && (key != KT_redraw))
- break;
+ if (!Players[scr].alive && key != KT_quit) break;
+ if (paused && key < KT_pause) break;
switch(key) {
case KT_left:
if (MovePiece(scr, 0, -1) && spied)
dropMode = Players[scr].dropmode;
break;
case KT_pause:
- pausedByMe = !pausedByMe;
- if (game == GT_classicTwo) {
- netint2 data[1];
-
- data[0] = hton2(pausedByMe);
- SendPacket(scr, NP_pause, sizeof(data), data);
- }
- paused = pausedByMe || pausedByThem;
- if (robotEnable)
- RobotCmd(1, "Pause %d %d\n", pausedByMe,
- pausedByThem);
- ShowPause(pausedByMe, pausedByThem);
+ Players[scr].flags ^= SCF_paused;
+ checkPaused();
+ if (game == GT_classicTwo)
+ SendPacket(scr, NP_pause, 0, NULL);
+ if (robotEnable) RobotCmd(1, "Pause %d\n", paused);
+ ShowPause(scr);
changed = 1;
break;
case KT_faster:
// if (paused)
// RefreshScreen();
break;
- }
+ case KT_quit:
+ FieldMessage(me, "G A M E O V E R");
+ refresh();
+ goto gameOver;
+ } //E_key
if (dropMode && DropPiece(scr) > 0) {
SetITimer(Game.speed, Game.speed);
if (spied)
changed = 1;
}
break;
- }
+ } //E_robot
case E_net:
switch(event.u.net.type) {
case NP_giveJunk:
netint2 data[2];
short column;
+ if (!Players[scr].alive) break;
memcpy(data, event.u.net.data, sizeof(data[0]));
column = Random(0, Players[scr].boardWidth);
data[1] = hton2(column);
SendPacket(scr, NP_insertJunk, sizeof(data), data);
// Message("Opponent added %d lines");
break;
- }
+ } //receive junklines
case NP_newPiece:
{
short shapeNum;
shapeNum = ntoh2(data[0]);
StartNewPiece(event.u.net.uid, NetNumToShape(shapeNum));
break;
- }
+ } //new piece
case NP_down:
MovePiece(event.u.net.uid, -1, 0);
break;
memcpy(data, event.u.net.data, sizeof(data));
InsertJunk(event.u.net.uid, ntoh2(data[0]), ntoh2(data[1]));
break;
- }
+ } //player added junklines
case NP_pause:
{
- netint2 data[1];
-
- memcpy(data, event.u.net.data, sizeof(data));
- pausedByThem = ntoh2(data[0]);
- paused = pausedByMe || pausedByThem;
- if (robotEnable)
- RobotCmd(1, "Pause %d %d\n", pausedByMe,
- pausedByThem);
- ShowPause(pausedByMe, pausedByThem);
+ Players[event.u.net.uid].flags ^= SCF_paused;
+ checkPaused();
+ if (robotEnable) RobotCmd(1, "Pause %d\n", paused);
+ ShowPause(event.u.net.uid);
+ changed = 1;
+ break;
+ } //(un)pause
+ case NP_argghhh:
+ {
+ memcpy(&Players[event.u.net.uid].alive,
+ event.u.net.data, sizeof(Players[0].alive));
+// checkPaused();
+ FieldMessage(event.u.net.uid, "G A M E O V E R");
changed = 1;
break;
- }
+ } //G/O
default:
break;
- }
+ } //E_net
break;
case E_lostRobot:
case E_lostConn:
goto gameOver;
default:
break;
- }
+ } //handle event
if (paused != oldPaused) {
if (paused) {
PauseTime();
ResumeTime();
}
oldPaused = paused;
- }
- }
+ } //(un)pause
+ } //game loop
nextPiece:
dropMode = 0;
FreezePiece(scr);
data[0] = hton2(junkLines);
SendPacket(scr, NP_giveJunk, sizeof(data), data);
}
- }
+ } //new piece loop
gameOver:
SetITimer(0, 0);
}
{
char ch;
+ port = DEFAULT_PORT;
Game.standout = Game.color = 1;
Game.initspeed = DEFAULT_INTERVAL;
MapKeys(DEFAULT_KEYS);
Players[0].boardHeight = MAX_BOARD_HEIGHT;
Players[0].boardVisible = 20;
Players[0].spy = 1;
- strcpy(Players[0].host, "localhost");
+ Players[0].alive = 1;
}
// if (getopt(argc, argv, "f:") == 'f')
// else
ReadConf(CONFIG_FILE);
while ((ch = getopt_long(argc, argv,
- "hHRs:r:Fk:c:odDSCap:i:l:", options, NULL)) != -1)
+ "hHRr:Fk:c:odDSCap:i:l:t:", options, NULL)) != -1)
HandleOption(ch, optarg);
if (optind < argc) {
Usage();
InitScreens();
if (initConn) {
game = GT_classicTwo;
- InitiateConnection(hostStr, portStr);
+ Players[0].flags |= SCF_paused;
+ paused = SCF_paused;
+ InitiateConnection(hostStr, port);
HandShake();
OneGame(me);
} //client
else {
game = GT_onePlayer;
- totalPlayers = 0;
+ totalPlayers = 1;
me = 1;
memcpy(&Players[me], &Players[0], sizeof(Player));
OneGame(me);
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;
-ExtFunc void make_netGen(void)
-{
- int i;
-
- for (i = 1; i <= MAX_SCREENS; i++)
- memcpy(netGen+i, &netGen[0], sizeof(EventGenRec));
-} //Make_netGen
-
-
-ExtFunc int InitiateConnection(char *hostStr, char *portStr)
+ExtFunc int InitiateConnection(char *hostStr, short port)
{ //connect to host
struct sockaddr_in addr;
struct hostent *host;
- short port;
-// make_netGen();
AtExit(CloseNet);
- if (portStr)
- port = atoi(portStr); /* XXX Error checking */
- else
- port = DEFAULT_PORT;
host = gethostbyname(hostStr);
if (!host)
die("gethostbyname");
goto again;
}
AddEventGen(&netGen[0]);
- totalPlayers = 0;
+ totalPlayers = 1;
return 0;
} //InitiateConnection
}
case NP_gamedata:
{
- fprintf(stderr, ": %d\n", event.type);
+ memcpy(&Game, event.u.net.data, event.u.net.size);
+ SRandom(Game.seed);
break;
}
case NP_newPlayer:
#include <stdio.h>
#include <signal.h>
+#define version_string "0.5.810"
+
#define ExtFunc /* Marks functions that need prototypes */
-#ifdef NOEXT
+#ifdef NOEXT //prevent re-declaration
# define EXT
-# define IN(a) a
#else
# define EXT extern
-# define IN(a)
#endif
-/*#ifndef NULL
- # define NULL ((void *)0)
- #endif*/
-
#ifdef HAS_SIGPROCMASK
typedef sigset_t MySigSet;
#else
#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"
+//#define DEFAULT_KEYS "hlkj mfp^lq"
+//#define DEFAULT_KEYS "4685 2fp^lq"
+#define DEFAULT_KEYS "dcaf b^fp^lq"
#define MAX_BOARD_WIDTH 32
#define MAX_BOARD_HEIGHT 64
-#define MAX_SCREENS 5
+#define MAX_SCREENS 9 //8 players
/* Event masks */
#define EM_alarm 000001
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_pause, NP_argghhh, NP_giveJunk, NP_newPiece, NP_down, NP_left, NP_right,
NP_rotright, NP_rotleft, NP_drop, NP_clear, NP_insertJunk
} NetPacketType;
char buf[512];
int bufSize, bufGoal;
} EventGenRec;
-extern EventGenRec netGen[MAX_SCREENS];
+EXT EventGenRec netGen[MAX_SCREENS];
MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
/* NP_startConn flags */
#define SCF_usingRobot 000001
#define SCF_fairRobot 000002
-#define SCF_setSeed 000004
+#define SCF_paused 000004
EXT int totalPlayers;
typedef struct _Player {
+ int alive;
char name[16];
int flags;
+ int team;
int dropmode;
int boardHeight, boardWidth, boardVisible;
int curX, curY;
long score;
int drops, lines, adds;
} score;
- char host[256];
- int spy;
+ char host[256]; //last-1
+ int spy; //last
} Player;
EXT Player Players[MAX_SCREENS];
EXT short me;
#define SPEEDMINIMUM 40000
typedef struct __Game {
- long seed;
- long initspeed, speed;
+ long seed; //1st
+ int initspeed; //2nd
+ int speed;
int standout, color, ascii;
} _Game;
EXT _Game Game;
EXT int robotEnable, robotVersion, fairRobot;
EXT int protocolVersion;
-EXT int initConn, waitConn;
-EXT char *hostStr, *portStr;
+EXT int initConn;
+EXT short port;
EXT char scratch[1024];
extern ShapeOption stdOptions[];
-extern char *version_string;
#include "proto.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' },
+ { "connections",1, 0, 'c' },
{ "speed", 1, 0, 'i' },
{ "seed", 1, 0, 's' },
{ "info", 0, 0, 'H' },
{ 0, 0, 0, 0 }
};
+static char Connections = 2;
+
static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
die("listen");
addrLen = sizeof(addr);
- for (i = 1; i <= MAX_CONNECTIONS; i++) {
+ for (i = 1; i <= 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));
return 0;
} //WaitForConnection
-ExtFunc int StartServer(char *portStr)
+ExtFunc int StartServer(void)
{
MyEvent event;
- char serverdata[255];
int playercount;
+ int playersReady = 0;
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);
+ char serverdata[255];
+ for (i = 1; i <= totalPlayers; i++) {
+ sprintf(serverdata, "Netris server %s", version_string);
+ SendPacketTo(i, i, NP_hello, strlen(serverdata)+1, serverdata);
+ }
}
- while(1) {
+ do {
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! :)
+ Players[event.u.net.sender].alive = 0;
+ for (i = 1; i <= totalPlayers; i++)
+ SendPacketTo(i, event.u.net.sender,
+ NP_argghhh, sizeof(Players[0].alive),
+ &Players[event.u.net.sender].alive);
break;
} //NP_endConn
case NP_hello:
{ //receive player details and return other players
memcpy(&Players[event.u.net.sender],
event.u.net.data, event.u.net.size);
+ if (!Players[event.u.net.sender].team)
+ Players[event.u.net.sender].team = 256 - event.u.net.sender;
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);
+ SendPacketTo(event.u.net.sender, 0, NP_gamedata,
+ sizeof(Game.seed)+sizeof(Game.initspeed), &Game);
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");
+ if (++playersReady >= totalPlayers) {
+ fprintf(stderr, "Starting game (%010d)\n", Game.seed);
for (i = 1; i <= totalPlayers; i++)
SendPacketTo(i, 0, NP_goAhead, 0, NULL);
- playercount++;
} //give go ahead
break;
} //NP_playerdata
// if (event.u.net.type >= NP_pause)
for (i = 1; i <= totalPlayers; i++)
if (i != event.u.net.sender)
+ if (event.u.net.type != NP_giveJunk
+ || Players[i].team != Players[event.u.net.sender].team)
SendPacketTo(i, event.u.net.sender, event.u.net.type,
event.u.net.size, event.u.net.data);
break;
}
- } //E_net
- }
- } //loop
+ }
+ } //E_net
+ playercount = 0;
+ for (i = 1; i <= totalPlayers; i++)
+ if (netGen[i].fd >= 0) playercount++;
+ } while (playercount > 1);
} //StartServer
{
switch (tag) {
case 'p': //port
- portStr = value; break;
+ port = atoi(value);
+ break;
+ case 'c': //connections
+ Connections = atoi(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);
if (sigsetjmp(close_env, 1)) exit(0);
signal(SIGINT, CatchInt);
- Game.standout = Game.color = 1;
+ port = DEFAULT_PORT;
Game.initspeed = DEFAULT_INTERVAL;
+ Game.seed = time(0);
// if (getopt(argc, argv, "f:") == 'f')
// ReadConf(optarg);
// else
ReadConf(CONFIG_FILE);
while ((ch = getopt_long(argc, argv,
- "hHp:i:s:", options, NULL)) != -1)
+ "hHp:i:s:c:", options, NULL)) != -1)
HandleOption(ch, optarg);
if (optind < argc) {
Usage();
// WriteConf();
Header();
- StartServer(portStr);
+ WaitForConnection(port);
+ StartServer();
return 0;
}
" -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"
ExtFunc void InitUtil(void)
{
- if (Game.seed)
- SRandom(Game.seed);
- else
- SRandom(time(0));
+ SRandom(time(0));
if (sigsetjmp(close_env, 1)) exit(0);
signal(SIGINT, CatchInt);
ResetBaseTime();
} //SRandom
ExtFunc int Random(int min, int max1)
-{
+{ //return a random value
myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
return myRandSeed % (max1 - min) + min;
} //Random