2 * Netris -- A free networked version of Tetris
3 * Copyright (C) 1994,1995 Mark Weaver <Mark_Weaver@brown.edu>
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * $Id: game.c,v 1.37 1995/07/11 08:53:23 mhw Exp $
27 #include <sys/types.h>
28 #include <netinet/in.h>
30 enum { KT_left, KT_rotate, KT_right, KT_drop,
31 KT_down, KT_toggleSpy, KT_pause, KT_faster, KT_numKeys };
33 static char *keyNames[KT_numKeys+1] = {
34 "Left", "Rotate", "Right", "Drop", "Down", "ToggleSpy", "Pause",
37 static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
39 static char keyTable[KT_numKeys+1] = "jkl mspf";
40 static int dropModeEnable = 0;
41 static char *robotProg;
43 ExtFunc int StartNewPiece(int scr, Shape *shape)
45 curShape[scr] = shape;
46 curY[scr] = boardVisible[scr] + 4;
47 curX[scr] = boardWidth[scr] / 2;
48 while (!ShapeVisible(shape, scr, curY[scr], curX[scr]))
50 if (!ShapeFits(shape, scr, curY[scr], curX[scr]))
52 PlotShape(shape, scr, curY[scr], curX[scr], 1);
56 ExtFunc void OneGame(int scr, int scr2)
59 int linesCleared, changed = 0;
60 int spied = 0, spying = 0, dropMode = 0;
61 int oldPaused = 0, paused = 0, pausedByMe = 0, pausedByThem = 0;
67 speed = stepDownInterval;
74 UpdateOpponentDisplay();
77 SetITimer(speed, speed);
79 RobotCmd(0, "GameType %s\n", gameNames[game]);
80 RobotCmd(0, "BoardSize 0 %d %d\n",
81 boardVisible[scr], boardWidth[scr]);
83 RobotCmd(0, "BoardSize 1 %d %d\n",
84 boardVisible[scr2], boardWidth[scr2]);
85 RobotCmd(0, "Opponent 1 %s %s\n", opponentName, opponentHost);
86 if (opponentFlags & SCF_usingRobot)
87 RobotCmd(0, "OpponentFlag 1 robot\n");
88 if (opponentFlags & SCF_fairRobot)
89 RobotCmd(0, "OpponentFlag 1 fairRobot\n");
91 RobotCmd(0, "TickLength %.3f\n", speed / 1.0e6);
92 RobotCmd(0, "BeginGame\n");
95 while (StartNewPiece(scr, ChooseOption(stdOptions))) {
96 if (robotEnable && !fairRobot)
97 RobotCmd(1, "NewPiece %d\n", ++pieceCount);
102 shapeNum = ShapeToNetNum(curShape[scr]);
103 data[0] = hton2(shapeNum);
104 SendPacket(NP_newPiece, sizeof(data), data);
107 changed = RefreshBoard(scr) || changed;
109 changed = RefreshBoard(scr2) || changed;
115 switch (WaitMyEvent(&event, EM_any)) {
117 if (!MovePiece(scr, -1, 0))
120 SendPacket(NP_down, 0, NULL);
123 p = strchr(keyTable, tolower(event.u.key));
126 RobotCmd(1, "UserKey %d %s\n",
127 (int)(unsigned char)event.u.key,
128 p ? keyNames[key] : "?");
134 if (paused && (key != KT_pause))
138 if (MovePiece(scr, 0, -1) && spied)
139 SendPacket(NP_left, 0, NULL);
142 if (MovePiece(scr, 0, 1) && spied)
143 SendPacket(NP_right, 0, NULL);
146 if (RotatePiece(scr) && spied)
147 SendPacket(NP_rotate, 0, NULL);
150 if (MovePiece(scr, -1, 0) && spied)
151 SendPacket(NP_down, 0, NULL);
154 spying = (!spying) && (scr2 >= 0);
157 if (DropPiece(scr) > 0) {
159 SendPacket(NP_drop, 0, NULL);
160 SetITimer(speed, speed);
162 dropMode = dropModeEnable;
165 pausedByMe = !pausedByMe;
166 if (game == GT_classicTwo) {
169 data[0] = hton2(pausedByMe);
170 SendPacket(NP_pause, sizeof(data), data);
172 paused = pausedByMe || pausedByThem;
174 RobotCmd(1, "Pause %d %d\n", pausedByMe,
176 ShowPause(pausedByMe, pausedByThem);
180 if (game != GT_onePlayer)
183 SetITimer(speed, SetITimer(0, 0));
188 if (dropMode && DropPiece(scr) > 0) {
190 SendPacket(NP_drop, 0, NULL);
191 SetITimer(speed, speed);
198 cmd = event.u.robot.data;
199 if ((p = strchr(cmd, ' ')))
202 p = cmd + strlen(cmd);
203 for (key = 0; keyNames[key]; ++key)
204 if (!strcmp(keyNames[key], cmd) &&
205 (fairRobot || (1 == sscanf(p, "%d", &num) &&
208 if (!strcmp(cmd, "Message")) {
215 switch(event.u.net.type) {
221 memcpy(data, event.u.net.data, sizeof(data[0]));
222 column = Random(0, boardWidth[scr]);
223 data[1] = hton2(column);
224 InsertJunk(scr, ntoh2(data[0]), column);
226 SendPacket(NP_insertJunk, sizeof(data), data);
235 memcpy(data, event.u.net.data, sizeof(data));
236 shapeNum = ntoh2(data[0]);
237 StartNewPiece(scr2, NetNumToShape(shapeNum));
241 MovePiece(scr2, -1, 0);
244 MovePiece(scr2, 0, -1);
247 MovePiece(scr2, 0, 1);
256 ClearFullLines(scr2);
262 memcpy(data, event.u.net.data, sizeof(data));
263 InsertJunk(scr2, ntoh2(data[0]), ntoh2(data[1]));
270 memcpy(data, event.u.net.data, sizeof(data));
271 pausedByThem = ntoh2(data[0]);
272 paused = pausedByMe || pausedByThem;
274 RobotCmd(1, "Pause %d %d\n", pausedByMe,
276 ShowPause(pausedByMe, pausedByThem);
290 if (paused != oldPaused) {
292 pauseTimeLeft = SetITimer(0, 0);
294 SetITimer(speed, pauseTimeLeft);
301 linesCleared = ClearFullLines(scr);
302 if (linesCleared > 0 && spied)
303 SendPacket(NP_clear, 0, NULL);
304 if (game == GT_classicTwo && linesCleared > 1) {
308 junkLines = linesCleared - (linesCleared < 4);
309 data[0] = hton2(junkLines);
310 SendPacket(NP_giveJunk, sizeof(data), data);
317 ExtFunc int main(int argc, char **argv)
319 int initConn = 0, waitConn = 0, ch;
320 char *hostStr = NULL, *portStr = NULL;
323 stepDownInterval = DEFAULT_INTERVAL;
324 while ((ch = getopt(argc, argv, "hHRs:r:Fk:c:woDSp:i:")) != -1)
337 stepDownInterval = atof(optarg) * 1e6;
340 initSeed = atoi(optarg);
341 myFlags |= SCF_setSeed;
346 myFlags |= SCF_usingRobot;
350 myFlags |= SCF_fairRobot;
368 for (i=0;optarg[i] && i < KT_numKeys;i++)
369 keyTable[i] = optarg[i];
379 if (optind < argc || (initConn && waitConn)) {
383 if (fairRobot && !robotEnable)
384 fatal("You can't use the -F option without the -r option");
387 InitRobot(robotProg);
390 if (initConn || waitConn) {
393 game = GT_classicTwo;
395 InitiateConnection(hostStr, portStr);
397 WaitForConnection(portStr);
402 data[0] = hton4(MAJOR_VERSION);
403 data[1] = hton4(PROTOCOL_VERSION);
404 SendPacket(NP_version, sizeof(data), data);
405 if (WaitMyEvent(&event, EM_net) != E_net)
406 fatal("Network negotiation failed");
407 memcpy(data, event.u.net.data, sizeof(data));
408 major = ntoh4(data[0]);
409 protocolVersion = ntoh4(data[1]);
410 if (event.u.net.type != NP_version || major < MAJOR_VERSION)
411 fatal("Your opponent is using an old, incompatible version\n"
412 "of Netris. They should get the latest version.");
413 if (major > MAJOR_VERSION)
414 fatal("Your opponent is using an newer, incompatible version\n"
415 "of Netris. Get the latest version.");
416 if (protocolVersion > PROTOCOL_VERSION)
417 protocolVersion = PROTOCOL_VERSION;
419 if (protocolVersion < 3 && stepDownInterval != DEFAULT_INTERVAL)
420 fatal("Your opponent's version of Netris predates the -i option.\n"
421 "For fairness, you shouldn't use the -i option either.");
427 if (protocolVersion >= 3)
430 len = sizeof(netint4[2]);
431 if ((myFlags & SCF_setSeed))
437 data[0] = hton4(myFlags);
438 data[1] = hton4(seed);
439 data[2] = hton4(stepDownInterval);
440 SendPacket(NP_startConn, len, data);
441 if (WaitMyEvent(&event, EM_net) != E_net ||
442 event.u.net.type != NP_startConn)
443 fatal("Network negotiation failed");
444 memcpy(data, event.u.net.data, len);
445 opponentFlags = ntoh4(data[0]);
446 seed = ntoh4(data[1]);
448 if ((opponentFlags & SCF_setSeed) != (myFlags & SCF_setSeed))
449 fatal("If one player sets the random number seed, "
451 if ((myFlags & SCF_setSeed) && seed != initSeed)
452 fatal("Both players have set the random number seed, "
453 "and they are unequal.");
454 if (protocolVersion >= 3 && stepDownInterval != ntoh4(data[2]))
455 fatal("Your opponent is using a different step-down "
456 "interval (-i).\nYou must both use the same one.");
464 userName = getenv("LOGNAME");
465 if (!userName || !userName[0])
466 userName = getenv("USER");
467 if (!userName || !userName[0])
468 strcpy(userName, "???");
469 len = strlen(userName)+1;
470 if (len > sizeof(opponentName))
471 len = sizeof(opponentName);
472 SendPacket(NP_userName, len, userName);
473 if (WaitMyEvent(&event, EM_net) != E_net ||
474 event.u.net.type != NP_userName)
475 fatal("Network negotiation failed");
476 strncpy(opponentName, event.u.net.data,
477 sizeof(opponentName)-1);
478 opponentName[sizeof(opponentName)-1] = 0;
479 for (i = 0; opponentName[i]; ++i)
480 if (!isprint(opponentName[i]))
481 opponentName[i] = '?';
482 for (i = 0; opponentHost[i]; ++i)
483 if (!isprint(opponentHost[i]))
484 opponentHost[i] = '?';