X-Git-Url: http://git.shiar.net/netris.git/blobdiff_plain/e3d58186949bfcdb149cc2a545ce6c14a8689268..4f561019fc85c2817e3a72341397d1df32bc0868:/game.c diff --git a/game.c b/game.c index 87208fb..b88e05d 100644 --- a/game.c +++ b/game.c @@ -26,15 +26,15 @@ #include #include #include +#include static struct option options[] = { { "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' }, @@ -49,16 +49,21 @@ static struct option options[] = { }; 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; + +static sigjmp_buf close_env; + ExtFunc void MapKeys(char *newKeys) { @@ -121,7 +126,8 @@ ExtFunc void HandleOption(char tag, char *value) 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; @@ -131,6 +137,9 @@ ExtFunc void HandleOption(char tag, char *value) 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; @@ -138,9 +147,6 @@ ExtFunc void HandleOption(char tag, char *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; @@ -230,84 +236,121 @@ ExtFunc int StartNewPiece(int scr, Shape *shape) Players[scr].curY, Players[scr].curX)) return 0; PlotShape(Players[scr].curShape, scr, - Players[scr].curY, Players[scr].curX, 1); + Players[scr].curY, Players[scr].curX, 1, 1); return 1; } -ExtFunc void OneGame(int scr) +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) + paused |= Players[i].flags & SCF_paused; + if (paused) paused = 1; + else if (Game.started == 1) { + Game.started = 2; + Messagef("The game has started"); + for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive) + ShowPause(i); + } //everybody ready +} //checkPaused + +ExtFunc void OneGame(void) { MyEvent event; int linesCleared, changed = 0; - int spied = 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; + char lastadd; int linevalues[4] = { 40, 100, 400, 1200 }; //= 50*lines! - 10*(lines==1) int i; + maxPlayer = lastadd = me; Game.speed = Game.initspeed; - for (i = 1; i < Players[scr].score.level; i++) + for (i = 1; i < Players[me].score.level; i++) Game.speed /= SPEEDINC; if (Game.speed < SPEEDMINIMUM) Game.speed = SPEEDMINIMUM; - ResetBaseTime(); + ResetBaseTime(); //reset timer + ClearField(me); InitFields(); - for (i = 1; i <= totalPlayers + 1; i++) - if (Players[i].spy) DrawField(i); - if (totalPlayers > 0) { - spied = 1; - } - ShowDisplayInfo(); SetITimer(Game.speed, Game.speed); if (robotEnable) { + int counter; 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++) { + Players[me].boardVisible, Players[me].boardWidth); + for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive && i != me) { RobotCmd(0, "BoardSize %d %d %d\n", - i, Players[i].boardVisible, Players[i].boardWidth); + counter, Players[i].boardVisible, Players[i].boardWidth); RobotCmd(0, "Opponent %d %s %s\n", - i, Players[i].name, Players[i].host); + 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++; } RobotCmd(0, "TickLength %.3f\n", Game.speed / 1.0e6); RobotCmd(0, "BeginGame\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); - } - for (;;) { - changed = RefreshBoard(scr) || changed; - for (i = 1; i <= totalPlayers+1; i++) if (Players[i].spy && i != me) - changed = RefreshBoard(i) || changed; + Players[me].nextShape = ChooseOption(stdOptions); + while (1) { + if (Players[me].alive) { + if (!StartNewPiece(me, ChooseOption(stdOptions))) { + netint4 data[4]; + Players[me].alive = 0; + if (lastadd == me) Messagef("You died"); + 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 && Players[i].spy) + changed |= RefreshBoard(i); if (changed) { if (!paused) ShowTime(); refresh(); changed = 0; - } + } //screen update + playercount = 0; + for (i = 1; i < MAX_SCREENS; i++) + if (Players[i].alive) 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(scr, NP_down, 0, NULL); + if (!paused && Players[me].alive) + if (!MovePiece(me, -1, 0)) + goto nextPiece; + else if (spied) + SendPacket(me, NP_down, 0, NULL); break; case E_key: p = strchr(keyTable, tolower(event.u.key)); @@ -317,59 +360,43 @@ ExtFunc void OneGame(int scr) (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 && key != KT_quit) break; + if (paused && key < KT_pause) break; switch(key) { case KT_left: - if (MovePiece(scr, 0, -1) && spied) - SendPacket(scr, 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(scr, NP_right, 0, NULL); + if (MovePiece(me, 0, 1) && spied) + SendPacket(me, NP_right, 0, NULL); break; case KT_rotleft: - if (RotatePiece(scr, 0) && spied) - SendPacket(scr, NP_rotleft, 0, NULL); + if (RotatePiece(me, 0) && spied) + SendPacket(me, NP_rotleft, 0, NULL); break; case KT_rotright: - if (RotatePiece(scr, 1) && spied) - SendPacket(scr, NP_rotright, 0, NULL); + if (RotatePiece(me, 1) && spied) + SendPacket(me, NP_rotright, 0, NULL); break; case KT_down: SetITimer(Game.speed, Game.speed); - if (MovePiece(scr, -1, 0)) { - if (spied) SendPacket(scr, NP_down, 0, NULL); + if (MovePiece(me, -1, 0)) { + if (spied) SendPacket(me, NP_down, 0, NULL); } else goto nextPiece; break; case KT_drop: SetITimer(Game.speed, Game.speed); - if (DropPiece(scr)) { - if (spied) SendPacket(scr, NP_drop, 0, NULL); - if (Players[scr].dropmode == 2) goto nextPiece; + if (DropPiece(me)) { + if (spied) SendPacket(me, NP_drop, 0, NULL); + if (Players[me].dropmode == 2) goto nextPiece; } else goto nextPiece; - 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); - changed = 1; + dropMode = Players[me].dropmode; break; case KT_faster: if (game != GT_onePlayer) @@ -377,20 +404,44 @@ ExtFunc void OneGame(int scr) if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM) Game.speed = SPEEDMINIMUM; SetITimer(Game.speed, SetITimer(0, 0)); - Players[scr].score.level++; - ShowScore(scr, Players[scr].score); + 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].alive && Players[i].spy) + 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(scr, NP_drop, 0, NULL); + SendPacket(me, NP_drop, 0, NULL); } break; case E_robot: @@ -408,27 +459,13 @@ ExtFunc void OneGame(int scr) 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, Players[scr].boardWidth); - data[1] = hton2(column); - InsertJunk(scr, ntoh2(data[0]), column); - if (spied) - SendPacket(scr, NP_insertJunk, sizeof(data), data); -// Message("Opponent added %d lines"); - break; - } case NP_newPiece: { short shapeNum; @@ -437,9 +474,10 @@ ExtFunc void OneGame(int scr) FreezePiece(event.u.net.uid); memcpy(data, event.u.net.data, sizeof(data)); shapeNum = ntoh2(data[0]); - StartNewPiece(event.u.net.uid, NetNumToShape(shapeNum)); + StartNewPiece(event.u.net.uid, + NetNumToShape(shapeNum)); break; - } + } //new piece case NP_down: MovePiece(event.u.net.uid, -1, 0); break; @@ -466,33 +504,110 @@ ExtFunc void OneGame(int scr) netint2 data[2]; memcpy(data, event.u.net.data, sizeof(data)); - InsertJunk(event.u.net.uid, ntoh2(data[0]), ntoh2(data[1])); + InsertJunk(event.u.net.uid, ntoh2(data[0]), + ntoh2(data[1])); break; - } - case NP_pause: + } //player added junklines + case NP_giveJunk: { - netint2 data[1]; + netint2 data[2]; + short column; - 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); + if (!Players[me].alive) 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 = 1; + checkPaused(); + break; + } //start 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); + Messagef("\\%d%s joins the game", + Players[event.u.net.uid].team > 7 ? 7 + : Players[event.u.net.uid].team, + Players[event.u.net.uid].name); + 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: + { + char s[20]; + + 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 good to go"); + Messagef("\\%d%s %s", + Players[event.u.net.uid].team > 7 ? 7 + : Players[event.u.net.uid].team, + 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_argghhh: + { + char i; + memcpy(&i, event.u.net.data, sizeof(i)); + Players[event.u.net.uid].alive = 0; + if (i == me) Messagef("You fragged %s", + 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) { PauseTime(); @@ -503,27 +618,27 @@ ExtFunc void OneGame(int scr) ResumeTime(); } oldPaused = paused; - } - } + } //(un)pause + } //game loop nextPiece: dropMode = 0; - FreezePiece(scr); - Players[scr].score.drops++; - Players[scr].score.score++; - if ((linesCleared = ClearFullLines(scr)) > 0) { + FreezePiece(me); + Players[me].score.drops++; + Players[me].score.score++; + if ((linesCleared = ClearFullLines(me)) > 0) { if (game == GT_onePlayer) - if ((Players[scr].score.lines / 10) < - ((Players[scr].score.lines + linesCleared) / 10)) { + 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[scr].score.level++; + Players[me].score.level++; } //level up - Players[scr].score.score += linevalues[linesCleared]; - Players[scr].score.lines += linesCleared; - Players[scr].score.adds += linesCleared - (linesCleared < 4); + Players[me].score.score += linevalues[linesCleared - 1]; + Players[me].score.lines += linesCleared; + Players[me].score.adds += linesCleared - (linesCleared < 4); if (spied) - SendPacket(scr, NP_clear, 0, NULL); + SendPacket(me, NP_clear, 0, NULL); } if (game == GT_classicTwo && linesCleared > 1) { short junkLines; @@ -531,17 +646,24 @@ ExtFunc void OneGame(int scr) junkLines = linesCleared - (linesCleared < 4); data[0] = hton2(junkLines); - SendPacket(scr, NP_giveJunk, sizeof(data), data); - } - } + SendPacket(me, NP_giveJunk, sizeof(data), data); + Messagef("You sent %d lines", 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) { char ch; + port = DEFAULT_PORT; Game.standout = Game.color = 1; Game.initspeed = DEFAULT_INTERVAL; MapKeys(DEFAULT_KEYS); @@ -549,26 +671,27 @@ ExtFunc int main(int argc, char **argv) int i; char *userName; - for (i = 0; i <= MAX_SCREENS; i++) + for (i = 0; i < MAX_SCREENS; i++) { 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, "???"); + } 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"); - } + Players[0].alive = 1; + } //set defaults // 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) + "hHRr:Fk:c:odDSCap:i:l:t:", options, NULL)) != -1) HandleOption(ch, optarg); if (optind < argc) { Usage(); @@ -578,20 +701,27 @@ ExtFunc int main(int argc, char **argv) fatal("You can't use the -F option without the -r option"); // WriteConf(); - InitUtil(); - InitScreens(); + SRandom(time(0)); //randomize + if (sigsetjmp(close_env, 1)) + exit(0); + signal(SIGINT, CatchInt); //handle exit (^C) + InitScreens(); //setup screen + DrawTitle(); if (initConn) { game = GT_classicTwo; - InitiateConnection(hostStr, portStr); + spied = 1; + InitiateConnection(hostStr, port); HandShake(); - OneGame(me); + checkPaused(); + OneGame(); } //client else { game = GT_onePlayer; - totalPlayers = 0; + Game.started = 2; + Game.maxplayers = 1; me = 1; memcpy(&Players[me], &Players[0], sizeof(Player)); - OneGame(me); + OneGame(); } //singleplay return 0; }