unofficial version 0.7.2: mainly sync/reset fixes v0.7.2
authorMischa POSLAWSKY <netris@shiar.org>
Sun, 25 Aug 2002 20:17:00 +0000 (22:17 +0200)
committerMischa POSLAWSKY <netris@shiar.org>
Tue, 27 Feb 2007 05:11:32 +0000 (06:11 +0100)
CHANGES
TODO
curses.c
game.c
inet.c
netris.h
server.c

diff --git a/CHANGES b/CHANGES
index be0fa70c3a554da34a6b52be774539d09a9dd2c4..be5e370f5a02c9067bfcc64e5661f9649dc6c8f1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
  -- v0.7.819 ------
 
  * shadow piece (preview current piece dropped down)
+ * new players' fields are cleared at start
  * players are now 'fragged' by the player last adding them lines
  * ^ when that last player was himself(m/f) (s)he just 'died'
  * 'Close connection' message no longer displayed
  * players in teams are displayed in their teamcolor
 
+ -- v0.7.820
+
+ * server doesn't quit, but just stops game when 1 player/team left
+ * when a game stops, all players are paused and their fields reset
+ * server handles disconnecting clients correctly again
+ * 'player quit' displayed when a client disconnects from server
+ * game ended messages not displayed when a game was ready but not yet started
+ * server sends new game seed at game stop
+ * players' scores and (next) pieces and stuff are reset at new game
+ * scores are erased instead of not drawn (apm/ppm remained at new game)
+
+ -- v0.7.821
+
+ * colorcoding altered a bit (server messages white, player stuff colored)
+ * when no team specified, server assigns a team and sends it to player
+ * client displays teamname of joining players
+ * client disconnects also transmitted to g/o players
+ * lag could delay changes to another game, desyncing clients
+   now game info is not transmitted when game has stopped
+
 ------------------------------------------------------------------------------
diff --git a/TODO b/TODO
index 3696e06a5969401b73ac99859a8a55cc63fc6a83..819dfceec97ee2f1c457e3dd738188eb7acaa155 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,37 +1,81 @@
+ * check out quadra gravity: single block over multiplayer junkhole
+
 ---- near-future: ------------------------------------------------------------
 
- * everybody in a team
- * teams are colored
- * server never quits
- * 'you won' message, remove 'close connection' echo
- * (check if commandprompt is below game)
+ * correct cursorposition at quit
  * transmit player fields of game in progress to new player
        * server has to maintain copy of player fields
- * empty new player's field (in case of recycle)
  * completely fix redraw
  * redraw on window resize
  * message position/size
  * allow custom nicks
+ * server should deny duplicate nicks
  * move piece when unable to rotate at screenedge
+ * display total frags for players (by server?)
+ * spacebar toggles ready as well
 
 
 ---- asap: -------------------------------------------------------------------
 
+ * quadra-style gravity option
+       * pieces stored as bitmaps
+       * blocks in shape stick together horizontally
+ * different key procedure? (allowing for multiple keys simoultaniously?)
+ * player messages (caps toggles typing mode?)
+       * commands (/team)
  * observers (join as g/o player)
  * fix -f
  * half width enemy fields if out of screen space
  * fix bot
  * multiplayer stats
  * time-based singleplayer leveling?
- * shapes stored as bitmap, rotate by modifying for
+ * shapes stored as bitmap, rotate by modifying for (should be smaller)
 
 
 ---- distant future: ---------------------------------------------------------
 
  * horizontally _and_ vertically resize enemy fields
+ * server can add lines after specified time
+ * sounds
+ * line clear animations (flash)
+ * multiple next pieces
  * special blocks
- * tetrinet compatible?
+       * inventory
+       * player keys
+       * delete key?
+       * blocks+actions
+               * tetrinet:
+                       * a: add (junk)line
+                       * b: remove specials on field
+                       * c: clear (bottom) line
+                       * g: gravity (move all blocks down)
+                       * n: nuke field
+                       * o: block bomb (blocks around any bombs on field are moved)
+                       * q: quake (shift lines left or right)
+                       * r: remove 10 blocks at random
+                       * s: swap fields
+               * suggested:
+                       * d: donate (next inv block given to other player)
+                       * f: flip (symetric vertical inversion)
+                       * h: hide (replaces inventory blocks by ?)
+                                       (one block restored per line added?)
+                       * l: lower (all specials from field going down (g))
+                       * p: purge (half remove special blocks from inventory)
+                       * t: take (take 2 specials from target player field)
+                       * ?: mystery (block only revealed in inventory)
+               * tetrinet 2:
+                       * d: darkness (temporarily blackens your field except
+                                       around current piece)
+                       * f: confusion (temporarily rearranges controls)
+                       * i: attack immunity (invincible to attacks)
+                       * m: mutated pieces (gives several difficult pieces)
+                       * v: clear column (erases vertical line)
+               * ideas:
+                       * x: seperate blocks (cut all shared pieces in quadra)
+ * quadra compatible?
+ * tetrinet compatible? (prolly not)
  * remove bot delay (make it humanplayer-like)
  * new+better bot?
- * replay ability? (tspec replay compatible?)
+ * ipv6
+ * replay ability? (tspec replay or quadra rec compatible?)
 
index 030ed25ceb1d7958e1033782ddc0b9fc54cb8181..8d500d9528da4dd41fb945cd12062d09d1eea113 100644 (file)
--- a/curses.c
+++ b/curses.c
@@ -242,7 +242,12 @@ ExtFunc void DrawField(int scr)
                } //add robot indicator
        } //display playername/host
 
-       // draw blocks (which is usually just clear field)
+       {
+               int x, y;
+               for (y = 0; y <= Players[scr].boardVisible; y++)
+                       for (x = 0; x <= Players[scr].boardWidth; x++)
+                               PlotBlock(scr, y, x, GetBlock(scr, y, x));
+       } //draw field
 
        ShowPause(scr);
 } //DrawField
@@ -342,19 +347,6 @@ ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
          PlotBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
 } //PlotBlock
 
-ExtFunc void PlotShadowBlock1(int scr, int y, int x, BlockType type)
-{
-       move(y, x);
-       if (type == BT_none) addstr("  ");
-       else addstr("::");
-} //PlotShadowBlock1
-ExtFunc void PlotShadowBlock(int scr, int y, int x, BlockType type)
-{
-       if (y >= 0 && y < Players[scr].boardVisible &&
-               x >= 0 && x < Players[scr].boardWidth)
-         PlotShadowBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
-} //PlotShadowBlock
-
 ExtFunc void PlotBlockS1(int scr, int y, int x, BlockType type)
 { //DOESN"T WORK YET...
        move(y, x);
@@ -402,7 +394,12 @@ ExtFunc void ShowScore(int scr, struct _Score score)
                                "yield    %3d%%", 100 * score.adds / score.lines);
                        mvprintw(10, statusXPos, "apm %9.1f", score.adds * 60 / timer);
                }
-       }
+       } //display [ap]pm
+       else {
+               int i;
+               for (i = 7; i <= 10; i++)
+                       mvaddstr(i, statusXPos, "             ");
+       } //too early to display stats, remove old..
 } //ShowScore
 
 ExtFunc void FieldMessage(int playa, char *message)
diff --git a/game.c b/game.c
index b88e05d2f789199bbf24cad58cd98a3c19453220..de0d605cfcdd0ee12648629d3548e1bd3c7224fc 100644 (file)
--- a/game.c
+++ b/game.c
@@ -61,6 +61,7 @@ static char keyTable[KT_numKeys+1];
 
 static char *hostStr;
 static int paused = 0;
+static char lastadd;
 
 static sigjmp_buf close_env;
 
@@ -245,17 +246,34 @@ ExtFunc void checkPaused(void)
        int i;
 
        paused = Game.started < 1;
-       for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive)
+       for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive > 0)
                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 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;
@@ -267,47 +285,41 @@ ExtFunc void OneGame(void)
        int key;
        char *p, *cmd;
        int playercount;
-       char lastadd;
        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;
 
-       maxPlayer = lastadd = me;
-       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
-       ClearField(me);
-       InitFields();
-       SetITimer(Game.speed, Game.speed);
+       StartGame();
        if (robotEnable) {
                int counter;
                RobotCmd(0, "GameType %s\n", gameNames[game]);
                RobotCmd(0, "BoardSize 0 %d %d\n",
                        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",
-                               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++;
-               }
+               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();
        }
-       Players[me].nextShape = ChooseOption(stdOptions);
        while (1) {
-               if (Players[me].alive) {
+GameLoop:
+               if (Players[me].alive > 0) {
                        if (!StartNewPiece(me, ChooseOption(stdOptions))) {
                                        netint4 data[4];
                                Players[me].alive = 0;
-                               if (lastadd == me) Messagef("You died");
+                               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);
@@ -332,7 +344,7 @@ ExtFunc void OneGame(void)
                } //new piece
                while (1) {
                        for (i = 1; i < MAX_SCREENS; i++)
-                               if (Players[i].alive && Players[i].spy)
+                               if (Players[i].alive > 0 && Players[i].spy)
                                        changed |= RefreshBoard(i);
                        if (changed) {
                                if (!paused) ShowTime();
@@ -341,18 +353,19 @@ ExtFunc void OneGame(void)
                        } //screen update
                        playercount = 0;
                        for (i = 1; i < MAX_SCREENS; i++)
-                               if (Players[i].alive) playercount++;
+                               if (Players[i].alive >= 0) playercount++;
                        if (playercount < 1) goto gameOver;
                        CheckNetConn();
                        switch (WaitMyEvent(&event, EM_any)) {
                                case E_alarm:
-                                       if (!paused && Players[me].alive)
+                                       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) {
@@ -363,7 +376,7 @@ ExtFunc void OneGame(void)
                                        } //let robot handle keypress
                                        if (!p) break;
                                keyEvent:
-                                       if (!Players[me].alive && key != KT_quit) break;
+                                       if (Players[me].alive <= 0 && key != KT_quit) break;
                                        if (paused && key < KT_pause) break;
                                        switch(key) {
                                                case KT_left:
@@ -429,7 +442,7 @@ ExtFunc void OneGame(void)
                                                        InitFields();
 //                                                     ScheduleFullRedraw();
                                                        for (i = 1; i < MAX_SCREENS; i++)
-                                                               if (Players[i].alive && Players[i].spy)
+                                                               if (Players[i].spy && Players[i].alive > 0)
                                                                        RefreshBoard(i);
                                                        refresh();
                                                        break;
@@ -513,7 +526,7 @@ ExtFunc void OneGame(void)
                                                        netint2 data[2];
                                                        short column;
 
-                                                       if (!Players[me].alive) break;
+                                                       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);
@@ -530,10 +543,32 @@ ExtFunc void OneGame(void)
                                                } //receive junklines
                                                case NP_start:
                                                {
-                                                       Game.started = 1;
-                                                       checkPaused();
+                                                       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)
@@ -541,10 +576,13 @@ ExtFunc void OneGame(void)
                                                        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].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)
@@ -567,10 +605,8 @@ ExtFunc void OneGame(void)
                                                        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,
+                                                                       ? "is not ready" : "is ready");
+                                                       Messagef("%s %s",
                                                                Players[event.u.net.uid].name, s);
                                                        checkPaused();
                                                        if (robotEnable) RobotCmd(1, "Pause %d\n", paused);
@@ -578,12 +614,25 @@ ExtFunc void OneGame(void)
                                                        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("You fragged %s",
+                                                       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",
@@ -647,7 +696,8 @@ ExtFunc void OneGame(void)
                        junkLines = linesCleared - (linesCleared < 4);
                        data[0] = hton2(junkLines);
                        SendPacket(me, NP_giveJunk, sizeof(data), data);
-                       Messagef("You sent %d lines", junkLines);
+                       Messagef("\\%dYou sent %d lines",
+                               Players[me].team > 7 ? 7 : Players[me].team, junkLines);
                } //send junk to others
        } //new piece loop
 gameOver:
@@ -672,11 +722,13 @@ ExtFunc int main(int argc, char **argv)
                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 (!(userName = getenv("LOGNAME")) || !userName[0])
                        if (!(userName = getenv("USER")) || !userName[0])
@@ -701,7 +753,6 @@ ExtFunc int main(int argc, char **argv)
                fatal("You can't use the -F option without the -r option");
 //     WriteConf();
 
-       SRandom(time(0));                       //randomize
        if (sigsetjmp(close_env, 1))
                exit(0);
        signal(SIGINT, CatchInt);       //handle exit (^C)
@@ -717,6 +768,7 @@ ExtFunc int main(int argc, char **argv)
        } //client
        else {
                game = GT_onePlayer;
+               Game.seed = time(0);
                Game.started = 2;
                Game.maxplayers = 1;
                me = 1;
diff --git a/inet.c b/inet.c
index 2caca525b91fb3c6b336cf6bc41868186c6c5c60..1549aa0b388b44c8c7b0c7a3d20e5133732649ce 100644 (file)
--- a/inet.c
+++ b/inet.c
@@ -91,6 +91,12 @@ ExtFunc void HandShake(void)
                                        &Players[me]);
                                break;
                        }
+                       case NP_team:
+                       { //receive your teamnumber
+                               memcpy(&Players[event.u.net.uid].team, event.u.net.data,
+                                       event.u.net.size);
+                               break;
+                       } //NP_team
                        case NP_gamedata:
                        {
                                static struct {
@@ -104,16 +110,16 @@ ExtFunc void HandShake(void)
 
                                memcpy(&data, event.u.net.data, event.u.net.size);
                                memcpy(&Players[me].flags, &data, sizeof(data.playerflags));
+                               memcpy(&Players[me].flags, &data, sizeof(data.playerflags));
                                memcpy(&Game, &data.maxplayers,
                                        sizeof(data) - sizeof(data.playerflags));
-                               SRandom(Game.seed);
                                break;
-                       }
+                       } //NP_gamedata
                        case NP_error:
                        {
                                fprintf(stderr, "Rejected by server: %s\n", event.u.net.data);
                                exit(1);
-                       }
+                       } //NP_error
                        default:
                                break;
                }
index 7bbfc3ce3fe25fda603f08c7f5b6579dcfd9f16b..a361c2fd489ebe92d871713317798f976edd9c10 100644 (file)
--- a/netris.h
+++ b/netris.h
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <signal.h>
 
-#define version_string         "0.7.819"
+#define version_string         "0.7.821"
 
 #define ExtFunc                /* Marks functions that need prototypes */
 
@@ -106,7 +106,9 @@ typedef enum _NetPacketType {
        NP_pause,               //player (un)pauses
        NP_stop,                //game ended
        NP_newPlayer,   //add new player
+       NP_team,                //player switched teams
        NP_argghhh,             //player died
+       NP_part,                //player left
 
        NP_newPiece,    //new piece info
        NP_rotright,    //rotate piece clockwise
index f67721f6eb3019366f229df40e20b4e9721b0240..6fe46f0c49f25c72c63ec8b54c37d1728481d26f 100644 (file)
--- a/server.c
+++ b/server.c
@@ -49,7 +49,7 @@ static struct option options[] = {
 };
 
 static char minplayers = 2;
-static char countPlayers = 0;
+static char playercount;
 static char verbose = 0;
 
 struct sockaddr_in addr;
@@ -166,8 +166,10 @@ ExtFunc void SCloseNet(short playa)
        MyEvent event;
 
        if (netGen[playa].fd >= 0) {
-               SendPacketTo(playa, 0, NP_endConn, 0, NULL);
-               do{} while (WaitMyEvent(&event, EM_net) != E_lostConn);
+               if (Players[playa].alive >= 0) {
+                       SendPacketTo(playa, 0, NP_endConn, 0, NULL);
+                       do{} while (WaitMyEvent(&event, EM_net) != E_lostConn);
+               } //say bye to player
                close(netGen[playa].fd);
                netGen[playa].fd = -1;
        }
@@ -313,22 +315,38 @@ static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event)
        return E_connect;
 } //ConnGenFunc
 
+ExtFunc void CountPlayers(void)
+{ //count number of players/teams
+       int i, j;
+       playercount = 0;
+       for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive > 0) {
+               if (Players[i].team < 128) for (j = 1; j < i; j++)
+                       if (Players[j].alive > 0 && (Players[j].team == Players[i].team)) {
+                               playercount--;
+                               break;
+                       } //player of same team counted before
+               playercount++;
+       } //player alive
+} //CountPlayers
+
 ExtFunc int StartServer(void)
 {
        MyEvent event;
        netint2 currentpiece[MAX_SCREENS];
-       int playercount;
        int playersReady = 0;
+       int paused = 1;
        int i;
+       char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple",
+                                                       "Red", "Grey", "White", "*Orange" };
 
        do {
                switch (WaitMyEvent(&event, EM_any)) {
                        case E_lostConn: //client went away :(
-                               Players[event.u.net.sender].alive = 0;
+                               Players[event.u.net.sender].alive = -1;
                                for (i = 1; i < MAX_SCREENS; i++)
-                                       if (Players[i].alive)
+                                       if (Players[i].alive >= 0)
                                                SendPacketTo(i, event.u.net.sender,
-                                                       NP_argghhh, sizeof(Players[0].alive),
+                                                       NP_part, sizeof(Players[0].alive),
                                                        &Players[event.u.net.sender].alive);
                                SCloseNet(event.u.net.sender);
                                break; //NP_endConn
@@ -366,14 +384,20 @@ ExtFunc int StartServer(void)
                                        //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)
+                                               if (Players[event.u.net.sender].team < 1
+                                               || Players[event.u.net.sender].team > 7) {
                                                        Players[event.u.net.sender].team =
-                                                               256 - event.u.net.sender;
+                                                               event.u.net.sender % 7 + 1;
+                                                       SendPacketTo(event.u.net.sender,
+                                                               event.u.net.sender, NP_team,
+                                                               sizeof(Players[event.u.net.sender].team),
+                                                               &Players[event.u.net.sender].team);
+                                               } //invalid team
                                                if (Game.started < 2)
                                                        Players[event.u.net.sender].flags |= SCF_paused;
                                                if (!Game.continuous && Game.started >= 2) {
                                                        char data[40];
-                                                       strcpy(data,"Can't join: Game has already started");
+                                                       strcpy(data, "Can't join: Game has already started");
                                                        fprintf(stderr, "- Can't join player #%d in "
                                                                "non-continuous game\n", event.u.net.sender);
                                                        SendPacketTo(event.u.net.sender, 0, NP_error,
@@ -414,21 +438,22 @@ ExtFunc int StartServer(void)
                                                                        - sizeof(Players[0].small),
                                                                        &Players[event.u.net.sender]);
                                                        } //send (to) players
-                                               fprintf(stderr, "> Joined player #%d: %s <%s>\n",
+                                               fprintf(stderr, "> Joined player #%d: %s <%s> (%s)\n",
                                                        event.u.net.sender,
                                                        Players[event.u.net.sender].name,
-                                                       Players[event.u.net.sender].host);
+                                                       Players[event.u.net.sender].host,
+                                                       teams[Players[event.u.net.sender].team]);
                                                if (++playersReady >= minplayers) {
-                                                       if (Game.started)
+                                                       if (Game.started > 1)
                                                                SendPacketTo(event.u.net.sender, 0,
                                                                        NP_start, 0, NULL);
-                                                       else {
+/*                                                     else {
                                                                fprintf(stderr, "* Starting game (%010d)\n",
                                                                        Game.seed);
                                                                for (i = 1; i < MAX_SCREENS; i++)
                                                                        SendPacketTo(i, 0, NP_start, 0, NULL);
                                                                Game.started++;
-                                                       } //first goahead (to all)
+                                                       } //first goahead (to all)*/
                                                } //give go ahead
                                                break; //NP_playerdata
                                        case NP_newPiece:
@@ -442,18 +467,22 @@ ExtFunc int StartServer(void)
                                                //check for unpaused game
                                        case NP_pause:
                                        {
-                                               int paused;
                                                Players[event.u.net.sender].flags ^= SCF_paused;
                                                paused = Game.started < 1;
-                                               for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive)
-                                                       paused |= Players[i].flags & SCF_paused;
+                                               for (i = 1; i < MAX_SCREENS; i++)
+                                                       if (Players[i].alive > 0)
+                                                               paused |= Players[i].flags & SCF_paused;
+                                               fprintf(stderr, "* Player #%d (un)paused (pause=%d)\n",
+                                                       event.u.net.sender, paused);
                                                if (paused) paused = 1;
-                                               else if (Game.started == 1) Game.started++;
                                                goto sendtoall;
                                        } //NP_pause
                                        default: //relay data to all players
                                        sendtoall:
 //                                             if (event.u.net.type >= NP_pause)
+                                               if (event.u.net.type >= NP_rotright
+                                               && Game.started < 2)
+                                                       break;
                                                for (i = 1; i < MAX_SCREENS; i++)
                                                        if (i != event.u.net.sender)
                                                        if (event.u.net.type != NP_giveJunk ||
@@ -474,20 +503,36 @@ ExtFunc int StartServer(void)
                                break;
                        } //E_connect
                } //event
-               {
-                       int j;
-                       playercount = 0;
-                       for (i = 1; i < MAX_SCREENS; i++) if (Players[i].alive) {
-                               if (Players[i].team < 128) for (j = 1; j < i; j++)
-                                       if (Players[j].alive
-                                       && (Players[j].team == Players[i].team)) {
-                                               playercount--;
-                                               break;
-                                       } //player of same team counted before
-                               playercount++;
-                       } //player alive
-               } //count players
-       } while (Game.started < 2 || playercount > 1 || Game.continuous);
+               CountPlayers();
+               if (Game.started < 1) {
+                       if (playercount > 1) {
+                               fprintf(stderr, "* Game (%010d) ready to start\n", Game.seed);
+                               Game.started++;
+                       } //give goahead
+               } //game not yet started
+               else {
+                       if (playercount < 2) {
+                               fprintf(stderr, "* Stopping game\n");
+                               if (Game.seed) Game.seed++;
+                               if (Game.started > 1) for (i = 1; i < MAX_SCREENS; i++)
+                                       if (Players[i].alive >= 0) {
+                                               Players[i].alive = 1;
+                                               Players[i].flags |= SCF_paused;
+                                               SendPacketTo(i, 0, NP_stop,
+                                                       sizeof(Game.seed), &Game.seed);
+                                       } //transmit game stop and set players not ready
+                               paused = 1;
+                               Game.started = 0;
+                       } //too few players for game
+                       if (Game.started == 1 && !paused) {
+                               Game.started++;
+                               fprintf(stderr, "* Game starts\n");
+                               for (i = 1; i < MAX_SCREENS; i++)
+                                       if (Players[i].alive > 0)
+                                               SendPacketTo(i, 0, NP_start, 0, NULL);
+                       } //everybody ready to start
+               } //game (ready to) start(ed)
+       } while (1);
        fprintf(stderr, "* Exiting server\n");
 } //StartServer
 
@@ -639,6 +684,12 @@ ExtFunc int main(int argc, char **argv)
        Game.maxplayers = 8;
        Game.initspeed = DEFAULT_INTERVAL;
        Game.seed = time(0);
+       {
+               int i;
+
+               for (i = 1; i < MAX_SCREENS; i++)
+                       Players[i].alive = -1;
+       }
 
 //     if (getopt(argc, argv, "f:") == 'f')
 //             ReadConf(optarg);