X-Git-Url: http://git.shiar.net/netris.git/blobdiff_plain/ec797c133bd83404f6167fb46c098c236333d168..45dc9d995860486f1758dcf79fd2d8cd8dfb210a:/game.c diff --git a/game.c b/game.c index 26ab6a8..de0d605 100644 --- a/game.c +++ b/game.c @@ -16,7 +16,7 @@ * 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.38 1996/02/09 08:22:11 mhw Exp $ + * $Id: game.c,v 1.39 1999/05/16 06:56:27 mhw Exp $ */ #define NOEXT @@ -26,19 +26,45 @@ #include #include #include +#include -enum { KT_left, KT_rotate, KT_right, KT_drop, KT_down, - KT_toggleSpy, KT_pause, KT_faster, KT_redraw, KT_numKeys }; +static struct option options[] = { + { "ascii", 2, 0, 'a' }, + { "connect", 1, 0, 'c' }, + { "port", 1, 0, 'p' }, + { "level", 1, 0, 'l' }, + { "team", 1, 0, 't' }, + { "spy", 1, 0, 1 }, + { "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_faster, KT_pause, KT_redraw, KT_quit, KT_numKeys }; static char *keyNames[KT_numKeys+1] = { - "Left", "Rotate", "Right", "Drop", "Down", "ToggleSpy", "Pause", - "Faster", "Redraw", NULL }; + "Left", "Right", "RotRight", "RotLeft", "Drop", "Down", + "Faster", "Pause", "Redraw", "Quit", NULL }; static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" }; static char keyTable[KT_numKeys+1]; -static int dropModeEnable = 0; -static char *robotProg; + +static char *hostStr; +static int paused = 0; +static char lastadd; + +static sigjmp_buf close_env; + ExtFunc void MapKeys(char *newKeys) { @@ -73,88 +99,273 @@ 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 + port = atoi(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 't': //team + Players[0].team = atoi(value); + break; + case 1: //spy + { + int i; + i = atof(value); + Players[i / 10].spy = i % 10; + } + 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) { - curShape[scr] = shape; - curY[scr] = boardVisible[scr] + 4; - curX[scr] = boardWidth[scr] / 2; - while (!ShapeVisible(shape, scr, curY[scr], curX[scr])) - --curY[scr]; - if (!ShapeFits(shape, scr, curY[scr], curX[scr])) + if (Players[scr].nextShape) { + Players[scr].curShape = Players[scr].nextShape; + Players[scr].nextShape = shape; + } + else + 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(shape, scr, curY[scr], curX[scr], 1); + PlotShape(Players[scr].curShape, scr, + Players[scr].curY, Players[scr].curX, 1, 1); return 1; } -ExtFunc void OneGame(int scr, int scr2) +ExtFunc void checkPaused(void) +{ //check whether anyone paused the game + int i; + + paused = Game.started < 1; + for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive > 0) + paused |= Players[i].flags & SCF_paused; + if (paused) paused = 1; +} //checkPaused + +ExtFunc void StartGame(void) +{ //init new game + int i; + + maxPlayer = lastadd = me; + SRandom(Game.seed); + Game.speed = Game.initspeed; + for (i = 1; i < Players[me].score.level; i++) + Game.speed /= SPEEDINC; + if (Game.speed < SPEEDMINIMUM) + Game.speed = SPEEDMINIMUM; + ResetBaseTime(); //reset timer + InitFields(); + SetITimer(Game.speed, Game.speed); + Players[me].nextShape = ChooseOption(stdOptions); + for (i = 1; i < MAX_SCREENS; i++) { + Players[i].score.score = Players[i].score.drops + = Players[i].score.lines = Players[i].score.adds = 0; + ClearField(i); + DrawField(i); + } //reset all players +} //StartGame + +ExtFunc void OneGame(void) { MyEvent event; int linesCleared, changed = 0; - int spied = 0, spying = 0, dropMode = 0; - int oldPaused = 0, paused = 0, pausedByMe = 0, pausedByThem = 0; + int dropMode = 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) + char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple", + "Red", "Grey", "White", "*Orange" }; + int i; - speed = stepDownInterval; - ResetBaseTime(); - InitBoard(scr); - if (scr2 >= 0) { - spied = 1; - spying = 1; - InitBoard(scr2); - UpdateOpponentDisplay(); - } - ShowDisplayInfo(); - SetITimer(speed, speed); + StartGame(); if (robotEnable) { + int counter; 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"); - } - RobotCmd(0, "TickLength %.3f\n", speed / 1.0e6); + Players[me].boardVisible, Players[me].boardWidth); + for (i = 1; i < MAX_SCREENS; i++) + if ((Players[i].alive >= 0) && (i != me)) { + RobotCmd(0, "BoardSize %d %d %d\n", + counter, Players[i].boardVisible, Players[i].boardWidth); + RobotCmd(0, "Opponent %d %s %s\n", + counter, 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); + counter++; + } //enemy + RobotCmd(0, "TickLength %.3f\n", Game.speed / 1.0e6); RobotCmd(0, "BeginGame\n"); RobotTimeStamp(); } - while (StartNewPiece(scr, ChooseOption(stdOptions))) { - if (robotEnable && !fairRobot) - RobotCmd(1, "NewPiece %d\n", ++pieceCount); - if (spied) { - short shapeNum; - netint2 data[1]; - - shapeNum = ShapeToNetNum(curShape[scr]); - data[0] = hton2(shapeNum); - SendPacket(NP_newPiece, sizeof(data), data); - } - for (;;) { - changed = RefreshBoard(scr) || changed; - if (spying) - changed = RefreshBoard(scr2) || changed; + while (1) { +GameLoop: + if (Players[me].alive > 0) { + if (!StartNewPiece(me, ChooseOption(stdOptions))) { + netint4 data[4]; + Players[me].alive = 0; + if (lastadd == me) Messagef("\\%dYou died", + Players[me].team > 7 ? 7 : Players[me].team); + else Messagef("\\%d%s fragged you", + Players[lastadd].team > 7 ? 7 : Players[lastadd].team, + Players[lastadd].name); + if (game == GT_classicTwo) + SendPacket(me, NP_argghhh, sizeof(lastadd), &lastadd); + ShowPause(me); + changed = 1; + } //die + else { + ShowScore(me, Players[me].score); + if (robotEnable && !fairRobot) + RobotCmd(1, "NewPiece %d\n", ++pieceCount); + if (spied) { + short shapeNum; + netint2 data[1]; + + shapeNum = ShapeToNetNum(Players[me].curShape); + data[0] = hton2(shapeNum); + SendPacket(me, NP_newPiece, sizeof(data), data); + } //send new piece + } + } //new piece + while (1) { + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0 && Players[i].spy) + changed |= RefreshBoard(i); if (changed) { - RefreshScreen(); + if (!paused) ShowTime(); + refresh(); changed = 0; - } + } //screen update + playercount = 0; + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive >= 0) playercount++; + if (playercount < 1) goto gameOver; CheckNetConn(); switch (WaitMyEvent(&event, EM_any)) { case E_alarm: - if (!MovePiece(scr, -1, 0)) - goto nextPiece; - else if (spied) - SendPacket(NP_down, 0, NULL); + if (!paused && Players[me].alive > 0) + if (!MovePiece(me, -1, 0)) + goto nextPiece; + else if (spied) + SendPacket(me, NP_down, 0, NULL); break; case E_key: + Messagef("key: %d", event.u.key); p = strchr(keyTable, tolower(event.u.key)); key = p - keyTable; if (robotEnable) { @@ -162,73 +373,88 @@ ExtFunc void OneGame(int scr, int scr2) (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[me].alive <= 0 && key != KT_quit) break; + if (paused && key < KT_pause) break; switch(key) { case KT_left: - if (MovePiece(scr, 0, -1) && spied) - SendPacket(NP_left, 0, NULL); + if (MovePiece(me, 0, -1) && spied) + SendPacket(me, NP_left, 0, NULL); break; case KT_right: - if (MovePiece(scr, 0, 1) && spied) - SendPacket(NP_right, 0, NULL); - break; - case KT_rotate: - if (RotatePiece(scr) && spied) - SendPacket(NP_rotate, 0, NULL); + if (MovePiece(me, 0, 1) && spied) + SendPacket(me, NP_right, 0, NULL); break; - case KT_down: - if (MovePiece(scr, -1, 0) && spied) - SendPacket(NP_down, 0, NULL); + case KT_rotleft: + if (RotatePiece(me, 0) && spied) + SendPacket(me, NP_rotleft, 0, NULL); break; - case KT_toggleSpy: - spying = (!spying) && (scr2 >= 0); + case KT_rotright: + if (RotatePiece(me, 1) && spied) + SendPacket(me, NP_rotright, 0, NULL); break; - case KT_drop: - if (DropPiece(scr) > 0) { - if (spied) - SendPacket(NP_drop, 0, NULL); - SetITimer(speed, speed); + case KT_down: + SetITimer(Game.speed, Game.speed); + if (MovePiece(me, -1, 0)) { + if (spied) SendPacket(me, NP_down, 0, NULL); } - dropMode = dropModeEnable; + else goto nextPiece; break; - case KT_pause: - pausedByMe = !pausedByMe; - if (game == GT_classicTwo) { - netint2 data[1]; - - data[0] = hton2(pausedByMe); - SendPacket(NP_pause, sizeof(data), data); + case KT_drop: + SetITimer(Game.speed, Game.speed); + if (DropPiece(me)) { + if (spied) SendPacket(me, NP_drop, 0, NULL); + if (Players[me].dropmode == 2) goto nextPiece; } - paused = pausedByMe || pausedByThem; - if (robotEnable) - RobotCmd(1, "Pause %d %d\n", pausedByMe, - pausedByThem); - ShowPause(pausedByMe, pausedByThem); - changed = 1; + else goto nextPiece; + dropMode = Players[me].dropmode; break; 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[me].score.level++; + ShowScore(me, Players[me].score); + changed = 1; + break; + case KT_pause: + Players[me].flags ^= SCF_paused; + if (Game.started > 1) + Messagef(Players[me].flags & SCF_paused + ? "You paused the game" + : "You unpaused the game"); + else + Messagef(Players[me].flags & SCF_paused + ? "You are not ready" : "You are ready"); + checkPaused(); + if (game == GT_classicTwo) + SendPacket(me, NP_pause, 0, NULL); + if (robotEnable) RobotCmd(1, "Pause %d\n", paused); + ShowPause(me); changed = 1; break; case KT_redraw: - ScheduleFullRedraw(); - if (paused) - RefreshScreen(); + DrawTitle(); + InitFields(); +// ScheduleFullRedraw(); + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].spy && Players[i].alive > 0) + RefreshBoard(i); + refresh(); break; - } - if (dropMode && DropPiece(scr) > 0) { + case KT_quit: + ShowPause(me); + refresh(); + goto gameOver; + } //E_key + if (dropMode && DropPiece(me) > 0) { + SetITimer(Game.speed, Game.speed); if (spied) - SendPacket(NP_drop, 0, NULL); - SetITimer(speed, speed); + SendPacket(me, NP_drop, 0, NULL); } break; case E_robot: @@ -246,285 +472,309 @@ ExtFunc void OneGame(int scr, int scr2) num == pieceCount))) goto keyEvent; if (!strcmp(cmd, "Message")) { - Message(p); + Messagef(p); changed = 1; } break; - } + } //E_robot case E_net: switch(event.u.net.type) { - case NP_giveJunk: - { - netint2 data[2]; - short column; - - memcpy(data, event.u.net.data, sizeof(data[0])); - column = Random(0, boardWidth[scr]); - data[1] = hton2(column); - InsertJunk(scr, ntoh2(data[0]), column); - if (spied) - SendPacket(NP_insertJunk, sizeof(data), data); - break; - } case NP_newPiece: { 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; - } + } //new piece 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_rotate: - RotatePiece(scr2); + case NP_rotleft: + RotatePiece(event.u.net.uid, 0); + break; + case NP_rotright: + 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; + } //player added junklines + case NP_giveJunk: + { + netint2 data[2]; + short column; + + if (Players[me].alive <= 0) break; + memcpy(data, event.u.net.data, sizeof(data[0])); + column = Random(0, Players[me].boardWidth); + data[1] = hton2(column); + Messagef("\\%d%s sends %d lines", + Players[event.u.net.uid].team > 7 ? 7 + : Players[event.u.net.uid].team, + Players[event.u.net.uid].name, ntoh2(data[0])); + lastadd = event.u.net.uid; + InsertJunk(me, ntoh2(data[0]), column); + if (spied) + SendPacket(me, NP_insertJunk, sizeof(data), + data); + break; + } //receive junklines + case NP_start: + { + Game.started = 2; + paused = 0; + Messagef("The game has started"); + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0) ShowPause(i); + break; + } //start game + case NP_stop: + { + if (Game.started > 1) + Messagef("The game has ended"); + Game.started = 0; + memcpy(&Game.seed, event.u.net.data, + event.u.net.size); + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive >= 0) { + Players[i].alive = 1; + Players[i].flags |= SCF_paused; + } //reset players + StartGame(); //reset everything + ShowTime(); //redraw timer while unpaused + checkPaused(); //pause + oldPaused = 0; //reset pause + changed = 1; + goto GameLoop; + } //stop game + case NP_newPlayer: + { + if (event.u.net.uid > maxPlayer) + maxPlayer = event.u.net.uid; + memcpy(&Players[event.u.net.uid], + event.u.net.data, event.u.net.size); + ClearField(event.u.net.uid); + if (Players[event.u.net.uid].team > 7) + Messagef("%s joined the game", + Players[event.u.net.uid].name); + else + Messagef("%s joined %s team", + Players[event.u.net.uid].name, + teams[Players[event.u.net.uid].team]); + if (Players[event.u.net.uid].flags & SCF_paused) { + checkPaused(); + if (robotEnable) + RobotCmd(1, "Pause %d\n", paused); + } //player has paused + DrawField(event.u.net.uid); +// ShowPause(event.u.net.uid); + changed = 1; break; - } + } //player joined case NP_pause: { - netint2 data[1]; + char s[20]; - 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; + if (Game.started > 1) + strcpy(s, + Players[event.u.net.uid].flags & SCF_paused + ? "paused the game" : "unpaused the game"); + else + strcpy(s, + Players[event.u.net.uid].flags & SCF_paused + ? "is not ready" : "is ready"); + Messagef("%s %s", + Players[event.u.net.uid].name, s); + checkPaused(); + if (robotEnable) RobotCmd(1, "Pause %d\n", paused); + ShowPause(event.u.net.uid); changed = 1; break; - } + } //(un)pause + case NP_part: + checkPaused(); + oldPaused = 0; + { + Players[event.u.net.uid].alive = -1; + Messagef("%s left", + Players[event.u.net.uid].name); + checkPaused(); + ShowPause(event.u.net.uid); + changed = 1; + break; + } //player left + case NP_argghhh: + { + char i; + memcpy(&i, event.u.net.data, sizeof(i)); + Players[event.u.net.uid].alive = 0; + if (i == me) Messagef("\\%dYou fragged %s", + Players[me].team > 7 ? 7 : Players[me].team, + Players[event.u.net.uid].name); + else if (i == event.u.net.uid) + Messagef("\\%d%s died", + Players[i].team > 7 ? 7 : Players[i].team, + Players[i].name); + else Messagef("\\%d%s fragged %s", + Players[i].team > 7 ? 7 : Players[i].team, + Players[i].name, + Players[event.u.net.uid].name); + checkPaused(); + ShowPause(event.u.net.uid); + 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) + if (paused) { + PauseTime(); pauseTimeLeft = SetITimer(0, 0); - else - SetITimer(speed, pauseTimeLeft); + } + else { + SetITimer(Game.speed, pauseTimeLeft); + ResumeTime(); + } oldPaused = paused; - } - } + } //(un)pause + } //game loop nextPiece: dropMode = 0; - FreezePiece(scr); - linesCleared = ClearFullLines(scr); - if (linesCleared > 0 && spied) - SendPacket(NP_clear, 0, NULL); + FreezePiece(me); + Players[me].score.drops++; + Players[me].score.score++; + if ((linesCleared = ClearFullLines(me)) > 0) { + if (game == GT_onePlayer) + if ((Players[me].score.lines / 10) < + ((Players[me].score.lines + linesCleared) / 10)) { + if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM) + Game.speed = SPEEDMINIMUM; + SetITimer(Game.speed, SetITimer(0, 0)); + Players[me].score.level++; + } //level up + Players[me].score.score += linevalues[linesCleared - 1]; + Players[me].score.lines += linesCleared; + Players[me].score.adds += linesCleared - (linesCleared < 4); + if (spied) + SendPacket(me, NP_clear, 0, NULL); + } if (game == GT_classicTwo && linesCleared > 1) { short junkLines; netint2 data[1]; junkLines = linesCleared - (linesCleared < 4); data[0] = hton2(junkLines); - SendPacket(NP_giveJunk, sizeof(data), data); - } - } + SendPacket(me, NP_giveJunk, sizeof(data), data); + Messagef("\\%dYou sent %d lines", + Players[me].team > 7 ? 7 : Players[me].team, junkLines); + } //send junk to others + } //new piece loop gameOver: SetITimer(0, 0); } +ExtFunc void CatchInt(int sig) +{ + siglongjmp(close_env, 1); +} + ExtFunc int main(int argc, char **argv) { - int initConn = 0, waitConn = 0, ch; - char *hostStr = NULL, *portStr = NULL; + char ch; - standoutEnable = 1; - stepDownInterval = DEFAULT_INTERVAL; + port = DEFAULT_PORT; + Game.standout = Game.color = 1; + Game.initspeed = DEFAULT_INTERVAL; MapKeys(DEFAULT_KEYS); - while ((ch = getopt(argc, argv, "hHRs:r:Fk:c:woDSp: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 '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); + { + int i; + char *userName; + + for (i = 0; i < MAX_SCREENS; i++) { + Players[i].alive = -1; + Players[i].score.level = Players[i].spy = 1; + Players[i].boardWidth = 10; + Players[i].boardHeight = MAX_BOARD_HEIGHT; + Players[i].boardVisible = 20; + strcpy(Players[i].name, "???"); + ClearField(i); } - if (optind < argc || (initConn && waitConn)) { + 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].alive = 1; + } //set defaults + +// if (getopt(argc, argv, "f:") == 'f') +// ReadConf(optarg); +// else + ReadConf(CONFIG_FILE); + while ((ch = getopt_long(argc, argv, + "hHRr:Fk:c:odDSCap:i:l:t:", 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"); - InitUtil(); - if (robotEnable) - InitRobot(robotProg); - InitNet(); - InitScreens(); - if (initConn || waitConn) { - MyEvent event; +// WriteConf(); + if (sigsetjmp(close_env, 1)) + exit(0); + signal(SIGINT, CatchInt); //handle exit (^C) + InitScreens(); //setup screen + DrawTitle(); + 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(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(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(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); - } + spied = 1; + InitiateConnection(hostStr, port); + HandShake(); + checkPaused(); + OneGame(); + } //client else { game = GT_onePlayer; - OneGame(0, -1); - } + Game.seed = time(0); + Game.started = 2; + Game.maxplayers = 1; + me = 1; + memcpy(&Players[me], &Players[0], sizeof(Player)); + OneGame(); + } //singleplay return 0; }