X-Git-Url: http://git.shiar.nl/netris.git/blobdiff_plain/ec797c133bd83404f6167fb46c098c236333d168..50f9d7882f93716af8b7436e88d1da62f05e198b:/game.c diff --git a/game.c b/game.c index 26ab6a8..5779d84 100644 --- a/game.c +++ b/game.c @@ -15,36 +15,66 @@ * 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.38 1996/02/09 08:22:11 mhw Exp $ */ #define NOEXT #include "netris.h" + #include #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 }; +#include "client.h" +#include "util.h" +#include "board.h" +#include "curses.h" +#include "inet.h" +#include "msg.en.h" + +static struct option options[] = { + { "ascii", 2, 0, 'a' }, + { "connect", 1, 0, 'c' }, + { "port", 1, 0, 'p' }, + { "level", 1, 0, 'l' }, + { "nick", 1, 0, 'n' }, + { "team", 1, 0, 't' }, + { "dropmode", 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" }; +_Sets Sets = {7, 0, 1, 1, 1}; static char keyTable[KT_numKeys+1]; -static int dropModeEnable = 0; -static char *robotProg; -ExtFunc void MapKeys(char *newKeys) +static char *hostStr; +static int paused = 0; +static char lastadd; + + +void MapKeys(char *newKeys) { int i, k, ch; char used[256]; int errs = 0; + char scratch[6]; /* XXX assumptions about ASCII encoding here */ for (i = k = 0; newKeys[i] && k < KT_numKeys; i++,k++) { @@ -67,7 +97,7 @@ ExtFunc void MapKeys(char *newKeys) fprintf(stderr, "Duplicate key mappings:\n"); errs++; fprintf(stderr, " %s mapped to both %s and %s\n", - scratch, keyNames[used[ch]-1], keyNames[k]); + scratch, keyNames[used[ch]-1], keyNames[k]); } used[ch] = k + 1; } @@ -75,460 +105,665 @@ ExtFunc void MapKeys(char *newKeys) exit(1); } -ExtFunc int StartNewPiece(int scr, Shape *shape) +void WriteConf(void) { - 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])) - return 0; - PlotShape(shape, scr, curY[scr], curX[scr], 1); - return 1; + 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); } -ExtFunc void OneGame(int scr, int scr2) +void HandleOption(char tag, char *value) { - MyEvent event; - int linesCleared, changed = 0; - int spied = 0, spying = 0, dropMode = 0; - int oldPaused = 0, paused = 0, pausedByMe = 0, pausedByThem = 0; - long pauseTimeLeft; - int pieceCount = 0; - int key; - char *p, *cmd; - - speed = stepDownInterval; - ResetBaseTime(); - InitBoard(scr); - if (scr2 >= 0) { - spied = 1; - spying = 1; - InitBoard(scr2); - UpdateOpponentDisplay(); + switch (tag) { + case 'a': //ascii + if (value && !strcasecmp(value, "0")) Sets.ascii = 0; + else Sets.ascii = 1; + Sets.drawstyle &= ~Sets.ascii; + break; + case 'c': //connect + game = GT_classicTwo; + 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 + Players[0].score.level = MIN(MAX(atof(value), 1), 15); + break; + case 'n': //nick + memcpy(Players[0].name, value, strlen(value) + 1); + break; + case 't': //team + Players[0].team = atoi(value); + break; + case 'd': //dropmode + Sets.dropmode = atoi(value); + break; + case 'C': //color + if (value && !strcasecmp(value, "1")) Sets.color = 1; + else Sets.color = 0; + break; + case 'S': //slowterm + if (value && !strcasecmp(value, "1")) Sets.standout = 1; + else Sets.standout = 0; + break; + case 'k': //keys + MapKeys(value); + break; + case 'H': //info + Header(); + DistInfo(); + exit(0); + case 'R': //rules + Rules(); + exit(0); + case 'h': //help + Usage(); + exit(0); + default: + Usage(); + exit(1); } - ShowDisplayInfo(); - SetITimer(speed, 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"); +} + +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; + } + } } - RobotCmd(0, "TickLength %.3f\n", speed / 1.0e6); - RobotCmd(0, "BeginGame\n"); - RobotTimeStamp(); + fclose(file_in); + } //read file + else { + fprintf(stderr, "Unable to open config file %s.\n", filename); + } //defaults + +} + +int StartNewPiece(int scr, char shape) +{ + Players[scr].score.pieces++; + { + Players[scr].curShape = Players[scr].nextShape; + Players[scr].nextShape = shape; } - 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); + Players[scr].curY = Players[scr].boardVisible + 4; + Players[scr].curX = Players[scr].boardWidth / 2 - 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(Players[scr].curShape, scr, + Players[scr].curY, Players[scr].curX, scr == me); + return 1; +} + +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; +} + +void StartGame(void) +{ //init new game + int i; + + 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 + SetITimer(Game.speed, Game.speed); + Players[me].nextShape = ChooseOption(stdOptions); + for (i = 1; i <= maxPlayer; i++) { + Players[i].score.score = Players[i].score.lines + = Players[i].score.adds = 0; + Players[i].score.pieces = -1; + ClearField(i); + } //reset all players + InitFields(); +} + +void CheckClears(int scr) +{ //check for full lines + int linesCleared; + int linevalues[] = { 40, 100, 400, 1200, }; //= 50*lines! - 10*(lines==1) +// int linevaluesq[] = { 25, 50, 100, 200, 500, 720, 980, 1280, 1620, 2000, +// 2420, 2880, 3380, 3920, 4500, 5120, 5780, 6480 }; + int linevaluesq[] = { 20, 50, 100, 200, 500, 750, 1000, 1250, 1500, 2000, + 2500, 3000, 3500, 4000, 4500, 5000, 6000, 7500 }; + + if ((linesCleared = ClearFullLines(scr)) > 0) { + 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 += Game.gravity + ? linevaluesq[linesCleared - 1] : linevalues[linesCleared - 1]; + Players[scr].score.lines += linesCleared; + Players[scr].score.adds += linesCleared - (linesCleared < 4); + if (scr == me) { + if (game == GT_classicTwo) { + SendPacket(scr, NP_clear, 0, NULL); + if (linesCleared > 1) { + short junkLines; + netint4 data[1]; + + junkLines = linesCleared - (Game.gravity ? 1 : linesCleared < 4); + data[0] = junkLines; + SendPacket(me, NP_giveJunk, sizeof(data), data); + Message("\\%dYou send %d lines", + Players[me].team > 7 ? 7 : Players[me].team, junkLines); + } //send junk to others + } //multiplayer + else { + Message("\\%dYou cleared %d lines", + Players[me].team > 7 ? 7 : Players[me].team, linesCleared); + } //singleplayer + } //IT'S YOU + } //lines cleared +} + +void OneGame(void) +{ + int changed = 0; + short gameStatus = 2; //2=loop; 1=new piece; 0=quit + int dropMode = 0; + int chatMode = 0; + char chatText[MSG_WIDTH] = "\0"; + + void GameKey(char key) + { + char *p; + + if (chatMode) { + if (key == 13) { + // enter text + chatMode = 0; + if (chatText[0]) { + Message("<\\%d%s\\7> %s", + Players[me].team > 7 ? 7 : Players[me].team, + Players[me].name, chatText); + if (game == GT_classicTwo) + SendPacket(me, NP_msg, strlen(chatText) + 1, chatText); + memset(chatText, 0, sizeof(chatText)); + } //say it + else Messagetype(27, -1, NULL); //escape + return; + } + else if (key == 27) //escape + chatMode = 0; + else if (key == 127 && chatText) //backspace + chatText[strlen(chatText) - 1] = 0; + else if (strlen(chatText) < MSG_WIDTH-1) //text + chatText[strlen(chatText)] = key; + Messagetype(key, strlen(chatText) - 1, chatText); + return; + } //key in chat mode + + if (key == 13) { + chatMode = 1; + Messagetype(key, strlen(chatText) - 1, chatText); } - for (;;) { - changed = RefreshBoard(scr) || changed; - if (spying) - changed = RefreshBoard(scr2) || changed; + + if (!(p = strchr(keyTable, tolower(key)))) return; + key = p - keyTable; + if (Players[me].alive <= 0 && key != KT_quit) return; + if (paused && key < KT_pause) return; + switch (key) { + case KT_left: + if (MovePiece(me, 0, -1) && spied) SendPacket(me, NP_left, 0, NULL); + break; + case KT_right: + if (MovePiece(me, 0, 1) && spied) SendPacket(me, NP_right, 0, NULL); + break; + case KT_rotleft: + if (RotatePiece(me, -1) && spied) SendPacket(me, NP_rotleft, 0, NULL); + break; + case KT_rotright: + if (RotatePiece(me, 1) && spied) SendPacket(me, NP_rotright, 0, NULL); + break; + case KT_down: + SetITimer(Game.speed, Game.speed); + if (MovePiece(me, -1, 0)) { + if (spied) SendPacket(me, NP_down, 0, NULL); + } //move one down + else + gameStatus = 1; //completely dropped + break; + case KT_drop: + SetITimer(Game.speed, Game.speed); + if (DropPiece(me)) { + if (spied) SendPacket(me, NP_drop, 0, NULL); + if (!Sets.dropmode) gameStatus = 1; //instadrop + } + else gameStatus = 1; //dropped + dropMode = Sets.dropmode > 1; + break; + case KT_faster: + if (game != GT_onePlayer) break; + 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) + Message(Players[me].flags & SCF_paused + ? "You paused the game" : "You unpaused the game"); + else + Message(Players[me].flags & SCF_paused + ? "You are not ready" : "You are ready"); + checkPaused(); + if (game == GT_classicTwo) + SendPacket(me, NP_pause, 0, NULL); + ShowPause(me); + changed = 1; + break; + case KT_redraw: + clear(); + InitFields(); +// ScheduleFullRedraw(); + refresh(); + break; + case KT_quit: + ShowPause(me); + refresh(); + gameStatus = 0; + break; + } //E_key + if (dropMode && DropPiece(me) > 0) { + SetITimer(Game.speed, Game.speed); + if (spied) SendPacket(me, NP_drop, 0, NULL); + } + return; + } //GameKey + + int oldPaused = 0; + + void GameNet(_netEvent net) + { + switch(net.type) { + case NP_newPiece: + { + memcpy(&Players[net.uid].nextShape, net.data, + sizeof(Players[0].nextShape)); + StartNewPiece(net.uid, Players[net.uid].curShape); + break; + } + case NP_down: + MovePiece(net.uid, -1, 0); + break; + case NP_left: + MovePiece(net.uid, 0, -1); + break; + case NP_right: + MovePiece(net.uid, 0, 1); + break; + case NP_rotleft: + RotatePiece(net.uid, -1); + break; + case NP_rotright: + RotatePiece(net.uid, 1); + break; + case NP_drop: + DropPiece(net.uid); + break; + case NP_clear: + CheckClears(net.uid); + break; + case NP_insertJunk: + { + netint4 data[3]; + + memcpy(data, net.data, sizeof(data)); + InsertJunk(net.uid, Players[data[2]].team, data[0], data[1]); + break; + } //player added junklines + case NP_giveJunk: + { + netint4 data[3]; + short column; + + if (Players[me].alive <= 0) break; + memcpy(data, net.data, sizeof(data[0])); + column = Random(0, Players[me].boardWidth); + Message("\\%d%s sends %d lines", + Players[net.uid].team > 7 ? 7 : Players[net.uid].team, + Players[net.uid].name, data[0]); + lastadd = net.uid; + InsertJunk(me, Players[net.uid].team, data[0], column); + if (spied) { + data[1] = column; + data[2] = net.uid; + SendPacket(me, NP_insertJunk, sizeof(data), data); + } //show changes to others + break; + } //receive junklines + case NP_msg: + { + Message("<\\%d%s\\7> %s", + Players[net.uid].team > 7 ? 7 : Players[net.uid].team, + Players[net.uid].name, net.data, net.type); + break; + } //chat + case NP_start: + { + int i; + + Game.started = 2; + paused = 0; + Message("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) { + int winner; + float timer; + int i; + + Message("The game has ended"); + timer = CurTimeval() / 1e6; + if (timer > 5) { + for (i = MAX_SCREENS-1; i > 0; i--) if (Players[i].alive >= 0) { + Message("\\%d%10s%6.1fp%5.1fa", + Players[i].team > 7 ? 7 : Players[i].team, Players[i].name, + Players[i].score.pieces / timer * 60, + Players[i].score.adds / timer * 60); + if (Players[i].alive > 0) winner = i; + } //show player stats + if (winner) + Message("%s won after %0.0f'%02d\"", + Players[winner].name, timer / 60, (int)timer % 60); + } //show game stats + Message(NULL); + } //game was playing + Game.started = 0; + memcpy(&Game.seed, net.data, net.size); + { + int i; + + 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; + gameStatus = 1; + break; + } //stop game + case NP_newPlayer: + { + char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple", + "Red", "Grey", "White", "*Orange" }; + + if (net.uid>maxPlayer) maxPlayer = net.uid; + memcpy(&Players[net.uid], net.data, net.size); + ClearField(net.uid); + InitFields(); + if (Players[net.uid].team > 7) + Message("%s joined the game", Players[net.uid].name); + else + Message("%s joined %s team", Players[net.uid].name, + teams[Players[net.uid].team]); + if (Players[net.uid].flags & SCF_paused) { + checkPaused(); + } //player has paused +// DrawField(net.uid); +// ShowPause(net.uid); + changed = 1; + break; + } //player joined + case NP_pause: + { + char s[20]; + + Players[net.uid].flags ^= SCF_paused; + if (Game.started > 1) + strcpy(s, Players[net.uid].flags&SCF_paused + ? "paused the game" : "unpaused the game"); + else + strcpy(s, Players[net.uid].flags&SCF_paused + ? "is not ready" : "is ready"); + Message("%s %s", Players[net.uid].name, s); + checkPaused(); + ShowPause(net.uid); + changed = 1; + break; + } //(un)pause + case NP_part: + // player left + checkPaused(); + oldPaused = 0; + Players[net.uid].alive = -1; + Message("%s left", Players[net.uid].name); + checkPaused(); + ShowPause(net.uid); + changed = 1; + break; + case NP_argghhh: + { + char i; + memcpy(&i, net.data, sizeof(i)); + Players[net.uid].alive = 0; + if (i == me) + Message("\\%dYou fragged %s", + Players[me].team > 7 ? 7 : Players[me].team, Players[net.uid].name); + else if (i == net.uid) + Message("\\%d%s died", + Players[i].team > 7 ? 7 : Players[i].team, Players[i].name); + else + Message("\\%d%s fragged %s", + Players[i].team > 7 ? 7 : Players[i].team, Players[i].name, + Players[net.uid].name); + checkPaused(); + ShowPause(net.uid); + changed = 1; + break; + } //G/O + default: + break; + } //E_net + } //GameNet + + MyEvent event; + long pauseTimeLeft; + int i; + + StartGame(); + while (gameStatus) { +GameLoop: + gameStatus = 2; + if (Players[me].alive > 0) { + if (!StartNewPiece(me, ChooseOption(stdOptions))) { + netint4 data[4]; + Players[me].alive = 0; + if (lastadd == me) Message("\\%dYou died", + Players[me].team > 7 ? 7 : Players[me].team); + else Message("\\%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 (spied) { + SendPacket(me, NP_newPiece, sizeof(Players[me].curShape), &Players[me].curShape); + } //send new piece + } + } //new piece + while (gameStatus == 2) { + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive > 0 && PlayerDisp[i]) + changed |= RefreshBoard(i); if (changed) { - RefreshScreen(); + if (!paused) ShowTime(); + refresh(); changed = 0; + } //screen update + { + short playercount = 0; + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive >= 0) playercount++; + if (playercount < 1) gameStatus = 0; } - CheckNetConn(); switch (WaitMyEvent(&event, EM_any)) { - case E_alarm: - if (!MovePiece(scr, -1, 0)) - goto nextPiece; - else if (spied) - SendPacket(NP_down, 0, NULL); - break; - case E_key: - p = strchr(keyTable, tolower(event.u.key)); - key = p - keyTable; - if (robotEnable) { - RobotCmd(1, "UserKey %d %s\n", - (int)(unsigned char)event.u.key, - p ? keyNames[key] : "?"); - break; - } - if (!p) - break; - keyEvent: - if (paused && (key != KT_pause) && (key != KT_redraw)) - break; - switch(key) { - case KT_left: - if (MovePiece(scr, 0, -1) && spied) - SendPacket(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); - break; - case KT_down: - if (MovePiece(scr, -1, 0) && spied) - SendPacket(NP_down, 0, NULL); - break; - case KT_toggleSpy: - spying = (!spying) && (scr2 >= 0); - break; - case KT_drop: - if (DropPiece(scr) > 0) { - if (spied) - SendPacket(NP_drop, 0, NULL); - SetITimer(speed, speed); - } - dropMode = dropModeEnable; - break; - case KT_pause: - pausedByMe = !pausedByMe; - if (game == GT_classicTwo) { - netint2 data[1]; - - data[0] = hton2(pausedByMe); - SendPacket(NP_pause, sizeof(data), data); - } - paused = pausedByMe || pausedByThem; - if (robotEnable) - RobotCmd(1, "Pause %d %d\n", pausedByMe, - pausedByThem); - ShowPause(pausedByMe, pausedByThem); - changed = 1; - break; - case KT_faster: - if (game != GT_onePlayer) - break; - speed = speed * 0.8; - SetITimer(speed, SetITimer(0, 0)); - ShowDisplayInfo(); - changed = 1; - break; - case KT_redraw: - ScheduleFullRedraw(); - if (paused) - RefreshScreen(); - break; - } - if (dropMode && DropPiece(scr) > 0) { - if (spied) - SendPacket(NP_drop, 0, NULL); - SetITimer(speed, speed); - } - break; - case E_robot: - { - int num; - - cmd = event.u.robot.data; - if ((p = strchr(cmd, ' '))) - *p++ = 0; + case E_alarm: + if (!paused && Players[me].alive > 0) + if (!MovePiece(me, -1, 0)) //move down + gameStatus = 1; //new piece else - p = cmd + strlen(cmd); - for (key = 0; keyNames[key]; ++key) - if (!strcmp(keyNames[key], cmd) && - (fairRobot || (1 == sscanf(p, "%d", &num) && - num == pieceCount))) - goto keyEvent; - if (!strcmp(cmd, "Message")) { - Message(p); - changed = 1; - } - break; - } - 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); - memcpy(data, event.u.net.data, sizeof(data)); - shapeNum = ntoh2(data[0]); - StartNewPiece(scr2, NetNumToShape(shapeNum)); - break; - } - case NP_down: - MovePiece(scr2, -1, 0); - break; - case NP_left: - MovePiece(scr2, 0, -1); - break; - case NP_right: - MovePiece(scr2, 0, 1); - break; - case NP_rotate: - RotatePiece(scr2); - break; - case NP_drop: - DropPiece(scr2); - break; - case NP_clear: - ClearFullLines(scr2); - break; - case NP_insertJunk: - { - netint2 data[2]; - - memcpy(data, event.u.net.data, sizeof(data)); - InsertJunk(scr2, ntoh2(data[0]), ntoh2(data[1])); - break; - } - 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); - changed = 1; - break; - } - default: - break; - } - break; - case E_lostRobot: - case E_lostConn: - goto gameOver; - default: - break; - } + if (spied) SendPacket(me, NP_down, 0, NULL); + break; + case E_key: + GameKey(event.u.key); + break; + case E_net: + GameNet(event.u.net); + break; + case E_lostConn: + goto gameOver; + } //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; - } - } - nextPiece: + } //(un)pause + } //game loop dropMode = 0; - FreezePiece(scr); - linesCleared = ClearFullLines(scr); - if (linesCleared > 0 && spied) - SendPacket(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); - } - } + Players[me].score.score++; + CheckClears(me); + } //new piece loop gameOver: SetITimer(0, 0); } -ExtFunc int main(int argc, char **argv) +int main(int argc, char **argv) { - int initConn = 0, waitConn = 0, ch; - char *hostStr = NULL, *portStr = NULL; + char ch; - standoutEnable = 1; - stepDownInterval = DEFAULT_INTERVAL; + game = GT_onePlayer; + port = DEFAULT_PORT; + maxPlayer = 1; + Game.initspeed = DEFAULT_INTERVAL; + Game.gravity = 0; 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 = 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; + Players[0].dropmode = 0; + } //set defaults + +// if (getopt(argc, argv, "f:") == 'f') +// ReadConf(optarg); +// else + ReadConf(CONFIG_FILE); + while ((ch = getopt_long( + argc, argv, "hHRk:c:n: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(); - 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; + InitScreens(); //setup screen - 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); - } + if (game == GT_classicTwo) { + spied = 1; + InitiateConnection(hostStr, port); + HandShake(); + maxPlayer = me; + checkPaused(); + OneGame(); + } //client else { - game = GT_onePlayer; - OneGame(0, -1); - } + Game.seed = time(0); + Game.started = 2; + me = 1; + memcpy(&Players[me], &Players[0], sizeof(_Player)); + Players[me].team = 7; + OneGame(); + } //singleplay return 0; } -/* - * vi: ts=4 ai - * vim: noai si - */