unofficial version 0.8: chat, code cleanup v0.8
authorMischa POSLAWSKY <netris@shiar.org>
Sun, 27 Oct 2002 22:12:00 +0000 (23:12 +0100)
committerMischa POSLAWSKY <netris@shiar.org>
Tue, 27 Feb 2007 09:50:49 +0000 (10:50 +0100)
- robot removed
- shape handling reworked
  - greatly simplified: bitmap shapes instead of paths
    (removes need for shapes.c)
  - block boundaries (needed for gravity mode)
- buffer messages; multiplayer chat
- handle screen resize
- manual include headers; messages from include

23 files changed:
.gitignore
CHANGES
Configure
INSTALL [new file with mode: 0644]
TODO
board.c
board.h [new file with mode: 0644]
client.h [new file with mode: 0644]
curses.c
curses.h [new file with mode: 0644]
game.c
inet.c
inet.h [new file with mode: 0644]
msg.en.h [new file with mode: 0644]
netris.conf
netris.h
robot.c [deleted file]
robot_desc [deleted file]
server.c
shapes.c [deleted file]
sr.c [deleted file]
util.c
util.h [new file with mode: 0644]

index a7463487ef18d09a93b738c1febb9f468666f44f..7a8b84c94401f89cf51e1f199711c512c105e9fd 100644 (file)
@@ -1,10 +1,6 @@
 Makefile
 config.h
-proto.h
-proto.chg
-.depend
 version.c
 *.o
 netris
-server
-sr
+netrisserver
diff --git a/CHANGES b/CHANGES
index be5e370f5a02c9067bfcc64e5661f9649dc6c8f1..1455fab879481162611aca776bdd8dbe121f6b96 100644 (file)
--- a/CHANGES
+++ b/CHANGES
 
  * counts score (as in gameboy version)
  * reads default parameters from netris.conf (or other file specified with -f)
+
  -- v0.6.83 -------
 
  * conffile can have comments (#) and tabs instead of spaces
  * level up every 10 lines (speed x1.2)
+
  -- v0.6.84 -------
 
  * same handler for configfile/parameters
  * 'Close connection' message no longer displayed
  * players in teams are displayed in their teamcolor
 
- -- v0.7.820
+ -- 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
  * 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
+ -- 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
  * lag could delay changes to another game, desyncing clients
    now game info is not transmitted when game has stopped
 
+ -- v0.7.825 ------
+
+ * shapes are now stored as bitmaps, and slightly altered to match quadra
+ * extensive simplification of many routines because of this
+   (binary just ~1500 bytes smaller)
+ * next piece indicator aligns piece to the right
+ * blocks of a piece are grouped horizontally
+   displays 1 block as [], 2 blocks [[]], 3 blocks [[[]]], stick [[[[]]]]
+ * falling blocks not stored differently from frozen blocks
+   (might cause problems with robot, but i'll deal with that later)
+ * if piece can't be rotated (ie near the edge) it tries to slide it right
+ * fix multiplay transmission of (new) pieces
+ * field reset to 'empty' when player leaves (not 'ready')
+
+ -- v0.7.826 ------
+
+ * new pieces appear near middle again
+ * junklines have the color of the player/team that added them
+ * fix bug causing wrong number of junklines being sent after 1st game
+ * --nick parameter changes nick from default login name
+ * can turn field spying back on on redraw
+ * new messages on top, old messages scroll down
+
+ -- v0.7.828 ------
+
+ * server places unteamed players in first unused team
+ * fields are resized to half width if they don't fit on screen
+ * instadrop is default (as in $any::decent::tetris)
+ * dropmodes as options --slidedrop and --dropmode (-d and -D)
+
+ -- v0.7.830 ------
+
+ * shapes stick vertically as well (not physically visible yet though)
+ * quadra style gravity (shape falls down when possible)
+ * alternate scoring method used in gravity mode
+ * junklines stick horizontally so they don't drop into each other
+
+ -- v0.7.831 ------
+
+ * fix bugs in free blocks detection routine
+ * correct J stickiness
+ * players' names displayed in teamcolor
+ * correct Z stickiness, correct check below mask
+ * client reports winner+time and player stats (ppm+apm), calc client-side
+
+ -- v0.7.91 -------
+
+ * buffered message history, can be redrawn
+ * you can send messages, enter key toggles chat mode
+ * messages can contain multiple color tags
+ * in chat mode, backspace backspaces, escape cancels message
+
+ -- v0.7.96 -------
+
+ * field messages were slightly corrupted sometimes, somehow :P
+ * handler which redraws when window resizes :)
+
+ -- v0.7.A2 -------
+
+ * different source identing, tabs of 8 chars
+ * a couple of botcalls removed
+ * server switches quadra mode with --quadra parameter
+
+ -- v0.7.A5 -------
+
+ * all robot-stuff removed
+ * standard includefiles for each file instead of generated proto.h
+
+ -- v0.7.A19 ------
+
+ * Sets struct for settings
+ * dropmode settings in single var, cleaned up
+
+ -- v0.7.A20 ------
+
+ * last gcc warning fixed
+ * messages now scroll bottom to top
+ * your own input is echoed on screen, _ marks cursor in typing mode
+ * long messages can be displayed over multiple lines
+ * typing messages longer than message window moves cursor over old text
+ * empty messages are escaped
+ * key and network handling in main loop in functions
+ * started moving messages to seperate file
+
+ -- v0.7.A21 ------
+
+ * used curses to invert pause text instead of stdout() so it works in screen
+ * some code cleaned up
+
+ -- v0.7.A27 ------
+
+ * clientspecific playerdata seperated from general playerdata (PlayerDisp[])
+ * player names printed over top field grid
+
+ -- v0.8 ----------
+
+ * gravity off by default
+ * revert stupid whitespace changes in 0.7.A2
+
 ------------------------------------------------------------------------------
index 537142f2b52e1c46528b43686905cc60f99a117d..1d0ce1c4795a315efbe621d0f9423f84e952846a 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -137,20 +137,19 @@ fi
 
 rm -f test.c test.o a.out
 
-ORIG_SOURCES="game- curses- shapes- board- util- inet- robot-"
-SOURCES="$ORIG_SOURCES"
-
+SOURCES="game- curses- board- util- inet-"
 SRCS="`echo $SOURCES | sed -e s/-/.c/g`"
 OBJS="`echo $SOURCES | sed -e s/-/.o/g`"
+SSOURCES="server- util-"
+SSRCS="`echo $SSOURCES | sed -e s/-/.c/g`"
+SOBJS="`echo $SSOURCES | sed -e s/-/.o/g`"
 
-DISTFILES="README FAQ COPYING VERSION Configure netris.h sr.c server.c robot_desc"
-DISTFILES="$DISTFILES `echo $ORIG_SOURCES | sed -e s/-/.c/g`"
-
-echo > .depend
+DISTFILES="README FAQ INSTALL COPYING VERSION TODO ChangeLog Configure netris.h"
+DISTFILES="$DISTFILES $SRCS server.c"
 
 echo "Creating Makefile"
-sed -e "s/-LFLAGS-/$LFLAGS/g" -e "s/-SRCS-/$SRCS/g" \
-       -e "s/-OBJS-/$OBJS/g" -e "s/-DISTFILES-/$DISTFILES/g" \
+sed -e "s/-LFLAGS-/$LFLAGS/g" -e "s/-OBJS-/$OBJS/g" \
+       -e "s/-SOBJS-/$SOBJS/g" -e "s/-DISTFILES-/$DISTFILES/g" \
        -e "s/-COPT-/$COPT/g" -e "s/-CEXTRA-/$CEXTRA/g" \
        -e "s/-LEXTRA-/$LEXTRA/g" -e "s/-CC-/$CC/g" \
        << "END" > Makefile
@@ -166,22 +165,19 @@ LFLAGS = -LEXTRA- -LFLAGS-
 CFLAGS = $(CEXTRA) $(COPT)
 
 PROG = netris
+SPROG = netrisserver
 HEADERS = netris.h
-
-SRCS = -SRCS-
 OBJS = -OBJS-
+SOBJS = -SOBJS-
 DISTFILES = -DISTFILES-
 
-all: Makefile config.h proto.h $(PROG) sr server
+all: Makefile config.h $(PROG) $(SPROG)
 
 $(PROG): $(OBJS)
        $(CC) -o $(PROG) $(OBJS) $(LFLAGS) $(CFLAGS)
 
-sr: sr.o
-       $(CC) -o sr sr.o $(LFLAGS) $(CFLAGS)
-
-server: server.o
-               $(CC) -o server server.o $(LFLAGS) $(CFLAGS)
+$(SPROG): $(SOBJS)
+       $(CC) -o $(SPROG) $(SOBJS) $(LFLAGS) $(CFLAGS)
 
 .c.o:
        $(CC) $(CFLAGS) -c $<
@@ -191,22 +187,6 @@ Makefile config.h: Configure
        @echo "Run ./Configure now"
        @false
 
-proto.h: $(SRCS)
-       @touch $@
-       @mv $@ $@.old
-       @cat $(SRCS) | grep '^ExtFunc[  ]' | sed -e 's/)$$/);/' > $@
-       @if diff $@.old $@ > /dev/null 2>&1; then :; else \
-               echo "proto.h changed"; \
-               touch proto.chg; \
-       fi
-       @rm -f $@.old
-
-depend: proto.h $(SRCS)
-       @echo "Checking dependencies"
-       @sed -n -e '1,/make depend #####$$/p' Makefile > Makefile.new
-       @$(CC) -M $(SRCS) | sed -e 's/proto\.h/proto.chg/g' >> Makefile.new
-       @mv -f Makefile.new Makefile
-
 dist: $(DISTFILES)
        @vers=`cat VERSION`; \
        dir="netris-$$vers"; \
@@ -221,12 +201,11 @@ dist: $(DISTFILES)
        tar -cvzof $$dir.tar.gz $$dir
 
 clean:
-       rm -f proto.h proto.chg $(PROG) $(OBJS) test.c a.out sr sr.o server server.o
+       rm -f $(PROG) $(OBJS) $(SPROG) $(SOBJS) a.out
 
 cleandir: clean
-       rm -f .depend Makefile config.h
+       rm -f Makefile config.h
 
-##### DO NOT EDIT OR DELETE THIS LINE, it's needed by make depend #####
 END
 
 echo "Creating config.h"
@@ -256,11 +235,6 @@ if [ "$CURSES_HACK" = "true" ]; then
        echo "#define CURSES_HACK" >> config.h
 fi
 
-echo "Running 'make depend'"
-if make depend; then :; else cat << END; fi
-
-make depend failed, but that's OK unless you're doing development
-END
 cat << END
 
 Now do a 'make'
diff --git a/INSTALL b/INSTALL
new file mode 100644 (file)
index 0000000..97cf600
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,4 @@
+./configure
+make
+make install
+
diff --git a/TODO b/TODO
index 819dfceec97ee2f1c457e3dd738188eb7acaa155..c3c58e3719a117c9dd5318ddb46b438f13524807 100644 (file)
--- a/TODO
+++ b/TODO
@@ -1,49 +1,55 @@
  * check out quadra gravity: single block over multiplayer junkhole
+   -> piece falls down
 
 ---- near-future: ------------------------------------------------------------
 
+ * only global pause (handled by server in mp)
+   every client still has readiness flag
+ * piece seperation when middle cleared away? (check quadra -> piece split)
  * correct cursorposition at quit
+ * echo \r
  * transmit player fields of game in progress to new player
        * server has to maintain copy of player fields
+       * server also handles endgame stats
  * 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
+ * spacebar toggles readiness 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)
+ * MENUTHINGY :)
+       * write options to file
+ * all messages in single include file
+ * timestamps
+       * backtrace...
+               * multiple players using a single (larger) field
+ * wrap multiline messages at word end
+ * commands (/team)
  * observers (join as g/o player)
- * fix -f
- * half width enemy fields if out of screen space
- * fix bot
- * multiplayer stats
+ * bot as seperate client
  * time-based singleplayer leveling?
- * shapes stored as bitmap, rotate by modifying for (should be smaller)
+ * fix -f (both client+server)
+ * more server options (field size..)
 
 
 ---- distant future: ---------------------------------------------------------
 
- * horizontally _and_ vertically resize enemy fields
+ * different key procedure? (allowing for multiple keys simoultaniously?)
+ * vertical shrinking of enemy fields (merging two lines into one!)
  * server can add lines after specified time
  * sounds
- * line clear animations (flash)
+ * graphics.... (or at least x version for keys)
+ * extra alarm event for effects
+       * line clear animations (flash)
  * multiple next pieces
  * special blocks
        * inventory
        * player keys
        * delete key?
        * blocks+actions
+               abcd.fgHi..LmnoPqrsTUvWx..
                * tetrinet:
                        * a: add (junk)line
                        * b: remove specials on field
@@ -55,8 +61,8 @@
                        * r: remove 10 blocks at random
                        * s: swap fields
                * suggested:
-                       * d: donate (next inv block given to other player)
-                       * f: flip (symetric vertical inversion)
+                       * d (w): donate (next inv block given to other player)
+                       * f (u): 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))
                        * 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?
  * ipv6
- * replay ability? (tspec replay or quadra rec compatible?)
+ * replay ability? (tspec replay and/or quadra rec compatible?)
+
+
+---- consider: ---------------------------------------------------------------
 
+ * colored shadows
diff --git a/board.c b/board.c
index 55983b477de3513218ebab9b019e0db1e029956f..c3a8d5cae44e69711ad4a6f7e1b698940eef6274 100644 (file)
--- a/board.c
+++ b/board.c
 #include "netris.h"
 #include <stdlib.h>
 
-#ifdef DEBUG_FALLING
-# define B_OLD
-#else
-# define B_OLD abs
-#endif
-
-static BlockType board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-static BlockType oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
+#include "board.h"
+
+static const char shapes[7][4][4][4] = {
+       { { {0x00, 0x00, 0x00, 0x00}, {0x47, 0xC7, 0x97, 0x00},
+           {0x00, 0x00, 0x27, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal
+         { {0x00, 0x17, 0x00, 0x00}, {0x00, 0x37, 0x00, 0x00},
+           {0x47, 0xA7, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt vertical J
+         { {0x17, 0x00, 0x00, 0x00}, {0x67, 0xC7, 0x87, 0x00},
+           {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal
+         { {0x00, 0x57, 0x87, 0x00}, {0x00, 0x37, 0x00, 0x00},
+           {0x00, 0x27, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //J (yellow)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x53, 0xC3, 0x83, 0x00},
+           {0x23, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal
+         { {0x43, 0x93, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00},
+           {0x00, 0x23, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp vertical
+         { {0x00, 0x00, 0x13, 0x00}, {0x43, 0xC3, 0xA3, 0x00},
+           {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal
+         { {0x00, 0x13, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00},
+           {0x00, 0x63, 0x83, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //L (cyan)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x48, 0xD8, 0x88, 0x00},
+           {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing down
+         { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xB8, 0x00, 0x00},
+           {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing left
+         { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xE8, 0x88, 0x00},
+           {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing up
+         { {0x00, 0x18, 0x00, 0x00}, {0x00, 0x78, 0x88, 0x00},
+           {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //T (white)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00},
+           {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+         { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00},
+           {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+         { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00},
+           {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+         { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00},
+           {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //S (green)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00},
+           {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+         { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00},
+           {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+         { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00},
+           {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+         { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00},
+           {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //Z (red)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84},
+           {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //lieing
+         { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00},
+           {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} }, //standing
+         { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84},
+           {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+         { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00},
+           {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} } }, //stick (blue)
+
+       { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+           {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+         { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+           {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+         { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+           {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+         { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+           {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} } } //square (purple)
+};
+
+int ShapeIterate(char s, int scr, int y, int x, ShapeDrawFunc func)
+{ //Draw a certain shape using <ShapeDrawFunc>
+       int i, j, result;
+       char type, rotation;
+
+       type = s/4;
+       rotation = s&3;
+       for (i = 0; i<4; i++)
+               for (j = 0; j<4; j++)
+                       if (shapes[type][rotation][i][j])
+                               if (result = func(scr, y-i, x+j, shapes[type][rotation][i][j]))
+                                       return result;
+       return 0;
+}
+
+
+float stdOptions[7] = {1, 1, 1, 1, 1, 1, 1}; //stdOptions
+
+char ChooseOption(float options[7])
+{ //Return a random piece with given piece weight
+       int i;
+       float total = 0, val;
+
+       for (i = 0; i<7; i++) total += options[i];
+       val = Random(0, 32767)/32768.0*total;
+       for (i = 0; i<7; i++) if ((val -= options[i])<0) return i<<2;
+       return 0;
+}
+
+
+static unsigned char board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
+static unsigned char oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
 static unsigned int changed[MAX_SCREENS][MAX_BOARD_HEIGHT];
-static int falling[MAX_SCREENS][MAX_BOARD_WIDTH];
-static int oldFalling[MAX_SCREENS][MAX_BOARD_WIDTH];
 static int shadowy;
 
-
-ExtFunc void ClearField(int scr)
-{
+void ClearField(int scr)
+{ //Empty the whole field (all blocks BT_none)
        int y, x;
 
        for (y = Players[scr].boardHeight - 1; y >= 0; --y)
@@ -46,123 +134,103 @@ ExtFunc void ClearField(int scr)
                }
 } //ClearField
 
-ExtFunc BlockType GetBlock(int scr, int y, int x)
-{
+unsigned char GetBlock(int scr, int y, int x)
+{ //Returns the block on field at position (x,y)
        if (y < 0 || x < 0 || x >= Players[scr].boardWidth)
                return BT_wall;
        else if (y >= Players[scr].boardHeight)
                return BT_none;
        else
-               return abs(board[scr][y][x]);
+               return board[scr][y][x];
 } //GetBlock
 
-ExtFunc void SetBlock(int scr, int y, int x, BlockType type)
+void SetBlock(int scr, int y, int x, unsigned char type)
 {
        if (y >= 0 && y < Players[scr].boardHeight &&
                x >= 0 && x < Players[scr].boardWidth) {
-               if (y < Players[scr].boardVisible)
-                       falling[scr][x] += (type < 0) - (board[scr][y][x] < 0);
                board[scr][y][x] = type;
                changed[scr][y] |= 1 << x;
        }
 } //SetBlock
 
-ExtFunc int RefreshBoard(int scr)
+int RefreshBoard(int scr)
 { //draw changes to screen
        int y, x, any = 0;
        unsigned int c;
-       BlockType b;
-
-       for (y = Players[scr].boardVisible - 1; y >= 0; --y)
-               if ((c = changed[scr][y])) {
-                       if (robotEnable) {
-                               RobotCmd(0, "RowUpdate %d %d", scr, y);
-                               for (x = 0; x < Players[scr].boardWidth; ++x) {
-                                       b = board[scr][y][x];
-                                       if (fairRobot)
-                                               b = abs(b);
-                                       RobotCmd(0, " %d", b);
+
+       for (y = Players[scr].boardVisible - 1; y >= 0; y--)
+               if ((c = changed[scr][y])) { //line changed
+                       for (x = 0; c; (c >>= 1), x++)
+                               if ((c & 1) && board[scr][y][x] != oldBoard[scr][y][x]) {
+                                       PlotBlock(scr, y, x, board[scr][y][x]);
+                                       oldBoard[scr][y][x] = board[scr][y][x];
                                }
-                               RobotCmd(0, "\n");
-                       } //robot
-                       changed[scr][y] = 0;
+                       changed[scr][y] = 0; //reset
                        any = 1;
-                       for (x = 0; c; (c >>= 1), (++x))
-                               if ((c & 1) && B_OLD(board[scr][y][x])!=oldBoard[scr][y][x]) {
-                                       PlotBlock(scr, y, x, B_OLD(board[scr][y][x]));
-                                       oldBoard[scr][y][x] = B_OLD(board[scr][y][x]);
-                               }
                } //changed row
-       if (robotEnable) RobotTimeStamp();
-       for (x = 0; x < Players[scr].boardWidth; ++x)
-               if (oldFalling[scr][x] != !!falling[scr][x]) {
-                       oldFalling[scr][x] = !!falling[scr][x];
-                       PlotUnderline(scr, x, oldFalling[scr][x]);
-                       any = 1;
-               }
        return any;
 } //RefreshBoard
 
-ExtFunc int GlanceFunc(int scr, int y, int x, BlockType type, void *data)
+int GlanceFunc(int scr, int y, int x, unsigned char type)
 {
-       PlotBlock1(scr, 20 - y, x * 2, type);
+       PlotBlockXY(y, x, type);
        return 0;
 } //GlanceFunc
 
-ExtFunc int ShadowFunc(int scr, int y, int x, BlockType type, void *data)
+int ShadowFunc(int scr, int y, int x, unsigned char type)
 { //draw shadow
        SetBlock(scr, y, x, BT_shadow);
        return 0;
 } //ShadowFunc
 
-ExtFunc int PlotFunc(int scr, int y, int x, BlockType type, void *data)
+int PlotFunc(int scr, int y, int x, unsigned char type)
 {
        SetBlock(scr, y, x, type);
        return 0;
 }
-ExtFunc void PlotShape(Shape *shape, int scr, int y, int x, int falling, int shadow)
+void PlotShape(char shape, int scr, int y, int x, int shadow)
 { //put shape on field
-       if (shadow && scr == me) {
+       if (shadow) {
                for (shadowy = y - 1; shadowy >= 0; shadowy--)
                        if (!ShapeFits(shape, scr, shadowy, x))
                                break;
-               ShapeIterate(shape, scr, shadowy + 1, x, falling, ShadowFunc, NULL);
+               ShapeIterate(shape, scr, shadowy + 1, x, ShadowFunc);
        } //draw shadow
-       ShapeIterate(shape, scr, y, x, falling, PlotFunc, NULL);
+       ShapeIterate(shape, scr, y, x, PlotFunc);
 } //PlotShape
 
-ExtFunc int EraseFunc(int scr, int y, int x, BlockType type, void *data)
+int EraseFunc(int scr, int y, int x, unsigned char type)
 {
        SetBlock(scr, y, x, BT_none);
        return 0;
 }
-ExtFunc void EraseShape(Shape *shape, int scr, int y, int x, int shadow)
+void EraseShape(char shape, int scr, int y, int x, int shadow)
 { //remove block from field
-       ShapeIterate(shape, scr, y, x, 0, EraseFunc, NULL);
+       ShapeIterate(shape, scr, y, x, EraseFunc);
        if (shadow && scr == me) //draw shadow
-               ShapeIterate(shape, scr, shadowy + 1, x, 0, EraseFunc, NULL);
+               ShapeIterate(shape, scr, shadowy + 1, x, EraseFunc);
 } //EraseShape
 
-ExtFunc int CollisionFunc(int scr, int y, int x, BlockType type, void *data)
+int CollisionFunc(int scr, int y, int x, unsigned char type)
 {
        return GetBlock(scr, y, x) > BT_none;
 }
-ExtFunc int ShapeFits(Shape *shape, int scr, int y, int x)
+int ShapeFits(char shape, int scr, int y, int x)
 { //check if there's nothing in the way
-       return !ShapeIterate(shape, scr, y, x, 0, CollisionFunc, NULL);
+       return !ShapeIterate(shape, scr, y, x, CollisionFunc);
 } //ShapeFits
 
-ExtFunc int VisibleFunc(int scr, int y, int x, BlockType type, void *data)
+int VisibleFunc(int scr, int y, int x, unsigned char type)
 {
        return (y >= 0 && y < Players[scr].boardVisible &&
                        x >= 0 && x < Players[scr].boardWidth);
 }
-ExtFunc int ShapeVisible(Shape *shape, int scr, int y, int x)
+int ShapeVisible(char shape, int scr, int y, int x)
 {
-       return ShapeIterate(shape, scr, y, x, 0, VisibleFunc, NULL);
+       return ShapeIterate(shape, scr, y, x, VisibleFunc);
 } //ShapeVisible
 
-ExtFunc int MovePiece(int scr, int deltaY, int deltaX)
+int MovePiece(int scr, int deltaY, int deltaX)
 {
        int result;
 
@@ -175,28 +243,36 @@ ExtFunc int MovePiece(int scr, int deltaY, int deltaX)
                Players[scr].curX += deltaX;
        }
        PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,
-               1, 1);
+               scr == me);
        return result;
 } //MovePiece
 
-ExtFunc int RotatePiece(int scr, int dir)
+int RotatePiece(int scr, int dir)
 {
+       char newshape;
        int result;
 
        EraseShape(Players[scr].curShape, scr, Players[scr].curY,
                Players[scr].curX, 1);
-       result = ShapeFits(dir ? Players[scr].curShape->rotateTo
-                                                  : Players[scr].curShape->rotateFrom,
-               scr, Players[scr].curY, Players[scr].curX);
-       if (result)
-               Players[scr].curShape = dir ? Players[scr].curShape->rotateTo
-                                                                       : Players[scr].curShape->rotateFrom;
+       /* (inc|dec)rement only 3 least significant bits which indicate rotation */
+       newshape = (Players[scr].curShape & 252) + (((Players[scr].curShape & 3) + dir) & 3);
+       result = ShapeFits(newshape, scr, Players[scr].curY, Players[scr].curX);
+       if (!result) {
+               short int slideX;
+               for (slideX = 0; slideX < 2; slideX = -slideX) {
+                       if (slideX >= 0) slideX++; //slide more
+                       if (result = ShapeFits(newshape, scr, Players[scr].curY,
+                               Players[scr].curX+slideX)) break;
+               } //slide left and right
+               if (result) Players[scr].curX += slideX;
+       } //try to fit if it doesn't
+       if (result) Players[scr].curShape = newshape;
        PlotShape(Players[scr].curShape, scr,
-                       Players[scr].curY, Players[scr].curX, 1, 1);
+                       Players[scr].curY, Players[scr].curX, scr == me);
        return result;
 } //RotatePiece
 
-ExtFunc int DropPiece(int scr)
+int DropPiece(int scr)
 {
        int count = 0;
 
@@ -204,26 +280,70 @@ ExtFunc int DropPiece(int scr)
                Players[scr].curY, Players[scr].curX, 1);
        while (ShapeFits(Players[scr].curShape, scr,
                        Players[scr].curY - 1, Players[scr].curX)) {
-               --Players[scr].curY;
-               ++count;
+               Players[scr].curY--;
+               count++;
        }
        PlotShape(Players[scr].curShape, scr,
-               Players[scr].curY, Players[scr].curX, 1, 0);
+               Players[scr].curY, Players[scr].curX, 0);
        return count;
 } //DropPiece
 
-ExtFunc int LineIsFull(int scr, int y)
-{
+int BlockFree(int scr, int x, int y, unsigned char z)
+{ //Check if blocks are empty below block (x,y) and sticking to (x,y) mask <z>
+       unsigned char curblock;
+
+       if (y == 0) return 0; //at bottom
+       curblock = GetBlock(scr, y, x) & z;
+       if (curblock & 16  && !BlockFree(scr, x, y-1, z & 208)) return 0;
+       if (curblock & 32  && !BlockFree(scr, x, y+1, z & 224)) return 0;
+       if (curblock & 64  && !BlockFree(scr, x+1, y, z & 112)) return 0;
+       if (curblock & 128 && !BlockFree(scr, x-1, y, z & 176)) return 0;
+       if ((z = GetBlock(scr, y-1, x)) & 32) return 1; //stuck to block below
+       if (z > BT_none) return 0; //some other piece below
+       return 1; //nothing below
+}
+
+int BlockFall(int scr, int x, int y, unsigned char z)
+{ //Drop down block (x,y) and those sticking to it mask <z>
+       if (GetBlock(scr, y, x) & z & 16)  BlockFall(scr, x, y-1, z & 208);
+       if (GetBlock(scr, y, x) & z & 32)  BlockFall(scr, x, y+1, z & 224);
+       if (GetBlock(scr, y, x) & z & 64)  BlockFall(scr, x+1, y, z & 112);
+       if (GetBlock(scr, y, x) & z & 128) BlockFall(scr, x-1, y, z & 174);
+       SetBlock(scr, y-1, x, GetBlock(scr, y, x));
+       SetBlock(scr, y, x, BT_none);
+}
+
+int CheckFall(int scr)
+{ //Drop any free blocks on field
+       int xloop, x, x2, y, fallen = 0;
+       unsigned char z;
+
+       if (!Game.gravity) return 0;
+       for (y = Players[scr].boardHeight-1; y > 0; y--)
+               for (x = 0; x < Players[scr].boardWidth; x++) {
+                       if (((z = GetBlock(scr, y, x)) > BT_none) && ((z & 160) == 0)) {
+                       //doesn't stick left/up => topleft block
+                               if (BlockFree(scr, x, y, 240)) {
+                                       BlockFall(scr, x, y, 240);
+                                       fallen++;
+                               } //move blocks down
+                       } //block present
+               } //handle line
+       return fallen;
+}
+
+int LineIsFull(int scr, int y)
+{ //return 0 if any blocks present on line <y>
        int x;
 
-       for (x = 0; x < Players[scr].boardWidth; ++x)
+       for (x = 0; x < Players[scr].boardWidth; x++)
                if (GetBlock(scr, y, x) <= BT_none)
                        return 0;
        return 1;
 }
 
-ExtFunc void CopyLine(int scr, int from, int to)
-{
+void CopyLine(int scr, int from, int to)
+{ //move blocks on line <from> to line <to>
        int x;
 
        if (from != to)
@@ -231,32 +351,35 @@ ExtFunc void CopyLine(int scr, int from, int to)
                        SetBlock(scr, to, x, GetBlock(scr, from, x));
 }
 
-ExtFunc int ClearFullLines(int scr)
-{
-       int from, to;
+int ClearFullLines(int scr)
+{ //remove full lines, return lines cleared
+       int from, to, x, linescleared = 0;
 
+       do {
        from = to = 0;
        while (to < Players[scr].boardHeight) {
-               while (LineIsFull(scr, from))
-                       ++from;
+               while (LineIsFull(scr, from)) {
+                       from++; //skip
+                       for (x = 0; x<Players[scr].boardWidth; x++) {
+                               SetBlock(scr, from, x, GetBlock(scr, from, x)&239);
+                               if (from>1)
+                                       SetBlock(scr, from-2, x, GetBlock(scr, from-2, x)&223);
+                       } //don't stick blocks to line which we'll remove
+               } //full lines
                CopyLine(scr, from++, to++);
        }
-       return from - to;
+       linescleared += from - to;
+       } while (CheckFall(scr));
+       return linescleared;
 }
 
-ExtFunc void FreezePiece(int scr)
+void FreezePiece(int scr)
 {
-       int y, x;
-       BlockType type;
-
-       for (y = 0; y < Players[scr].boardHeight; ++y)
-               for (x = 0; x < Players[scr].boardWidth; ++x)
-                       if ((type = board[scr][y][x]) < 0)
-                               SetBlock(scr, y, x, -type);
+       // remove me! :)
 }
 
-ExtFunc void InsertJunk(int scr, int count, int column)
-{
+void InsertJunk(int scr, int color, int count, int column)
+{ //add <count> junklines with hole at <column> to <scr> by team <color>
        int y, x;
 
        EraseShape(Players[scr].curShape, scr,
@@ -265,14 +388,16 @@ ExtFunc void InsertJunk(int scr, int count, int column)
                CopyLine(scr, y, y + count);
        for (y = 0; y < count; ++y)
                for (x = 0; x < Players[scr].boardWidth; ++x)
-                       SetBlock(scr, y, x, (x == column) ? BT_none : BT_white);
+                       SetBlock(scr, y, x, (x == column) ? BT_none : color + 1
+                               + 64 * (x != column-1 && x < Players[scr].boardWidth-1)
+                               + 128 * (x != column+1 && x > 0));
        Players[scr].curY += count; //move piece up..
        for (y = 0; y < count; ++y)
                if (ShapeFits(Players[scr].curShape, scr, Players[scr].curY - 1, Players[scr].curX))
                        Players[scr].curY--; //..and down again as far as possible
                else break;
        PlotShape(Players[scr].curShape, scr, Players[scr].curY, Players[scr].curX,
-               1, 1);
+               scr == me);
 } //InoertJunk
 
 /*
diff --git a/board.h b/board.h
new file mode 100644 (file)
index 0000000..5f53aee
--- /dev/null
+++ b/board.h
@@ -0,0 +1,36 @@
+#ifndef __BOARD_H
+#define __BOARD_H
+
+extern float stdOptions[7];
+
+typedef int (*ShapeDrawFunc)(int scr, int y, int x, unsigned char type);
+extern int ShapeIterate(char s, int scr, int y, int x, ShapeDrawFunc func);
+extern char ChooseOption(float options[7]);
+extern void ClearField(int scr);
+extern unsigned char GetBlock(int scr, int y, int x);
+extern void SetBlock(int scr, int y, int x, unsigned char type);
+extern int RefreshBoard(int scr);
+extern int GlanceFunc(int scr, int y, int x, unsigned char type);
+extern int ShadowFunc(int scr, int y, int x, unsigned char type);
+extern int PlotFunc(int scr, int y, int x, unsigned char type);
+extern void PlotShape(char shape, int scr, int y, int x, int shadow);
+extern int EraseFunc(int scr, int y, int x, unsigned char type);
+extern void EraseShape(char shape, int scr, int y, int x, int shadow);
+extern int CollisionFunc(int scr, int y, int x, unsigned char type);
+extern int ShapeFits(char shape, int scr, int y, int x);
+extern int VisibleFunc(int scr, int y, int x, unsigned char type);
+extern int ShapeVisible(char shape, int scr, int y, int x);
+extern int MovePiece(int scr, int deltaY, int deltaX);
+extern int RotatePiece(int scr, int dir);
+extern int DropPiece(int scr);
+extern int BlockFree(int scr, int x, int y, unsigned char z);
+extern int BlockFall(int scr, int x, int y, unsigned char z);
+extern int CheckFall(int scr);
+extern int LineIsFull(int scr, int y);
+extern void CopyLine(int scr, int from, int to);
+extern int ClearFullLines(int scr);
+extern void FreezePiece(int scr);
+extern void InsertJunk(int scr, int color, int count, int column);
+
+#endif //__BOARD_H
+
diff --git a/client.h b/client.h
new file mode 100644 (file)
index 0000000..2da42ed
--- /dev/null
+++ b/client.h
@@ -0,0 +1,14 @@
+#ifndef __CLIENT_H
+#define __CLIENT_H
+
+typedef struct {
+       short drawstyle;
+       short dropmode;
+       short standout;
+       short color;
+       short ascii;
+} _Sets;
+extern _Sets Sets;
+
+#endif //__CLIENT_H
+
index 8d500d9528da4dd41fb945cd12062d09d1eea113..aab808d81bc4ae44e7d84be0835f047739474382 100644 (file)
--- a/curses.c
+++ b/curses.c
  */
 
 #include "netris.h"
+
 #include <sys/types.h>
 #include <unistd.h>
 #include <curses.h>
 #include <string.h>
 #include <stdlib.h>
 
+#include "client.h"
+#include "curses.h"
+#include "util.h"
+#include "board.h"
+#include "msg.en.h"
+
 #ifdef NCURSES_VERSION
 # define HAVE_NCURSES
 #endif
 
-ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type);
-
 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event);
 static EventGenRec keyGen =
+//             { NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
                { NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
 
 static int boardYPos[MAX_SCREENS], boardXPos[MAX_SCREENS];
+static int boardSize[MAX_SCREENS];
+//^^^struct
 static int statusYPos, statusXPos;
 static int messageYPos, messageXPos, messageHeight, messageWidth;
+WINDOW *msgwin;
 static int haveColor;
+int PlayerDisp[MAX_SCREENS];
+
+#define MSG_HEIGHT 64 //max history
+char *message[MSG_HEIGHT];
+char messages[MSG_HEIGHT][MSG_WIDTH];
 
 static char *term_vi;  /* String to make cursor invisible */
 static char *term_ve;  /* String to make cursor visible */
 
-ExtFunc void InitScreens(void)
+void InitScreens(void)
 {
        MySigSet oldMask;
 
@@ -66,10 +80,10 @@ ExtFunc void InitScreens(void)
 #endif
 
 #ifdef HAVE_NCURSES
-       haveColor = Game.color && has_colors();
+       haveColor = Sets.color && has_colors();
        if (haveColor) {
                static struct {
-                       BlockType type;
+                       char type;
                        short color;
                } myColorTable[] = {
                        { BT_white,             COLOR_WHITE },
@@ -103,20 +117,30 @@ ExtFunc void InitScreens(void)
 //     keypad(stdscr, TRUE);           //get arrow/functionkeys 'n stuff
        OutputTermStr(term_vi, 0);
        AddEventGen(&keyGen);           //key handler
+       signal(SIGWINCH, CatchWinCh);   //handle window resize
+//  ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW);
        standend();                                     //normal text
+
+       memset(messages, 0, sizeof(messages)); //empty messages
+       {
+               int i;
+               for (i = 0; i<MSG_HEIGHT; i++)
+                       message[i] = messages[i]; //set pointers
+       }
 } //InitScreens
 
-ExtFunc void CleanupScreens(void)
+void CleanupScreens(void)
 {
        RemoveEventGen(&keyGen);
        endwin();                                       //end curses
        OutputTermStr(term_ve, 1);
 } //CleanupScreens
 
-ExtFunc void GetTermcapInfo(void)
+void GetTermcapInfo(void)
 {
        char *term, *buf, *data;
-       int bufSize = 10240;
+       int bufSize = 8192;
+       char scratch[1024];
 
        if (!(term = getenv("TERM")))
                return;
@@ -169,7 +193,7 @@ ExtFunc void GetTermcapInfo(void)
                term_vi = term_ve = NULL;
 } //GetTermcapInfo
 
-ExtFunc void OutputTermStr(char *str, int flush)
+void OutputTermStr(char *str, int flush)
 {
        if (str) {
                fputs(str, stdout);
@@ -177,7 +201,7 @@ ExtFunc void OutputTermStr(char *str, int flush)
        }
 } //OutputTermStr
 
-ExtFunc void DrawTitle(void)
+void DrawTitle(void)
 {
        int rows, cols;
        char s[255];
@@ -198,48 +222,43 @@ ExtFunc void DrawTitle(void)
        standend();     //normal text
 } //DrawTitle
 
-ExtFunc void DrawBox(int x1, int y1, int x2, int y2)
+void DrawBox(int x1, int y1, int x2, int y2)
 { //draw grid
        int y, x;
 
        for (y = y1 + 1; y < y2; y++) {
-               mvaddch(y, x1, Game.ascii ? '|' : ACS_VLINE); //left
-               mvaddch(y, x2, Game.ascii ? '|' : ACS_VLINE); //right
-       }
+               mvaddch(y, x1, Sets.ascii ? '|' : ACS_VLINE); //left
+               mvaddch(y, x2, Sets.ascii ? '|' : ACS_VLINE); //right
+       } //draw vertical lines
        move(y1, x1); //top
-       addch(Game.ascii ? '+' : ACS_ULCORNER);
+       addch(Sets.ascii ? '+' : ACS_ULCORNER);
        for (x = x1 + 1; x < x2; x++)
-               addch(Game.ascii ? '-' : ACS_HLINE);
-       addch(Game.ascii ? '+' : ACS_URCORNER);
+               addch(Sets.ascii ? '-' : ACS_HLINE);
+       addch(Sets.ascii ? '+' : ACS_URCORNER);
        move(y2, x1); //bottom
-       addch(Game.ascii ? '+' : ACS_LLCORNER);
+       addch(Sets.ascii ? '+' : ACS_LLCORNER);
        for (x = x1 + 1; x < x2; x++)
-               addch(Game.ascii ? '-' : ACS_HLINE);
-       addch(Game.ascii ? '+' : ACS_LRCORNER);
+               addch(Sets.ascii ? '-' : ACS_HLINE);
+       addch(Sets.ascii ? '+' : ACS_LRCORNER);
 } //DrawBox
 
-ExtFunc void DrawField(int scr)
+void DrawField(int scr)
 { //draw field for player scr
-       if (!Players[scr].spy) return; 
+       if (!PlayerDisp[scr]) return; 
        DrawBox(boardXPos[scr] - 1, boardYPos[scr] - Players[scr].boardVisible,
-               boardXPos[scr] + 2 * Players[scr].boardWidth, boardYPos[scr] + 1);
+               boardXPos[scr] + boardSize[scr] * Players[scr].boardWidth, boardYPos[scr] + 1);
        {
-               char s[2*Players[scr].boardWidth];
+               char s[boardSize[scr]*Players[scr].boardWidth+1];
 
-               memset(s, ' ', sizeof(s));
                if (Players[scr].host && Players[scr].host[0])
-                       snprintf(s, sizeof(s), "%s <%s>",
+                       snprintf(s, sizeof(s), " %s <%s> ",
                                Players[scr].name, Players[scr].host);
-               else snprintf(s, sizeof(s), "%s", Players[scr].name);
-               s[strlen(s)] = ' ';
-               s[sizeof(s) - 7*((Players[scr].flags & SCF_usingRobot) != 0)
-                       - 5*((Players[scr].flags & SCF_fairRobot) != 0)] = 0;
+               else snprintf(s, sizeof(s), " %s ", Players[scr].name);
+               s[sizeof(s)] = 0;
+               if (haveColor && Players[scr].team > 0 && Players[scr].team <= 7)
+                       attrset(A_REVERSE | COLOR_PAIR(Players[scr].team + 1));
                mvaddstr(1, boardXPos[scr], s);
-
-               if (Players[scr].flags & SCF_usingRobot) {
-                       addstr((Players[scr].flags & SCF_fairRobot)
-                               ? "(fair robot)" : "(robot)");
-               } //add robot indicator
+               if (haveColor) standend();
        } //display playername/host
 
        {
@@ -252,147 +271,265 @@ ExtFunc void DrawField(int scr)
        ShowPause(scr);
 } //DrawField
 
-ExtFunc void InitFields(void)
+void InitFields(void)
 { //calculate positions of all fields
        int scr, prevscr;
        int y, x;
+       int spaceavail;
 
+       clear();
+       DrawTitle();
        getmaxyx(stdscr, y, x);
+       boardSize[me] = 2;
        boardXPos[me] = 1;
-       boardYPos[me] = 22;
-       statusXPos = 2 * Players[me].boardWidth + 3;
-       statusYPos = 22;
+       boardYPos[me] = 21;
+       PlayerDisp[me] = 1;
+       statusXPos = boardSize[me] * Players[me].boardWidth + 3;
+       statusYPos = 21;
+       ShowScore(me, Players[me].score);
+
        messageXPos = 2;
-       messageYPos = 25;
-       messageWidth = x - messageXPos - 2;
-       if ((messageHeight = y - messageYPos - 1) < 0) messageHeight = 0;
-       else DrawBox(messageXPos - 2, messageYPos - 1,
-               messageXPos + messageWidth + 1, messageYPos + messageHeight);
+       messageYPos = 24;
+       if ((messageWidth = x - messageXPos - 2) > MSG_WIDTH) messageWidth = MSG_WIDTH;
+       if ((messageHeight = y - messageYPos - 1) > MSG_HEIGHT) messageHeight = MSG_HEIGHT;
+       if (messageHeight <= 0) {
+               messageWidth = 27;
+               messageHeight = y - 3;
+               messageXPos = statusXPos + 16;
+               messageYPos = 2;
+       } //messagebox doesn't fit below
+       DrawBox(messageXPos - 2, messageYPos - 1,
+               messageXPos + messageWidth + 1, messageYPos+messageHeight);
+       if (msgwin = subwin(stdscr, messageHeight, messageWidth,
+                               messageYPos, messageXPos))
+               scrollok(msgwin, 1);  //allow scrolling
+       wmove(msgwin, messageHeight - 2, 0);
+       for (scr = messageHeight - 2; scr >= 0; scr--) //display message history
+               DisplayMessage(message[scr]);
+
+       spaceavail = x;
+       for (scr = 1; scr <= maxPlayer; scr++)
+               spaceavail -= Players[scr].boardWidth+2;
        prevscr = me;
        for (scr = 1; scr < MAX_SCREENS; scr++) if (scr != me) {
+               boardYPos[scr] = 21;
                boardXPos[scr] =
-                       boardXPos[prevscr] + 2 * Players[prevscr].boardWidth + 3;
-               if (prevscr == me)
-                       boardXPos[scr] += 14; //scorebar
-               boardYPos[scr] = 22;
-               if (x < boardXPos[scr] + 2 * Players[scr].boardWidth + 1)
-                       Players[scr].spy = 0; //field doesn't fit on screen
+                       boardXPos[prevscr] + 2 + boardSize[prevscr] * Players[prevscr].boardWidth;
+               if (prevscr == me) {
+                       boardXPos[scr] += 15; //scorebar
+                       if (messageYPos < 24)
+                               boardXPos[scr] += messageWidth + 4; //messagebox
+                       spaceavail -= boardXPos[scr] - 3;
+               } //stuff before second player
+               if (spaceavail >= 0) {
+                       boardSize[scr] = 2;
+                       spaceavail -= Players[scr].boardWidth;
+               } //not enough space, half width
+               else
+                       boardSize[scr] = 1;
+               if (x < boardXPos[scr] + 1 + boardSize[scr] * Players[scr].boardWidth)
+                       PlayerDisp[scr] = 0; //field doesn't fit on screen
+               else
+                       PlayerDisp[scr] = 1;
                prevscr = scr;
        }
-       for (scr = 1; scr <= Game.maxplayers; scr++)
+       for (scr = 1; scr <= maxPlayer; scr++)
                DrawField(scr);
 } //InitFields
 
-ExtFunc void CleanupScreen(int scr)
+void CleanupScreen(int scr)
 {
 }
 
-ExtFunc void Messagef(char *fmt, ...)
+void DisplayMessage(char *p)
+{
+       char s[MSG_WIDTH];
+       char *psearch;
+       char c;
+
+       memcpy(s, p, sizeof(s)-1);
+       s[MSG_WIDTH-1] = 0;
+       p = s;
+       while (psearch = strchr(p, '\\')) {
+               *psearch = '\0';
+               waddstr(msgwin, p);
+               c = atoi(++psearch)+1;
+               if (haveColor) wattrset(msgwin, A_REVERSE | COLOR_PAIR(c));
+               p = ++psearch;
+       } //search for color escapes (\)
+       waddstr(msgwin, p);
+       if (haveColor) wstandend(msgwin);
+       waddch(msgwin, '\n');
+} //DisplayMessage
+
+void Message(char *fmt, ...)
 { //print game/bot message
-       static int line = 0;
        va_list args;
-       char s[255];
-       char *p, *psearch;
+       char s[MSG_WIDTH];
+       char *p;
        int i;
 
        if (!messageHeight) return;
        va_start(args, fmt);
-       move(messageYPos + line, messageXPos);
-//     vwprintw(stdscr, fmt, args); //doesn't seem to be a vprintw
-       vsprintf(s, fmt, args);
-       p = s;
-       while (psearch = strchr(s, '\\')) {
-               *psearch = '\0';
-               addstr(p);
-               if (haveColor)
-                       attrset(A_REVERSE | COLOR_PAIR(atoi(psearch + 1) + 1));
-               p = psearch + 2;
-       } //search for color escapes (\)
-       addstr(p);
-       if (messageHeight > 1) {
-               char s[messageWidth + 1];
-               line = (line + 1) % messageHeight;
-               memset(s, ' ', messageWidth);
-               s[messageWidth] = 0;
-               mvaddstr(messageYPos + line, messageXPos, s);
-       } //multiple lines
-       if (haveColor) standend();
+       vsnprintf(s, sizeof(s), fmt, args);
        va_end(args);
+       p = message[MSG_HEIGHT - 1]; //save last pointer
+       for (i = MSG_HEIGHT - 1; i > 0; i--)
+               message[i] = message[i - 1]; //scroll history
+       message[0] = p;
+       strcpy(p, s);
+
+       wmove(msgwin, messageHeight - 1, 0);
+       DisplayMessage(s);
+       wclrtoeol(msgwin);
+       wrefresh(msgwin);
 } //Message
 
-ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type)
-{
-       int colorIndex = abs(type);
-
+void Messagetype(char c, int x, char *s)
+{ //show single typed character
+       if (c == 27) {
+               mvwaddch(msgwin, messageHeight-1, (x+1) % (messageWidth-1), ' ');
+       } //escape
+       else {
+               if (c == 13 || c==127) //enter/backspace
+                       mvwaddch(msgwin, messageHeight - 1, (x+2) % (messageWidth-1),
+                               x>=messageWidth-3 ? s[x - messageWidth + 3] : ' ');
+               else //any character
+                       mvwaddch(msgwin, messageHeight - 1, x % (messageWidth-1), c);
+               mvwaddch(msgwin, messageHeight - 1, (x+1) % (messageWidth-1), '_');
+       } //typing mode
+       wrefresh(msgwin);
+} //Messagetype
+
+void PlotBlock1(int y, int x, unsigned char type)
+{ //display block on screen
        move(y, x);
        if (type == BT_none) addstr("  ");
        else if (type == BT_shadow) addstr("::");
        else {
-               if (Game.standout) {
 #ifdef HAVE_NCURSES
-                       if (haveColor) attrset(COLOR_PAIR(colorIndex));
+               if (Sets.standout) {
+                       if (haveColor) attrset(COLOR_PAIR(type & 15));
                        else attrset(A_REVERSE);
-#endif
                }
-               addstr(type ? "[]" : "$$");
+#endif
+               switch (Sets.drawstyle) {
+                       case 2:
+                               switch (type & 192) {
+                                case 64:  //right neighbour
+                                        addstr("[[");
+                                        break;
+                                case 128: //left
+                                        addstr("]]");
+                                        break;
+                                default:  //both/none
+                                        addstr("[]");
+                                        break;
+                               } //horizontal stickiness
+                               break; //ascii horizontally grouped
+                       case 3:
+                               switch (type & 240) {
+                                case 48:
+                                        addstr("||"); break; //middle
+                                case 64: case 80: case 96:
+                                        addstr("[="); break; //left end
+                                case 112:
+                                        addstr("|="); break;
+                                case 128: case 144: case 160:
+                                        addstr("=]"); break; //right end
+                                case 176:
+                                        addstr("=|"); break;
+                                case 192: case 208: case 224:
+                                        addstr("=="); break;
+                                default:
+                                        addstr("[]"); break; //top/bottom/mid
+                               } //neighbours
+                               break; //ascii semi-grouped
+                       case 7:
+                               switch (type & 240) {
+                                case 16:  addch(ACS_ULCORNER); addch(ACS_URCORNER); break;//top end
+                                case 32:  addch(ACS_LLCORNER); addch(ACS_LRCORNER); break;//bottom end
+                                case 48:  addch(ACS_VLINE); addch(ACS_VLINE); break;   //vertical middle
+                                case 64:  addch(' '); addch(ACS_HLINE); break;         //left end
+                                case 80:  addch(ACS_ULCORNER); addch(ACS_TTEE); break; //top left corner
+                                case 96:  addch(ACS_LLCORNER); addch(ACS_BTEE); break; //bottom left corner
+                                case 112: addch(ACS_LTEE); addch(ACS_PLUS); break;     //vertical+right
+                                case 128: addch(ACS_HLINE); addch(' '); break;         //right end
+                                case 144: addch(ACS_TTEE); addch(ACS_URCORNER); break; //top right corner
+                                case 160: addch(ACS_BTEE); addch(ACS_LRCORNER); break; //bottom right corner
+                                case 176: addch(ACS_PLUS); addch(ACS_RTEE); break;     //vertical+left
+                                case 192: addch(ACS_HLINE); addch(ACS_HLINE); break;   //horizontal middle
+                                case 208: addch(ACS_TTEE); addch(ACS_TTEE); break;     //horizontal+down
+                                case 224: addch(ACS_BTEE); addch(ACS_BTEE); break;     //horizontal+up
+                                default:  addstr("[]"); break;
+                               } //neighbours
+                               break; //curses grouped
+                       default:
+                               addstr("[]");
+                               break; //ascii non-grouped
+               } //draw block
 #ifdef HAVE_NCURSES
-               if (Game.standout) standend();
+               if (Sets.standout) standend();
 #endif
        } //display one brick
 } //PlotBlock1
-ExtFunc void PlotBlock(int scr, int y, int x, BlockType type)
-{
-       if (y >= 0 && y < Players[scr].boardVisible &&
-               x >= 0 && x < Players[scr].boardWidth)
-         PlotBlock1(scr, boardYPos[scr] - y, boardXPos[scr] + 2 * x, type);
-} //PlotBlock
-
-ExtFunc void PlotBlockS1(int scr, int y, int x, BlockType type)
-{ //DOESN"T WORK YET...
+void PlotBlock1S(int y, int x, unsigned char type)
+{ //display block small
        move(y, x);
-       if (type == BT_none) addstr(" ");
+       if (type == BT_none) addch(' ');
+       else if (type == BT_shadow) addch(':');
        else {
-               addstr(type ? "O" : "$");
-               standend();
+               if (Sets.standout) {
+#ifdef HAVE_NCURSES
+                       if (haveColor)
+                               attrset(COLOR_PAIR(type & 15));
+                       else attrset(A_REVERSE);
+#endif
+               }
+               if ((type & 192) == 64)
+                       addch('[');
+               else if ((type & 192) == 128)
+                       addch(']');
+               else
+                       addch('|');
+#ifdef HAVE_NCURSES
+               if (Sets.standout) standend();
+#endif
        } //display one brick
-} //PlotBlock1
-ExtFunc void PlotBlockS(int scr, int y, int x, BlockType type)
+} //PlotBlock1S
+void PlotBlock(int scr, int y, int x, unsigned char type)
 {
        if (y >= 0 && y < Players[scr].boardVisible &&
-               x >= 0 && x < Players[scr].boardWidth)
-         PlotBlockS1(scr, boardYPos[scr] - y, boardXPos[scr] + x, type);
+               x >= 0 && x < Players[scr].boardWidth) {
+               if (boardSize[scr] > 1)
+                       PlotBlock1(boardYPos[scr] - y, boardXPos[scr] + 2*x, type);
+               else
+                       PlotBlock1S(boardYPos[scr] - y, boardXPos[scr] + x, type);
+       } //on screen
+} //PlotBlock
+void PlotBlockXY(int y, int x, unsigned char type)
+{ //Draw block at specified position on screen (not on field)
+       PlotBlock1(20 - y, 2 * x, type);
 } //PlotBlock
 
-ExtFunc void PlotUnderline(int scr, int x, int flag)
-{ //display piece of bottom fieldgrid
-  move(boardYPos[scr] + 1, boardXPos[scr] + 2 * x);
-  if (Game.ascii)
-       addstr(flag ? "==" : "--");
-  else {
-       addch(flag ? ACS_BTEE : ACS_HLINE);
-       addch(flag ? ACS_BTEE : ACS_HLINE);
-  } //ncurses graphics
-} //PlotUnderline
-
-ExtFunc void ShowScore(int scr, struct _Score score)
+void ShowScore(int scr, struct _Score score)
 { //show score stuff
        float timer;
 
-       mvaddstr(13, statusXPos, "next         ");
+       mvaddstr(13, statusXPos, MSG_NEXT " ");
        mvaddstr(14, statusXPos + 5,  "        ");
        ShapeIterate(Players[scr].nextShape, scr,
-         ShapeToNetNum(Players[scr].nextShape) == 15 ? 6 : 7,
-         statusXPos / 2 + 4, 1, GlanceFunc, NULL);
-       mvprintw(3, statusXPos, "level   %5d", score.level);
-       mvprintw(5, statusXPos, "score%8d", score.score);
-       mvprintw(6, statusXPos, "lines%8d", score.lines);
+               8, statusXPos/2 + (Players[scr].nextShape/4 == 5 ? 3 : 4),
+               GlanceFunc); //draw; stick one more to the left
+       mvprintw(3, statusXPos, MSG_LEVEL, score.level);
+       mvprintw(5, statusXPos, MSG_SCORE, score.score);
+       mvprintw(6, statusXPos, MSG_LINES, score.lines);
        timer = CurTimeval() / 1e6;
        if (timer > 4) {
-               mvprintw(9, statusXPos, "ppm %9.1f", score.drops * 60 / timer);
+               mvprintw(9, statusXPos, MSG_PPM, score.pieces * 60 / timer);
                if (score.lines > 0) {
-                       mvprintw(7, statusXPos,
-                               "yield    %3d%%", 100 * score.adds / score.lines);
-                       mvprintw(10, statusXPos, "apm %9.1f", score.adds * 60 / timer);
+                       mvprintw(7, statusXPos, MSG_YIELD, 100 * score.adds / score.lines);
+                       mvprintw(10, statusXPos, MSG_APM, score.adds * 60 / timer);
                }
        } //display [ap]pm
        else {
@@ -402,15 +539,15 @@ ExtFunc void ShowScore(int scr, struct _Score score)
        } //too early to display stats, remove old..
 } //ShowScore
 
-ExtFunc void FieldMessage(int playa, char *message)
+void FieldMessage(int playa, char *message)
 { //put a message over playa's field
-       if (!Players[playa].spy) return;
+       if (!PlayerDisp[playa]) return;
        if (message) {
                char s[MAX_BOARD_WIDTH+1];
                memset(s, ' ', MAX_BOARD_WIDTH);
-               memcpy(&s[Players[playa].boardWidth - strlen(message) / 2],
+               memcpy(&s[(boardSize[playa] * Players[playa].boardWidth / 2) - (strlen(message) / 2)],
                        message, strlen(message));
-               s[Players[playa].boardWidth * 2] = 0;
+               s[boardSize[playa] * Players[playa].boardWidth] = 0;
 #ifdef HAVE_NCURSES
                attrset(A_REVERSE);
 #else
@@ -428,30 +565,46 @@ ExtFunc void FieldMessage(int playa, char *message)
        } //restore field
 } //FieldMessage
 
-ExtFunc void ShowPause(int playa)
+void ShowPause(int playa)
 { //put paused over player's field
-       if (Players[playa].alive)
+       if (Players[playa].alive > 0)
                if (Players[playa].flags & SCF_paused)
-                       FieldMessage(playa, Game.started > 1
-                               ? "P A U S E D" : "N O T  R E A D Y");
-               else FieldMessage(playa, Game.started > 1 ? NULL : "R E A D Y");
-       else FieldMessage(playa, playa > maxPlayer
-                       ? "E M P T Y" : "G A M E  O V E R");
+                       if (Game.started > 1)
+                               FieldMessage(playa, boardSize[playa] > 1 ? "P A U S E D" : "PAUSED");
+                       else
+                               FieldMessage(playa,
+                                       boardSize[playa] > 1 ? "N O T  R E A D Y" : "NOT  READY");
+               else
+                       if (Game.started > 1)
+                               FieldMessage(playa, NULL);
+                       else
+                               FieldMessage(playa, boardSize[playa] > 1 ? "R E A D Y" : "READY");
+       else if (!Players[playa].alive)
+               FieldMessage(playa,
+                       boardSize[playa] > 1 ? "G A M E  O V E R" : "GAME  OVER");
+       else
+               FieldMessage(playa, boardSize[playa] > 1 ? "E M P T Y" : "EMPTY");
 } //ShowPause
 
 
-ExtFunc void ShowTime(void)
+void ShowTime(void)
 { //display timer
        mvprintw(statusYPos, statusXPos, "timer %7.0f ", CurTimeval() / 1e6);
-//     move(boardYPos[0] + 1, boardXPos[0] + 2 * Players[0].boardWidth + 1);
-//     refresh();
 } //ShowTime
 
-ExtFunc void ScheduleFullRedraw(void)
+void ScheduleFullRedraw(void)
 {
        touchwin(stdscr);
 } //ScheduleFullRedraw
 
+void CatchWinCh(int sig)
+{ //handle window resize
+       endwin();    //exit curses
+       refresh();    //and reinit display (with different sizes)
+       InitFields();  //manually redraw everything
+       refresh();    //refresh
+} //CatchWinCh
+
 static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event)
 { //read keypresses
        if (MyRead(gen->fd, &event->u.key, 1))
diff --git a/curses.h b/curses.h
new file mode 100644 (file)
index 0000000..14597c6
--- /dev/null
+++ b/curses.h
@@ -0,0 +1,30 @@
+#ifndef __CURSES_H
+#define __CURSES_H
+
+extern int PlayerDisp[MAX_SCREENS];
+
+extern void InitScreens(void);
+extern void CleanupScreens(void);
+extern void GetTermcapInfo(void);
+extern void OutputTermStr(char *str, int flush);
+extern void DrawTitle(void);
+extern void DrawBox(int x1, int y1, int x2, int y2);
+extern void DrawField(int scr);
+extern void InitFields(void);
+extern void CleanupScreen(int scr);
+extern void DisplayMessage(char *p);
+extern void Messagef(char *fmt, ...);
+extern void Messagetype(char c, int x, char *s);
+extern void PlotBlock1(int y, int x, unsigned char type);
+extern void PlotBlock1S(int y, int x, unsigned char type);
+extern void PlotBlock(int scr, int y, int x, unsigned char type);
+extern void PlotBlockXY(int y, int x, unsigned char type);
+extern void ShowScore(int scr, struct _Score score);
+extern void FieldMessage(int playa, char *message);
+extern void ShowPause(int playa);
+extern void ShowTime(void);
+extern void ScheduleFullRedraw(void);
+extern void CatchWinCh(int sig);
+
+#endif //__CURSES_H
+
diff --git a/game.c b/game.c
index de0d605cfcdd0ee12648629d3548e1bd3c7224fc..6ad7e8b53a77c4e8291c3d16b71571c7732d5b27 100644 (file)
--- a/game.c
+++ b/game.c
 
 #define NOEXT
 #include "netris.h"
+
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
 #include <sys/types.h>
 #include <netinet/in.h>
-#include <setjmp.h>
+
+#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' },
-       { "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' },
@@ -55,7 +59,7 @@ static char *keyNames[KT_numKeys+1] = {
        "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}; //Sets
 
 static char keyTable[KT_numKeys+1];
 
@@ -63,14 +67,13 @@ static char *hostStr;
 static int paused = 0;
 static char lastadd;
 
-static sigjmp_buf close_env;
-
 
-ExtFunc void MapKeys(char *newKeys)
+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++) {
@@ -101,7 +104,7 @@ ExtFunc void MapKeys(char *newKeys)
                exit(1);
 } //MapKeys
 
-ExtFunc void WriteConf(void)
+void WriteConf(void)
 {
        FILE *file_out;
 
@@ -115,15 +118,15 @@ ExtFunc void WriteConf(void)
        fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
 } //WriteConf
 
-ExtFunc void HandleOption(char tag, char *value)
+void HandleOption(char tag, char *value)
 {
        switch (tag) {
                case 'a':       //ascii
-                       if (value && !strcasecmp(value, "0")) Game.ascii = 0;
-                       else Game.ascii = 1;
+                       if (value && !strcasecmp(value, "0")) Sets.ascii = 0;
+                       else Sets.ascii = 1;
                        break;
                case 'c':       //connect
-                       initConn = 1;
+                       game = GT_classicTwo;
                        hostStr = value;
                        break;
                case 'p':       //port
@@ -138,40 +141,22 @@ ExtFunc void HandleOption(char tag, char *value)
                        if (Players[0].score.level > 15)
                                Players[0].score.level = 15;
                        break;
+               case 'n':       //nick
+                       memcpy(Players[0].name, value, strlen(value) + 1);
+                       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;
+               case 'd':       //dropmode
+                       Sets.dropmode = atoi(value);
                        break;
                case 'C':       //color
-                       if (value && !strcasecmp(value, "1")) Game.color = 1;
-                       else Game.color = 0;
+                       if (value && !strcasecmp(value, "1")) Sets.color = 1;
+                       else Sets.color = 0;
                        break;
                case 'S':       //slowterm
-                       if (value && !strcasecmp(value, "1")) Game.standout = 1;
-                       else Game.standout = 0;
+                       if (value && !strcasecmp(value, "1")) Sets.standout = 1;
+                       else Sets.standout = 0;
                        break;
                case 'k':       //keys
                        MapKeys(value); break;
@@ -186,7 +171,7 @@ ExtFunc void HandleOption(char tag, char *value)
        }
 } //HandleParam
 
-ExtFunc void ReadConf(char *filename)
+void ReadConf(char *filename)
 {
        FILE *file_in;
        char buf[513];
@@ -220,16 +205,15 @@ ExtFunc void ReadConf(char *filename)
 
 } //ReadConf
 
-ExtFunc int StartNewPiece(int scr, Shape *shape)
+int StartNewPiece(int scr, char shape)
 {
-       if (Players[scr].nextShape) {
+       Players[scr].score.pieces++;
+       {
                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;
+       Players[scr].curX = Players[scr].boardWidth / 2 - 2;
        while (!ShapeVisible(Players[scr].curShape, scr,
                        Players[scr].curY, Players[scr].curX))
                Players[scr].curY--;
@@ -237,11 +221,11 @@ 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, 1);
+               Players[scr].curY, Players[scr].curX, scr == me);
        return 1;
 }
 
-ExtFunc void checkPaused(void)
+void checkPaused(void)
 { //check whether anyone paused the game
        int i;
 
@@ -251,11 +235,11 @@ ExtFunc void checkPaused(void)
        if (paused) paused = 1;
 } //checkPaused
 
-ExtFunc void StartGame(void)
+void StartGame(void)
 { //init new game
        int i;
 
-       maxPlayer = lastadd = me;
+       lastadd = me;
        SRandom(Game.seed);
        Game.speed = Game.initspeed;
        for (i = 1; i < Players[me].score.level; i++)
@@ -263,64 +247,384 @@ ExtFunc void StartGame(void)
        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;
+       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);
-               DrawField(i);
        } //reset all players
+       InitFields();
 } //StartGame
 
-ExtFunc void OneGame(void)
+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];
+
+                                       if (Game.gravity) junkLines = linesCleared - 1;
+                                       else junkLines = linesCleared - (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
+} //CheckClears
+
+void OneGame(void)
 {
-       MyEvent event;
-       int linesCleared, changed = 0;
+       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 (key == 13) {
+                       if (!(chatMode = !chatMode)) {
+                               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;
+                       } //leave chat mode
+               } //enter pressed (start/stop chat mode)
+               if (chatMode) {
+                       if (key == 27) //escape
+                               chatMode = 0;
+                       else if (key == 127 && chatText) //backspace
+                               chatText[strlen(chatText) - 1] = 0;
+                       else if (key != 13 && strlen(chatText) < MSG_WIDTH-1) //text
+                               chatText[strlen(chatText)] = key;
+                       Messagetype(key, strlen(chatText) - 1, chatText);
+                       return;
+               } //key in chat mode
+               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:
+               {
+                       FreezePiece(net.uid);
+                       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:
+                       checkPaused();
+                       oldPaused = 0;
+               {
+                       Players[net.uid].alive = -1;
+                       Message("%s left", Players[net.uid].name);
+                       checkPaused();
+                       ShowPause(net.uid);
+                       changed = 1;
+                       break;
+               } //player left
+               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 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;
 
        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 >= 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 (1) {
+       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) Messagef("\\%dYou died",
+                               if (lastadd == me) Message("\\%dYou died",
                                        Players[me].team > 7 ? 7 : Players[me].team);
-                               else Messagef("\\%d%s fragged you",
+                               else Message("\\%d%s fragged you",
                                        Players[lastadd].team > 7 ? 7 : Players[lastadd].team,
                                        Players[lastadd].name);
                                if (game == GT_classicTwo)
@@ -330,332 +634,42 @@ GameLoop:
                        } //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);
+                                       SendPacket(me, NP_newPiece, sizeof(Players[me].curShape), &Players[me].curShape);
                                } //send new piece
                        }
                } //new piece
-               while (1) {
+               while (gameStatus == 2) {
                        for (i = 1; i < MAX_SCREENS; i++)
-                               if (Players[i].alive > 0 && Players[i].spy)
+                               if (Players[i].alive > 0 && PlayerDisp[i])
                                        changed |= RefreshBoard(i);
                        if (changed) {
                                if (!paused) ShowTime();
                                refresh();
                                changed = 0;
                        } //screen update
-                       playercount = 0;
+                       {
+                       short playercount = 0;
                        for (i = 1; i < MAX_SCREENS; i++)
                                if (Players[i].alive >= 0) playercount++;
-                       if (playercount < 1) goto gameOver;
-                       CheckNetConn();
+                       if (playercount < 1) gameStatus = 0;
+                       }
                        switch (WaitMyEvent(&event, EM_any)) {
                                case E_alarm:
                                        if (!paused && Players[me].alive > 0)
-                                               if (!MovePiece(me, -1, 0))
-                                                       goto nextPiece;
-                                               else if (spied)
-                                                       SendPacket(me, NP_down, 0, NULL);
+                                               if (!MovePiece(me, -1, 0)) //move down
+                                                       gameStatus = 1; //new piece
+                                               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) {
-                                               RobotCmd(1, "UserKey %d %s\n",
-                                                               (int)(unsigned char)event.u.key,
-                                                               p ? keyNames[key] : "?");
-                                               break;
-                                       } //let robot handle keypress
-                                       if (!p) break;
-                               keyEvent:
-                                       if (Players[me].alive <= 0 && key != KT_quit) break;
-                                       if (paused && key < KT_pause) break;
-                                       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, 0) && 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);
-                                                       }
-                                                       else goto nextPiece;
-                                                       break;
-                                               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;
-                                                       }
-                                                       else goto nextPiece;
-                                                       dropMode = Players[me].dropmode;
-                                                       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)
-                                                               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:
-                                                       DrawTitle();
-                                                       InitFields();
-//                                                     ScheduleFullRedraw();
-                                                       for (i = 1; i < MAX_SCREENS; i++)
-                                                               if (Players[i].spy && Players[i].alive > 0)
-                                                                       RefreshBoard(i);
-                                                       refresh();
-                                                       break;
-                                               case KT_quit:
-                                                       ShowPause(me);
-                                                       refresh();
-                                                       goto gameOver;
-                                       } //E_key
-                                       if (dropMode && DropPiece(me) > 0) {
-                                               SetITimer(Game.speed, Game.speed);
-                                               if (spied)
-                                                       SendPacket(me, NP_drop, 0, NULL);
-                                       }
+                                       GameKey(event.u.key);
                                        break;
-                               case E_robot:
-                               {
-                                       int num;
-
-                                       cmd = event.u.robot.data;
-                                       if ((p = strchr(cmd, ' ')))
-                                               *p++ = 0;
-                                       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")) {
-                                               Messagef(p);
-                                               changed = 1;
-                                       }
-                                       break;
-                               } //E_robot
                                case E_net:
-                                       switch(event.u.net.type) {
-                                               case NP_newPiece:
-                                               {
-                                                       short shapeNum;
-                                                       netint2 data[1];
-
-                                                       FreezePiece(event.u.net.uid);
-                                                       memcpy(data, event.u.net.data, sizeof(data));
-                                                       shapeNum = ntoh2(data[0]);
-                                                       StartNewPiece(event.u.net.uid,
-                                                               NetNumToShape(shapeNum));
-                                                       break;
-                                               } //new piece
-                                               case NP_down:
-                                                       MovePiece(event.u.net.uid, -1, 0);
-                                                       break;
-                                               case NP_left:
-                                                       MovePiece(event.u.net.uid, 0, -1);
-                                                       break;
-                                               case NP_right:
-                                                       MovePiece(event.u.net.uid, 0, 1);
-                                                       break;
-                                               case NP_rotleft:
-                                                       RotatePiece(event.u.net.uid, 0);
-                                                       break;
-                                               case NP_rotright:
-                                                       RotatePiece(event.u.net.uid, 1);
-                                                       break;
-                                               case NP_drop:
-                                                       DropPiece(event.u.net.uid);
-                                                       break;
-                                               case NP_clear:
-                                                       ClearFullLines(event.u.net.uid);
-                                                       break;
-                                               case NP_insertJunk:
-                                               {
-                                                       netint2 data[2];
-
-                                                       memcpy(data, event.u.net.data, sizeof(data));
-                                                       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:
-                                               {
-                                                       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 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
+                                       GameNet(event.u.net);
                                        break;
-                               case E_lostRobot:
                                case E_lostConn:
                                        goto gameOver;
-                               default:
-                                       break;
                        } //handle event
                        if (paused != oldPaused) {
                                if (paused) {
@@ -669,53 +683,23 @@ GameLoop:
                                oldPaused = paused;
                        } //(un)pause
                } //game loop
-       nextPiece:
                dropMode = 0;
-               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(me, NP_giveJunk, sizeof(data), data);
-                       Messagef("\\%dYou sent %d lines",
-                               Players[me].team > 7 ? 7 : Players[me].team, junkLines);
-               } //send junk to others
+               CheckClears(me);
        } //new piece loop
 gameOver:
        SetITimer(0, 0);
 }
 
-ExtFunc void CatchInt(int sig)
-{
-       siglongjmp(close_env, 1);
-}
-
-ExtFunc int main(int argc, char **argv)
+int main(int argc, char **argv)
 {
        char ch;
 
+       game = GT_onePlayer;
        port = DEFAULT_PORT;
-       Game.standout = Game.color = 1;
+       maxPlayer = 1;
        Game.initspeed = DEFAULT_INTERVAL;
+       Game.gravity = 0;
        MapKeys(DEFAULT_KEYS);
        {
                int i;
@@ -723,7 +707,7 @@ ExtFunc int main(int argc, char **argv)
 
                for (i = 0; i < MAX_SCREENS; i++) {
                        Players[i].alive = -1;
-                       Players[i].score.level = Players[i].spy = 1;
+                       Players[i].score.level = 1;
                        Players[i].boardWidth = 10;
                        Players[i].boardHeight = MAX_BOARD_HEIGHT;
                        Players[i].boardVisible = 20;
@@ -736,6 +720,7 @@ ExtFunc int main(int argc, char **argv)
                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')
@@ -743,36 +728,29 @@ ExtFunc int main(int argc, char **argv)
 //     else
        ReadConf(CONFIG_FILE);
        while ((ch = getopt_long(argc, argv,
-                       "hHRr:Fk:c:odDSCap:i:l:t:", options, NULL)) != -1)
+                       "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");
 //     WriteConf();
 
-       if (sigsetjmp(close_env, 1))
-               exit(0);
-       signal(SIGINT, CatchInt);       //handle exit (^C)
        InitScreens();                          //setup screen
-       DrawTitle();
-       if (initConn) {
-               game = GT_classicTwo;
+       if (game == GT_classicTwo) {
                spied = 1;
                InitiateConnection(hostStr, port);
                HandShake();
+               maxPlayer = me;
                checkPaused();
                OneGame();
        } //client
        else {
-               game = GT_onePlayer;
                Game.seed = time(0);
                Game.started = 2;
-               Game.maxplayers = 1;
                me = 1;
-               memcpy(&Players[me], &Players[0], sizeof(Player));
+               memcpy(&Players[me], &Players[0], sizeof(_Player));
+               Players[me].team = 7;
                OneGame();
        } //singleplay
        return 0;
diff --git a/inet.c b/inet.c
index 1549aa0b388b44c8c7b0c7a3d20e5133732649ce..8da9956b16917e3f236a9409432c8df139553e32 100644 (file)
--- a/inet.c
+++ b/inet.c
@@ -20,6 +20,7 @@
  */
 
 #include "netris.h"
+
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <netdb.h>
 #include <string.h>
 #include <errno.h>
+#include <setjmp.h>
+
+#include "inet.h"
 
 #define HEADER_SIZE sizeof(netint2[2])
 #define HEADER_SIZE3 sizeof(netint4[3])
 
-ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
 EventGenRec netGen =
        { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE3 };
 
 
-ExtFunc int InitiateConnection(char *hostStr, short port)
+static sigjmp_buf close_env;
+
+void CatchInt(int sig)
+{
+       siglongjmp(close_env, 1);
+} //CatchInt
+
+int InitiateConnection(char *hostStr, short port)
 { //connect to host
        struct sockaddr_in addr;
        struct hostent *host;
 
+       if (sigsetjmp(close_env, 1))
+               exit(0);
+       signal(SIGINT, CatchInt);  //handle exit (^C)
        AtExit(CloseNet);
        host = gethostbyname(hostStr);
        if (!host)
@@ -65,7 +79,7 @@ ExtFunc int InitiateConnection(char *hostStr, short port)
        return 0;
 } //InitiateConnection
 
-ExtFunc void HandShake(void)
+void HandShake(void)
 { //talk to your host
        MyEvent event;
 
@@ -78,16 +92,15 @@ ExtFunc void HandShake(void)
 
        do {
                if (WaitMyEvent(&event, EM_net) == E_net)
-               switch (event.u.net.type) {
+                       switch (event.u.net.type) {
                        case NP_hello:
                        {
                                me = event.u.net.uid;
-                               memcpy(&Players[me], &Players[0], sizeof(Player));
+                               memcpy(&Players[me], &Players[0], sizeof(_Player));
                                fprintf(stderr, "Accepted (%s) as #%d (%s)\n",
                                        event.u.net.data, me, Players[me].name);
                                SendPacket(0, NP_newPlayer,
-                                       sizeof(Player) - sizeof(Players[me].host)
-                                       - sizeof(Players[me].spy) - sizeof(Players[me].small),
+                                       sizeof(_Player) - sizeof(Players[me].host),
                                        &Players[me]);
                                break;
                        }
@@ -122,19 +135,15 @@ ExtFunc void HandShake(void)
                        } //NP_error
                        default:
                                break;
-               }
+                       }
                else
                        fatal("Hm, the party apparantly ended prematurely.");
        }
        while (event.u.net.type != NP_gamedata);
 } //HandShake
 
-ExtFunc void CheckNetConn(void)
-{ //am I necessary?
-}
-
 
-ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
 { //receive
        int result;
        short uid, type, size;
@@ -168,7 +177,7 @@ ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
        return E_net;
 } //NetGenFunc
 
-ExtFunc void SendPacket(short uid, NetPacketType type, int size, void *data)
+void SendPacket(short uid, NetPacketType type, int size, void *data)
 { //send shit to server
        netint4 header[3];
 
@@ -181,7 +190,7 @@ ExtFunc void SendPacket(short uid, NetPacketType type, int size, void *data)
                die("write");
 } //SendPacket
 
-ExtFunc void CloseNet(void)
+void CloseNet(void)
 { //kick some connection's ass!
        MyEvent event;
 
diff --git a/inet.h b/inet.h
new file mode 100644 (file)
index 0000000..fbeb0ba
--- /dev/null
+++ b/inet.h
@@ -0,0 +1,12 @@
+#ifndef __INET_H
+#define __INET_H
+
+extern MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+extern int InitiateConnection(char *hostStr, short port);
+extern void HandShake(void);
+extern MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+extern void SendPacket(short uid, NetPacketType type, int size, void *data);
+extern void CloseNet(void);
+
+#endif //__INET_H
+
diff --git a/msg.en.h b/msg.en.h
new file mode 100644 (file)
index 0000000..972fa3c
--- /dev/null
+++ b/msg.en.h
@@ -0,0 +1,8 @@
+#define MSG_NEXT       "next        "
+#define MSG_LEVEL      "level   %5d"
+#define MSG_SCORE      "score%8d"
+#define MSG_LINES      "lines%8d"
+#define MSG_PPM                "ppm %9.1f"
+#define MSG_APM                "apm %9.1f"
+#define MSG_YIELD      "yield    %3d%%"
+
index b8a153c0252fa147fd6b94ffea34764b93d89ef9..edc7b30a479d526c115a8cef1fcde501712bf21c 100644 (file)
@@ -1,9 +1,6 @@
 ### NETRIS 0.5.82 Config file ###
 
-Keys   = 4685 2
-Color  = 1
-InstaDrop
-Handicap= 1
-ascii  = 0
-#spy = 10
-#spy = 20
+Keys           = 4685 2
+Color          = 1
+Handicap       = 1
+ascii          = 0
index a361c2fd489ebe92d871713317798f976edd9c10..cab651cf0a97f22098e4b589985a0de65b4602ea 100644 (file)
--- a/netris.h
+++ b/netris.h
  * $Id: netris.h,v 1.28 1999/05/16 06:56:29 mhw Exp $
  */
 
-#ifndef NETRIS_H
-#define NETRIS_H
+#ifndef __NETRIS_H
+#define __NETRIS_H
 
 #include "config.h"
+
 #include <sys/time.h>
 #include <assert.h>
 #include <stdio.h>
 #include <signal.h>
 
-#define version_string         "0.7.821"
-
-#define ExtFunc                /* Marks functions that need prototypes */
+#define version_string         "0.8"
 
 #ifdef NOEXT   //prevent re-declaration
 # define EXT
@@ -61,7 +60,6 @@ typedef long netint4;
 /* Protocol versions */
 #define MAJOR_VERSION          1       
 #define PROTOCOL_VERSION       4
-#define ROBOT_VERSION          1
 
 #define DEFAULT_PORT 9284      /* Very arbitrary */
 
@@ -79,7 +77,6 @@ typedef long netint4;
 #define EM_alarm                       000001
 #define EM_key                         000002
 #define EM_net                         000004
-#define EM_robot                       000010
 #define EM_connect                     000020
 #define EM_any                         000777
 
@@ -93,7 +90,7 @@ typedef enum _Dir { D_down, D_right, D_up, D_left } Dir;
 typedef enum _Cmd { C_end, C_forw, C_back, C_left, C_right, C_plot } Cmd;
 typedef enum _FDType { FT_read, FT_write, FT_except, FT_len } FDType;
 typedef enum _MyEventType {
-       E_none, E_alarm, E_key, E_connect, E_net, E_lostConn, E_robot, E_lostRobot
+       E_none, E_alarm, E_key, E_connect, E_net, E_lostConn
 } MyEventType;
 typedef enum _NetPacketType {
        NP_endConn,             //client/server quits
@@ -110,6 +107,8 @@ typedef enum _NetPacketType {
        NP_argghhh,             //player died
        NP_part,                //player left
 
+       NP_msg,                 //chat message
+
        NP_newPiece,    //new piece info
        NP_rotright,    //rotate piece clockwise
        NP_rotleft,             //rotate piece counterclockwise
@@ -123,18 +122,17 @@ typedef enum _NetPacketType {
        NP_giveJunk             //player has to add junk
 } NetPacketType;
 
-typedef signed char BlockType;
-
+typedef struct {
+       short sender, uid;
+       NetPacketType type;
+       int size;
+       void *data;
+} _netEvent;
 typedef struct _MyEvent {
        MyEventType type;
        union {
                char key;
-               struct {
-                       short sender, uid;
-                       NetPacketType type;
-                       int size;
-                       void *data;
-               } net;
+               _netEvent net;
                struct {
                        int size;
                        char *data;
@@ -160,27 +158,13 @@ typedef struct _EventGenRec {
 MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
 
 typedef struct _Shape {
-       struct _Shape *rotateTo, *rotateFrom;
-       int initY, initX, mirrored;
-       Dir initDir;
-       BlockType type;
-       Cmd *cmds;
+       char shape, rotate;
 } Shape;
 
-typedef struct _ShapeOption {
-       float weight;
-       Shape *shape;
-} ShapeOption;
-
-typedef int (*ShapeDrawFunc)(int scr, int y, int x,
-                                       BlockType type, void *data);
-
 /* NP_startConn flags */
-#define SCF_usingRobot         000001
-#define SCF_fairRobot          000002
-#define SCF_paused                     000004
+#define SCF_paused             1
 
-typedef struct _Player {
+typedef struct {
        int alive;
        char name[16];
        int flags;
@@ -188,16 +172,15 @@ typedef struct _Player {
        int dropmode;
        int boardHeight, boardWidth, boardVisible;
        int curX, curY;
-       Shape *curShape, *nextShape;
+       char curShape, nextShape;
        struct _Score {
                short level;
                long score;
-               int drops, lines, adds;
+               int pieces, lines, adds;
        } score;
-       char host[256]; //last-1
-       int spy,small;  //last
-} Player;
-EXT Player Players[MAX_SCREENS];
+       char host[256]; //last
+} _Player;
+EXT _Player Players[MAX_SCREENS];
 EXT short me;
 EXT short maxPlayer;
 EXT int spied; //in player.flags
@@ -206,31 +189,23 @@ EXT int spied; //in player.flags
 #define SPEEDINC                       1.2
 #define SPEEDMINIMUM           40000
 
-typedef struct __Game {
-       int maxplayers; //1
+typedef struct {
+       int gravity;    //1
        int started;    //2
        int continuous; //3
        long seed;              //4
        int initspeed;  //5
        int speed;
-       int standout, color, ascii;
 } _Game;
 EXT _Game Game;
 
-EXT GameType game;
-EXT int robotEnable, robotVersion, fairRobot;
-EXT int protocolVersion;
-
-EXT int initConn;
-EXT short port;
-
-EXT char scratch[1024];
+#define MSG_WIDTH 128
 
-extern ShapeOption stdOptions[];
+EXT GameType game; // => Game.type
 
-#include "proto.h"
+EXT short port; // => just in game.c, parameter to inet connect
 
-#endif /* NETRIS_H */
+#endif //__NETRIS_H
 
 /*
  * vi: ts=4 ai
diff --git a/robot.c b/robot.c
deleted file mode 100644 (file)
index 31bb5d8..0000000
--- a/robot.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Netris -- A free networked version of T*tris
- * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * 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: robot.c,v 1.8 1996/02/09 08:22:15 mhw Exp $
- */
-
-#include "netris.h"
-#include <unistd.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-
-static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event);
-static EventGenRec robotGen =
-               { NULL, 0, FT_read, -1, RobotGenFunc, EM_robot };
-
-static int robotProcess;
-static FILE *toRobot;
-static int toRobotFd, fromRobotFd;
-
-static char robotBuf[128];
-static int robotBufSize, robotBufMsg;
-
-static int gotSigPipe;
-
-ExtFunc void InitRobot(char *robotProg)
-{
-       int to[2], from[2];
-       int status;
-       MyEvent event;
-
-       signal(SIGPIPE, CatchPipe);
-       AtExit(CloseRobot);
-       if (pipe(to) || pipe(from))
-               die("pipe");
-       robotProcess = fork();
-       if (robotProcess < 0)
-               die("fork");
-       if (robotProcess == 0) {
-               dup2(to[0], STDIN_FILENO);
-               dup2(from[1], STDOUT_FILENO);
-               close(to[0]);
-               close(to[1]);
-               close(from[0]);
-               close(from[1]);
-               execl("/bin/sh", "sh", "-c", robotProg, NULL);
-               die("execl failed");
-       }
-       close(to[0]);
-       close(from[1]);
-       toRobotFd = to[1];
-       robotGen.fd = fromRobotFd = from[0];
-       if (!(toRobot = fdopen(toRobotFd, "w")))
-               die("fdopen");
-       if ((status = fcntl(fromRobotFd, F_GETFL, 0)) < 0)
-               die("fcntl/F_GETFL");
-       status |= O_NONBLOCK;
-       if (fcntl(fromRobotFd, F_SETFL, status) < 0)
-               die("fcntl/F_SETFL");
-       AddEventGen(&robotGen);
-       RobotCmd(1, "Version %d\n", ROBOT_VERSION);
-       if (WaitMyEvent(&event, EM_robot) != E_robot)
-               fatal("Robot didn't start successfully");
-       if (1 > sscanf(event.u.robot.data, "Version %d", &robotVersion)
-                       || robotVersion < 1)
-               fatal("Invalid Version line from robot");
-       if (robotVersion > ROBOT_VERSION)
-               robotVersion = ROBOT_VERSION;
-}
-
-ExtFunc void CatchPipe(int sig)
-{
-       robotGen.ready = gotSigPipe = 1;
-}
-
-ExtFunc void RobotCmd(int flush, char *fmt, ...)
-{
-       va_list args;
-
-       va_start(args, fmt);
-       vfprintf(toRobot, fmt, args);
-       va_end(args);
-       if (flush)
-               fflush(toRobot);
-}
-
-ExtFunc void RobotTimeStamp(void)
-{
-       RobotCmd(1, "TimeStamp %.3f\n", CurTimeval() / 1.0e6);
-}
-
-ExtFunc void CloseRobot(void)
-{
-       RemoveEventGen(&robotGen);
-       if (robotProcess > 0)
-               RobotCmd(1, "Exit\n");
-       fclose(toRobot);
-       close(fromRobotFd);
-}
-
-static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event)
-{
-       static int more;
-       int result, i;
-       char *p;
-
-       if (gotSigPipe) {
-               gotSigPipe = 0;
-               robotGen.ready = more;
-               return E_lostRobot;
-       }
-       if (robotBufMsg > 0) {
-               /*
-                *      Grrrrrr!  SunOS 4.1 doesn't have memmove (or atexit)
-                *  I'm told some others have a broken memmove
-                *
-                *      memmove(robotBuf, robotBuf + robotBufMsg,
-                *                      robotBufSize - robotBufMsg);
-                */
-               for (i = robotBufMsg; i < robotBufSize; ++i)
-                       robotBuf[i - robotBufMsg] = robotBuf[i];
-
-               robotBufSize -= robotBufMsg;
-               robotBufMsg = 0;
-       }
-       if (more)
-               more = 0;
-       else {
-               do {
-                       result = read(fromRobotFd, robotBuf + robotBufSize,
-                                       sizeof(robotBuf) - robotBufSize);
-               } while (result < 0 && errno == EINTR);
-               if (result <= 0)
-                       return E_lostRobot;
-               robotBufSize += result;
-       }
-       if (!(p = memchr(robotBuf, '\n', robotBufSize))) {
-               if (robotBufSize >= sizeof(robotBuf))
-                       fatal("Line from robot is too long");
-               return E_none;
-       }
-       *p = 0;
-       robotBufMsg = p - robotBuf + 1;
-       robotGen.ready = more = (memchr(robotBuf + robotBufMsg, '\n',
-                       robotBufSize - robotBufMsg) != NULL);
-       event->u.robot.size = p - robotBuf;
-       event->u.robot.data = robotBuf;
-       return E_robot;
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
diff --git a/robot_desc b/robot_desc
deleted file mode 100644 (file)
index 53415b2..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-$Id: robot_desc,v 1.4 1999/05/16 06:56:30 mhw Exp $
-
-
-GENERAL PROTOCOL
-================
-When you pass the "-r <robot>" option to Netris, it launches
-"/bin/sh -c <robot>" as a subprocess and communicates to it via pipes.
-
-The robot reads events from Netris through stdin, and writes commands to
-stdout.  All exchanges are ASCII lines composed of tokens separated by
-spaces.  The first token in a line is the name of the command.
-
-The robot should ignore commands which it doesn't recognize.  The protocol
-may be extended by adding extra commands without incrementing the version
-number.  The version number will only be increased when a command cannot
-be safely ignored.
-
-Netris will also ignore commands which it doesn't recognize, for the same
-reason.
-
-
-INITIALIZATION
-==============
-The initial exchange between Netris and the robot is Version negotiation.
-Each sends a "Version <num>" line to the other, and the lowest version is
-used.  Currently, the robot protocol version is 1.
-
-Next, Netris sends "GameType <type>", there <type> is either OnePlayer
-or ClassicTwo.  There may be other games in the future.
-
-Then Netris sends "BoardSize <player> <height> <width>" for each player.
-<player> is 0 for the computer player and 1 for the opponent, if any.
-Other numbers may be used in the future.
-
-For each opponent, Netris sends "Opponent <player> <username> <host>".
-<host> is not necessarily a fully qualified host name, unfortunately.
-It might even be something like "localhost".  
-
-For each opponent, Netris may send 0 or more flags associated with the
-opponent.  For each flag which is true, Netris sends
-"OpponentFlag <player> <flag>".  Currently, the flags are "robot" and
-"fairRobot".
-
-Next, Netris sends "TickLength <seconds>", where <seconds> is the number
-of seconds between pieces stepping down.
-
-Finally, a "BeginGame" command is sent to the robot.
-
-
-NORMAL GAME (Netris --> robot)
-==============================
-Here's a list of commands sent from Netris to the robot, and a brief
-description of each one.
-
-Exit
-----
-This is always sent to the robot when the game is over, for any reason.
-The robot should exit immediately.
-
-NewPiece <num>
---------------
-This command is never sent in "fair" robot mode.
-
-Every time a new piece is created, this command is sent to the robot.
-<num> is a positive integer uniquely identifying the piece.  <num> should
-be sent as a parameter to each movement command (sent to Netris) in
-order to prevent accidental movement of the wrong piece.
-
-TimeStamp <seconds>
--------------------
-This command may be sent to the robot at any time.  <seconds> is
-a floating point number of seconds since the beginning of the game.
-One is always sent immediately after "BeginGame" and "RowUpdate" commands.
-One will be sent at least every tick (see "TickLength") unless the game
-is paused.
-
-RowUpdate <player> <row> <col0> <col1> <col2> ... <coln>
---------------------------------------------------------
-Whenever the screen changes, a group of these commands is sent to the
-robot followed by a "TimeStamp".  After a "RowUpdate" command, the robot's
-view of the board is incorrect until the "TimeStamp".
-
-<player> is 0 for the computer player and positive numbers for opponents.
-<row> is an integer from 0 to boardHeight-1.  0 is the bottom row.
-
-<col0> ... <coln> are integers separated by spaces, one for each column.
-"0" indicates an empty square.  Positive integers indicates blocks.
-Currently only "1" is used, but in the future there may be special kinds of
-blocks indicated by higher numbers.  Negative integers indicate part of
-the currently falling piece.  For each block, the absolute value of the
-number indicates the type of piece, and the sign indicates whether it is
-currently falling.
-
-If Netris is in "fair robot" (-F) mode, Netris will not highlight the
-falling piece with negative numbers.  In this case, all numbers will
-be non-negative.
-
-UserKey <key> <keyname>
------------------------
-Whenever the user presses a key, this command is sent to the robot.  The
-key is not automatically interpreted by Netris.
-
-<key> is the ascii value of the key, from 0 to 255.  <keyname> is one
-of the following strings: "Left", "Rotate", "Right", "Drop", "Down",
-"ToggleSpy", "Pause", or "?".  When possible, you should use <keyname>,
-since it will pay attention to keyboard remappings.
-
-For each possible <keyname> (other than "?"), there's an equivalent
-command recognized by Netris from the robot which performs the equivalent
-of the key.  Therefore, if you want give the user "manual" control, you
-can send Netris "<keyname> <piecenum>".
-
-Pause <pausedByMe> <pausedByThem>
----------------------------------
-<pausedByMe> is 0 or 1, indicating whether the game is currently paused by
-our side.  <pausedByThem> is 0 or 1, indicating whether any player other
-than our side has paused the game.  If either is 1, the game is paused.
-
-You may actually receive this command even when neither of the flags change.
-
-
-NORMAL GAME (robot --> Netris)
-==============================
-Here's a list of commands recognized by Netris from the robot:
-
-Left <num>
-Rotate <num>
-Right <num>
-Drop <num>
-Down <num>
-ToggleSpy <num>
-Pause <num>
----------------
-These commands perform the equivalent of typing the corresponding command
-on the keyboard, if you weren't in robot mode.  
-
-<num> is checked against the current piece number (the value sent along
-with "NewPiece" commands).  If it doesn't match, the command is ignored.
-However, in "fair robot" mode, the <num> is ignored.
-
-These commands (except "Pause") are also ignored if the game is paused.
-
-Message <message>
------------------
-<message> is printed on the messages part of the display.  Messages too
-long to fit on the screen may be truncated.
-
-<message> may contain spaces and printable characters only.
-
-
-EXAMPLE
-=======
-Here's a portion of an example log generated by the sample robot.  The
-sample robot generates a log file in "log" if the "-l" is given to sr
-(eg "netris -r 'sr -l'").
-
-In this log file, every line is preceeded by two characters.  Lines
-sent from Netris to the robot are preceeded by two spaces "  ", and
-lines sent to Netris are preceeded by "> ".
-
-> Version 1
-  Version 1
-  GameType OnePlayer
-  BoardSize 0 20 10
-  TickLength 0.300
-  BeginGame
-  TimeStamp 0.009
-  NewPiece 1
-  RowUpdate 0 19 0 0 0 0 0 -1 -1 0 0 0
-  TimeStamp 0.010
-  RowUpdate 0 19 0 0 0 0 -1 -1 0 0 0 0
-  RowUpdate 0 18 0 0 0 0 0 -1 -1 0 0 0
-  TimeStamp 0.314
-> Message Goal 0 : ** :**  :    :    :
-> Left 1
-  TimeStamp 0.352
-  RowUpdate 0 19 0 0 0 -1 -1 0 0 0 0 0
-  RowUpdate 0 18 0 0 0 0 -1 -1 0 0 0 0
-  TimeStamp 0.362
-> Left 1
-  RowUpdate 0 19 0 0 -1 -1 0 0 0 0 0 0
-  RowUpdate 0 18 0 0 0 -1 -1 0 0 0 0 0
-  TimeStamp 0.375
-> Left 1
-  RowUpdate 0 19 0 -1 -1 0 0 0 0 0 0 0
-  RowUpdate 0 18 0 0 -1 -1 0 0 0 0 0 0
-  TimeStamp 0.387
-> Left 1
-  RowUpdate 0 19 -1 -1 0 0 0 0 0 0 0 0
-  RowUpdate 0 18 0 -1 -1 0 0 0 0 0 0 0
-  TimeStamp 0.399
-> Drop 1
-  RowUpdate 0 19 0 0 0 0 0 0 0 0 0 0
-  RowUpdate 0 18 0 0 0 0 0 0 0 0 0 0
-  RowUpdate 0 1 -1 -1 0 0 0 0 0 0 0 0
-  RowUpdate 0 0 0 -1 -1 0 0 0 0 0 0 0
-  TimeStamp 0.413
-  NewPiece 2
-  RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
-  RowUpdate 0 1 1 1 0 0 0 0 0 0 0 0
-  RowUpdate 0 0 0 1 1 0 0 0 0 0 0 0
-  TimeStamp 0.715
-  RowUpdate 0 19 0 0 0 0 -1 -1 -1 0 0 0
-  RowUpdate 0 18 0 0 0 0 0 -1 0 0 0 0
-  TimeStamp 1.014
-> Message Goal 3 :*** : *  :    :    :
-> Rotate 2
-  TimeStamp 1.053
-  RowUpdate 0 19 0 0 0 0 0 -1 -1 0 0 0
-  RowUpdate 0 18 0 0 0 0 0 -1 0 0 0 0
-  TimeStamp 1.062
-  RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
-  RowUpdate 0 18 0 0 0 0 0 -1 -1 0 0 0
-  RowUpdate 0 17 0 0 0 0 0 -1 0 0 0 0
-  TimeStamp 1.314
-> Rotate 2
-  RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
-  RowUpdate 0 18 0 0 0 0 -1 -1 -1 0 0 0
-  RowUpdate 0 17 0 0 0 0 0 0 0 0 0 0
-  TimeStamp 1.326
-[...]
-  Exit
-
-
-# vi: tw=70 ai
index 6fe46f0c49f25c72c63ec8b54c37d1728481d26f..39222bf6da6623ee14838c5bd426cae2ab8c6c7c 100644 (file)
--- a/server.c
+++ b/server.c
@@ -21,6 +21,7 @@
 
 #define NOEXT
 #include "netris.h"
+
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
 #include <errno.h>
 #include <setjmp.h>
 
+#include "util.h"
+
 #define HEADER_SIZE sizeof(netint4[3])
 
 static struct option options[] = {
        { "wait",               0, 0, 'w' },
        { "port",               1, 0, 'p' },
+       { "quadra",             1, 0, 'q' },
        { "min-players",1, 0, 'm' },
        { "max-players",1, 0, 'x' },
        { "continuous", 1, 0, 'c' },
@@ -49,14 +53,13 @@ static struct option options[] = {
 };
 
 static char minplayers = 2;
+static char maxplayers = 8;
 static char playercount;
 static char verbose = 0;
 
 struct sockaddr_in addr;
 
-static char *gameNames[GT_len] = { "OnePlayer", "ClassicTwo" };
-
-ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
 static EventGenRec netGen[MAX_SCREENS] = {
        { NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE } };
 
@@ -73,51 +76,13 @@ static EventGenRec *nextGen = &alarmGen;
 static sigjmp_buf close_env;
 
 
-ExtFunc volatile void die(char *msg)
-{
-       perror(msg);
-       exit(1);
-} //die
-
-ExtFunc int MyRead(int fd, void *data, int len)
-{
-       int result, left;
-
-       left = len;
-       while (left > 0) {
-               result = read(fd, data, left);
-               if (result > 0) {
-                       data = ((char *)data) + result;
-                       left -= result;
-               }
-               else if (errno != EINTR)
-                       return result;
-       }
-       return len;
-} //MyRead
-
-ExtFunc int MyWrite(int fd, void *data, int len)
-{
-       int result, left;
-
-       left = len;
-       while (left > 0) {
-               result = write(fd, data, left);
-               if (result > 0) {
-                       data = ((char *)data) + result;
-                       left -= result;
-               }
-               else if (errno != EINTR)
-                       return result;
-       }
-       return len;
-} //MyWrite
-
-ExtFunc void SendPacketTo(short playa, short uid, NetPacketType type, int size, void *data)
+void SendPacketTo(short playa, short uid, NetPacketType type, int size, void *data)
 { //send to someone
        netint4 header[3];
 
        if (netGen[playa].fd >= 0) {
+               if (verbose)
+                       fprintf(stderr, ": send %d from %d to %d\n", type, uid, playa);
                header[0] = hton4(uid);
                header[1] = hton4(type);
                header[2] = hton4(size + HEADER_SIZE);
@@ -133,35 +98,7 @@ static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
        return E_alarm;
 } //AlarmGenFunc
 
-ExtFunc void AddEventGen(EventGenRec *gen)
-{
-       assert(gen->next == NULL);
-       assert(nextGen->next != (void*)0xffffffff);
-       gen->next = nextGen->next;
-       nextGen->next = gen;
-} //AddEventGen
-
-ExtFunc void RemoveEventGen(EventGenRec *gen)
-{
-       // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
-       if (gen->next) {
-               while (nextGen->next != gen)
-                       nextGen = nextGen->next;
-               nextGen->next = gen->next;
-               gen->next = NULL;
-       }
-} //RemoveEventGen
-
-ExtFunc void AtExit(void (*handler)(void))
-{ //setup something to do at exit (^C)
-#ifdef HAS_ON_EXIT
-       on_exit((void *)handler, NULL);
-#else
-       atexit(handler);
-#endif
-} //AtExit
-
-ExtFunc void SCloseNet(short playa)
+void SCloseNet(short playa)
 { //kick some connection's ass!
        MyEvent event;
 
@@ -177,7 +114,7 @@ ExtFunc void SCloseNet(short playa)
                RemoveEventGen(&netGen[playa]);
 } //SCloseNet
 
-ExtFunc void CloseNets(void)
+void CloseNets(void)
 { //nou oogjes dicht en snaveltjes toe
        int i;
 
@@ -187,60 +124,7 @@ ExtFunc void CloseNets(void)
        fprintf(stderr, "* All Done\n\n");
 } //CloseNets
 
-ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
-{ //poll
-       int i, retry = 0;
-       fd_set fds[FT_len];
-       EventGenRec *gen;
-       int result, anyReady, anySet;
-       struct timeval tv;
-
-       for (;;) {
-               for (i = 0; i < FT_len; ++i)
-                       FD_ZERO(&fds[i]);
-               anyReady = anySet = 0;
-               gen = nextGen;
-               do {
-                       if (gen->mask & mask) {
-                               if (gen->ready)
-                                       anyReady = 1;
-                               if (gen->fd >= 0) {
-                                       FD_SET(gen->fd, &fds[gen->fdType]);
-                                       anySet = 1;
-                               }
-                       }
-                       gen = gen->next;
-               } while (gen != nextGen);
-               if (anySet) {
-                       tv.tv_sec = 0;
-                       tv.tv_usec = (retry && !anyReady) ? 500000 : 0;
-                       result = select(FD_SETSIZE, &fds[FT_read], &fds[FT_write],
-                                       &fds[FT_except], anyReady ? &tv : NULL);
-               }
-               else {
-                       if (retry && !anyReady)
-                               sleep(1);
-                       result = 0;
-               }
-               gen = nextGen;
-               do {
-                       if ((gen->mask & mask)
-                                       && (gen->ready || (result > 0 && gen->fd >= 0
-                                               && FD_ISSET(gen->fd, &fds[gen->fdType])))) {
-                               gen->ready = 0;
-                               event->type = gen->func(gen, event);
-                               if (event->type != E_none) {
-                                       nextGen = gen->next;
-                                       return event->type;
-                               }
-                       }
-                       gen = gen->next;
-               } while (gen != nextGen);
-               retry = 1;
-       }
-} //WaitMyEvent
-
-ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event)
 { //receive
        int result;
        short uid, type, size;
@@ -286,7 +170,7 @@ static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event)
        addrLen = sizeof(addr);
        for (new = 1; new <= MAX_SCREENS; new++)
                if (netGen[new].fd < 0) break;
-       if (new > Game.maxplayers) return;
+       if (new > maxplayers) return;
 
        if ((netGen[new].fd =
                accept(gen->fd, (struct sockaddr *)&addr, &addrLen)) < 0)
@@ -315,7 +199,7 @@ static MyEventType ConnGenFunc(EventGenRec *gen, MyEvent *event)
        return E_connect;
 } //ConnGenFunc
 
-ExtFunc void CountPlayers(void)
+void CountPlayers(void)
 { //count number of players/teams
        int i, j;
        playercount = 0;
@@ -329,7 +213,7 @@ ExtFunc void CountPlayers(void)
        } //player alive
 } //CountPlayers
 
-ExtFunc int StartServer(void)
+int StartServer(void)
 {
        MyEvent event;
        netint2 currentpiece[MAX_SCREENS];
@@ -360,6 +244,7 @@ ExtFunc int StartServer(void)
                                                netint4 versiondata[2];
                                                char data[255];
                                                int major;
+                                               int protocolVersion;
 
                                                memcpy(versiondata, event.u.net.data,
                                                        sizeof(versiondata));
@@ -386,10 +271,16 @@ ExtFunc int StartServer(void)
                                                        event.u.net.data, event.u.net.size);
                                                if (Players[event.u.net.sender].team < 1
                                                || Players[event.u.net.sender].team > 7) {
-                                                       Players[event.u.net.sender].team =
-                                                               event.u.net.sender % 7 + 1;
-                                                       SendPacketTo(event.u.net.sender,
-                                                               event.u.net.sender, NP_team,
+                                                       int team;
+
+                                                       for (team = 1; team < 7; team++) {
+                                                               for (i = 1; i < MAX_SCREENS; i++)
+                                                                       if ((Players[i].alive > 0) && (Players[i].team == team))
+                                                                               break; //team in use
+                                                               if (i==MAX_SCREENS) break;
+                                                       } //find unused team
+                                                       Players[event.u.net.sender].team = team;
+                                                       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
@@ -408,7 +299,7 @@ ExtFunc int StartServer(void)
                                                {
                                                        static struct {
                                                                int playerflags;
-                                                               int maxplayers; //1
+                                                               int gravity;    //1
                                                                int started;    //2
                                                                int continuous; //3
                                                                long seed;              //4
@@ -417,7 +308,7 @@ ExtFunc int StartServer(void)
 
                                                        memcpy(&data, &Players[event.u.net.sender].flags,
                                                                sizeof(data.playerflags));
-                                                       memcpy(&data.maxplayers, &Game,
+                                                       memcpy(&data.gravity, &Game,
                                                                sizeof(data) - sizeof(data.playerflags));
                                                        SendPacketTo(event.u.net.sender, 0, NP_gamedata,
                                                                sizeof(data), &data);
@@ -425,18 +316,11 @@ ExtFunc int StartServer(void)
                                                for (i = 1; i < MAX_SCREENS; i++)
                                                        if (netGen[i].fd >= 0 && i != event.u.net.sender) {
                                                                SendPacketTo(event.u.net.sender, i,
-                                                                       NP_newPlayer, sizeof(Player)
-                                                                       - sizeof(Players[0].spy)
-                                                                       - sizeof(Players[0].small),
-                                                                       &Players[i]);
-                                                               SendPacketTo(event.u.net.sender, i,
-                                                                       NP_newPiece, sizeof(currentpiece[i]),
-                                                                       &currentpiece[i]);
-                                                               SendPacketTo(i, event.u.net.sender,
-                                                                       NP_newPlayer, sizeof(Player)
-                                                                       - sizeof(Players[0].spy)
-                                                                       - sizeof(Players[0].small),
-                                                                       &Players[event.u.net.sender]);
+                                                                       NP_newPlayer, sizeof(_Player), &Players[i]);
+                                                               SendPacketTo(event.u.net.sender, i, NP_newPiece,
+                                                                       sizeof(Players[i].curShape), &Players[i].curShape);
+                                                               SendPacketTo(i, event.u.net.sender, NP_newPlayer,
+                                                                       sizeof(_Player), &Players[event.u.net.sender]);
                                                        } //send (to) players
                                                fprintf(stderr, "> Joined player #%d: %s <%s> (%s)\n",
                                                        event.u.net.sender,
@@ -457,8 +341,8 @@ ExtFunc int StartServer(void)
                                                } //give go ahead
                                                break; //NP_playerdata
                                        case NP_newPiece:
-                                               memcpy(&currentpiece[event.u.net.sender],
-                                                       event.u.net.data, sizeof(currentpiece[0]));
+                                               memcpy(&Players[event.u.net.sender].curShape,
+                                                       event.u.net.data, sizeof(Players[0].curShape));
                                                goto sendtoall;
                                        case NP_argghhh:
                                                Players[event.u.net.sender].alive = 0;
@@ -537,16 +421,16 @@ ExtFunc int StartServer(void)
 } //StartServer
 
 
-ExtFunc void Header(void)
+void SHeader(void)
 {
        fprintf(stderr,
          "NETRIS Server %s\t(c) 2002 Shiar <shiar@shiar.org>\n\n",
          version_string);
-} //Header
+}
 
-ExtFunc void Usage(void)
+void SUsage(void)
 {
-       Header();
+       SHeader();
        fprintf(stderr,
          "Usage: netris <options>\n"
          "\n"
@@ -563,9 +447,10 @@ ExtFunc void Usage(void)
          "\n", DEFAULT_PORT);
 }
 
-ExtFunc void DistInfo(void)
+/*
+void DistInfo(void)
 {
-       Header();
+       SHeader();
        fprintf(stderr,
          "This program is free software; you can redistribute it and/or modify\n"
          "it under the terms of the GNU General Public License as published by\n"
@@ -582,8 +467,9 @@ ExtFunc void DistInfo(void)
          "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
          "\n");
 } //DistInfo
+*/
 
-ExtFunc void WriteConf(void)
+void WriteConf(void)
 {
        FILE *file_out;
 
@@ -599,7 +485,7 @@ ExtFunc void WriteConf(void)
        fprintf(stderr, "Wrote new game configuration to %s\n", CONFIG_FILE);
 } //WriteConf
 
-ExtFunc void HandleOption(char tag, char *value)
+void HandleOption(char tag, char *value)
 {
        switch (tag) {
                case 'v':       //verbose
@@ -615,9 +501,12 @@ ExtFunc void HandleOption(char tag, char *value)
                        minplayers = atoi(value);
                        break;
                case 'x':       //max-players
-                       Game.maxplayers = atoi(value);
-                       if (Game.maxplayers >= MAX_SCREENS)
-                               Game.maxplayers = MAX_SCREENS;
+                       maxplayers = atoi(value);
+                       if (maxplayers >= MAX_SCREENS)
+                               maxplayers = MAX_SCREENS;
+                       break;
+               case 'q':       //quadra-style gravity
+                       Game.gravity ^= 1;
                        break;
                case 'i':       //speed (of level 1)
                        Game.initspeed = atof(value) * 1e6;
@@ -628,13 +517,13 @@ ExtFunc void HandleOption(char tag, char *value)
                case 'H':       //info
                        DistInfo(); exit(0);
                case 'h':       //help
-                       Usage(); exit(0);
+                       SUsage(); exit(0);
                default:
                        break;
        }
 } //HandleParam
 
-ExtFunc void ReadConf(char *filename)
+void ReadConf(char *filename)
 {
        FILE *file_in;
        char buf[513];
@@ -669,21 +558,22 @@ ExtFunc void ReadConf(char *filename)
 
 } //ReadConf
 
-ExtFunc void CatchInt(int sig)
+void CatchInt(int sig)
 {
        siglongjmp(close_env, 1);
 }
 
-ExtFunc int main(int argc, char **argv)
+int main(int argc, char **argv)
 {
        char ch;
 
        if (sigsetjmp(close_env, 1)) exit(0);
        signal(SIGINT, CatchInt);
        port = DEFAULT_PORT;
-       Game.maxplayers = 8;
+       maxplayers = 8;
        Game.initspeed = DEFAULT_INTERVAL;
        Game.seed = time(0);
+       Game.gravity = 0;
        {
                int i;
 
@@ -696,15 +586,15 @@ ExtFunc int main(int argc, char **argv)
 //     else
        ReadConf(CONFIG_FILE);
        while ((ch = getopt_long(argc, argv,
-                       "hHvp:i:s:c:m:x:", options, NULL)) != -1)
+                       "hHvqp:i:s:c:m:x:", options, NULL)) != -1)
                HandleOption(ch, optarg);
        if (optind < argc) {
-               Usage();
+               SUsage();
                exit(1);
        }
 //     WriteConf();
 
-       Header();
+       SHeader();
 
        {
                int i;
diff --git a/shapes.c b/shapes.c
deleted file mode 100644 (file)
index 42fdf51..0000000
--- a/shapes.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Netris -- A free networked version of T*tris
- * Copyright (C) 1994-1996,1999  Mark H. Weaver <mhw@netris.org>
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * 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: shapes.c,v 1.16 1999/05/16 06:56:31 mhw Exp $
- */
-
-#include "netris.h"
-#include <stdlib.h>
-
-#define ShapeName(name, dir) \
-       shape_ ## name ## _ ## dir
-
-#define PreDecl(name, dir) \
-       static Shape ShapeName(name, dir)
-
-#define StdShape(name, cmdName, mirror, type, realDir, dir, nextDir, prevDir) \
-       static Shape ShapeName(name, dir) = { \
-               &ShapeName(name, nextDir), &ShapeName(name, prevDir), \
-               0, 0, mirror, D_ ## realDir, type, cmds_ ## cmdName \
-       }
-
-#define FourWayDecl(name, cmdName, mirror, type) \
-       PreDecl(name, down); \
-       PreDecl(name, up); \
-       StdShape(name, cmdName, mirror, type, left, left, up, down); \
-       PreDecl(name, right); \
-       StdShape(name, cmdName, mirror, type, up, up, right, left); \
-       StdShape(name, cmdName, mirror, type, right, right, down, up); \
-       StdShape(name, cmdName, mirror, type, down, down, left, right)
-
-#define TwoWayDecl(name, cmdName, mirror, type) \
-       PreDecl(name, vert); \
-       StdShape(name, cmdName, mirror, type, right, horiz, vert, vert); \
-       StdShape(name, cmdName, mirror, type, down, vert, horiz, horiz)
-
-static Cmd cmds_long[] = { C_back, C_plot, C_forw, C_plot, C_forw, C_plot,
-       C_forw, C_plot, C_end };
-TwoWayDecl(long, long, 0, BT_blue);
-
-static Cmd cmds_square[] = { C_plot, C_forw, C_left, C_plot, C_forw, C_left,
-       C_plot, C_forw, C_left, C_plot, C_end };
-static Shape shape_square = { &shape_square, &shape_square, 0, 0, D_up, 0,
-       BT_magenta, cmds_square };
-
-static Cmd cmds_l[] = { C_right, C_back, C_plot, C_forw, C_plot, C_forw,
-       C_plot, C_left, C_forw, C_plot, C_end };
-FourWayDecl(l, l, 0, BT_cyan); 
-FourWayDecl(l1, l, 1, BT_yellow);
-
-static Cmd cmds_t[] = { C_plot, C_forw, C_plot, C_back, C_right, C_forw,
-       C_plot, C_back, C_back, C_plot, C_end };
-FourWayDecl(t, t, 0, BT_white);
-
-static Cmd cmds_s[] = { C_back, C_plot, C_forw, C_plot, C_left, C_forw,
-       C_plot, C_right, C_forw, C_plot, C_end };
-TwoWayDecl(s, s, 0, BT_green);
-TwoWayDecl(s1, s, 1, BT_red);
-
-ShapeOption stdOptions[] = {
-       {1, &shape_long_horiz},
-       {1, &shape_square},
-       {1, &shape_l_down},
-       {1, &shape_l1_down},
-       {1, &shape_t_down},
-       {1, &shape_s_horiz},
-       {1, &shape_s1_horiz},
-       {0, NULL}};
-
-Shape *netMapping[] = {
-       &shape_long_horiz,
-       &shape_long_vert,
-       &shape_square,
-       &shape_l_down,
-       &shape_l_right,
-       &shape_l_up,
-       &shape_l_left,
-       &shape_l1_down,
-       &shape_l1_right,
-       &shape_l1_up,
-       &shape_l1_left,
-       &shape_t_down,
-       &shape_t_right,
-       &shape_t_up,
-       &shape_t_left,
-       &shape_s_horiz,
-       &shape_s_vert,
-       &shape_s1_horiz,
-       &shape_s1_vert,
-       NULL};
-
-ExtFunc void MoveInDir(Dir dir, int dist, int *y, int *x)
-{
-       switch (dir) {
-               case D_down:    *y -= dist; break;
-               case D_right:   *x += dist; break;
-               case D_up:              *y += dist; break;
-               case D_left:    *x -= dist; break;
-               default:
-                       assert(0);
-       }
-}
-
-ExtFunc Dir RotateDir(Dir dir, int delta)
-{
-       return 3 & (dir + delta);
-}
-
-ExtFunc int ShapeIterate(Shape *s, int scr, int y, int x, int falling,
-ExtFunc                                                        ShapeDrawFunc func, void *data)
-{
-       int i, mirror, result;
-       Dir dir;
-       BlockType type;
-
-       y += s->initY;
-       x += s->initX;
-       dir = s->initDir;
-       type = falling ? -s->type : s->type;
-       mirror = s->mirrored ? -1 : 1;
-       for (i = 0; s->cmds[i] != C_end; ++i)
-               switch (s->cmds[i]) {
-                       case C_forw:
-                               MoveInDir(dir, 1, &y, &x);
-                               break;
-                       case C_back:
-                               MoveInDir(dir, -1, &y, &x);
-                               break;
-                       case C_left:
-                               dir = RotateDir(dir, mirror);
-                               break;
-                       case C_right:
-                               dir = RotateDir(dir, -mirror);
-                               break;
-                       case C_plot:
-                               if ((result = func(scr, y, x, type, data)))
-                                       return result;
-                               break;
-                       default:
-                               assert(0);
-               }
-       return 0;
-}
-
-ExtFunc Shape *ChooseOption(ShapeOption *options)
-{
-       int i;
-       float total = 0, val;
-
-       for (i = 0; options[i].shape; ++i)
-               total += options[i].weight;
-       val = Random(0, 32767) / 32768.0 * total;
-       for (i = 0; options[i].shape; ++i) {
-               val -= options[i].weight;
-               if (val < 0)
-                       return options[i].shape;
-       }
-       return options[0].shape;
-}
-
-ExtFunc short ShapeToNetNum(Shape *shape)
-{
-       int num;
-
-       for (num = 0; netMapping[num]; ++num)
-               if (netMapping[num] == shape)
-                       return num;
-       assert(0);
-       return 0;
-}
-
-ExtFunc Shape *NetNumToShape(short num)
-{
-       assert(num >= 0 && num < sizeof(netMapping) / sizeof(netMapping[0]) - 1);
-       return netMapping[num];
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
diff --git a/sr.c b/sr.c
deleted file mode 100644 (file)
index 2cc3c93..0000000
--- a/sr.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/*
- * sr -- A sample robot for Netris
- * Copyright (C) 1994,1995,1996  Mark H. Weaver <mhw@netris.org>
- * 
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * 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: sr.c,v 1.10 1996/02/09 08:22:20 mhw Exp $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <math.h>
-#include <limits.h>
-
-/* Both of these should be at least twice the actual max */
-#define MAX_BOARD_WIDTH                32
-#define MAX_BOARD_HEIGHT       64
-
-char b[1024];
-FILE *logFile;
-
-int twoPlayer;
-int boardHeight, boardWidth;
-int board[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-int piece[4][4];
-int pieceLast[4][4];
-
-int board1[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-int piece1[4][4];
-int piece2[4][4];
-
-int pieceCount;                /* Serial number of current piece, for sending commands */
-int pieceVisible;      /* How many blocks of the current piece are visible */
-int pieceBottom, pieceLeft;    /* Position of bottom-left square */
-int pieceBottomLast, pieceLeftLast;
-
-/*
- * 0 = Not decided yet
- * 1 = decided
- * 2 = move in progress
- * 3 = drop in progress
- */
-int pieceState;
-
-int leftDest;
-int pieceDest[4][4];
-
-int masterEnable = 1, dropEnable = 1;
-
-float curTime, moveTimeout;
-
-int min(int a, int b)
-{
-       return a < b ? a : b;
-}
-
-char *ReadLine(char *buf, int size)
-{
-       int len;
-
-       if (!fgets(buf, size, stdin))
-               return NULL;
-       len = strlen(buf);
-       if (len > 0 && buf[len-1] == '\n')
-               buf[len-1] = 0;
-       if (logFile)
-               fprintf(logFile, "  %s\n", buf);
-       return buf;
-}
-
-int WriteLine(char *fmt, ...)
-{
-       int result;
-       va_list args;
-
-       va_start(args, fmt);
-       result = vfprintf(stdout, fmt, args);
-       if (logFile) {
-               fprintf(logFile, "> ");
-               vfprintf(logFile, fmt, args);
-       }
-       va_end(args);
-       return result;
-}
-
-void FindPiece(void)
-{
-       int row, col;
-
-       pieceVisible = 0;
-       pieceBottom = MAX_BOARD_HEIGHT;
-       pieceLeft = MAX_BOARD_WIDTH;
-       for (row = boardHeight - 1; row >= 0; --row)
-               for (col = boardWidth - 1; col >= 0; --col)
-                       if (board[row][col] < 0) {
-                               pieceBottom = row;
-                               if (pieceLeft > col)
-                                       pieceLeft = col;
-                               pieceVisible++;
-                       }
-       for (row = 0; row < 4; ++row)
-               for (col = 0; col < 4; ++col)
-                       piece[row][col] = board[pieceBottom + row][pieceLeft + col] < 0;
-}
-
-void RotatePiece1(void)
-{
-       int row, col, height = 0;
-
-       for (row = 0; row < 4; ++row)
-               for (col = 0; col < 4; ++col)
-               {
-                       piece2[row][col] = piece1[row][col];
-                       piece1[row][col] = 0;
-                       if (piece2[row][col])
-                               height = row + 1;
-               }
-       for (row = 0; row < 4; ++row)
-               for (col = 0; col < height; ++col)
-                       piece1[row][col] = piece2[height - col - 1][row];
-}
-
-int PieceFits(int row, int col)
-{
-       int i, j;
-
-       if (row < 0)
-               return 0;
-       for (i = 0; i < 4; ++i)
-               for (j = 0; j < 4; ++j)
-                       if (piece1[i][j])
-                               if (col+j >= boardWidth || board[row+i][col+j] > 0)
-                                       return 0;
-       return 1;
-}
-
-int SimPlacement(int row, int col)
-{
-       int i, j;
-       int from, to, count;
-
-       for (i = 0; i < boardHeight; ++i)
-               for (j = 0; j < boardWidth; ++j) {
-                       board1[i][j] = board[i][j] > 0;
-                       if (i >= row && i < row+4 && j >= col && j < col+4)
-                               if (piece1[i - row][j - col])
-                                       board1[i][j] = 1;
-               }
-       for (from = to = 0; to < boardHeight; ++from) {
-               count = boardWidth;
-               for (j = 0; j < boardWidth; ++j)
-                       count -= board1[to][j] = board1[from][j];
-               to += (count > 0);
-       }
-       return from - to;
-}
-
-double BoardScore(int linesCleared, int pRow, int verbose)
-{
-       double score = 0;
-       double avgHeight2 = 0, avgHolesTimesDepth = 0;
-       int maxMidHeight = 0, maxHeight = 0;
-       int height[MAX_BOARD_WIDTH];
-       int holesTimesDepth[MAX_BOARD_WIDTH];
-       int holes[MAX_BOARD_WIDTH];
-       double hardFit[MAX_BOARD_HEIGHT];
-       int depend[MAX_BOARD_HEIGHT];
-       int cover[MAX_BOARD_WIDTH];
-       int row, col, count, i;
-       int deltaLeft, deltaRight;
-       double closeToTop, topShape = 0, fitProbs = 0, space = 0;
-       double maxHard;
-
-       for (col = 0; col < boardWidth; ++col) {
-               cover[col] = 0;
-               height[col] = 0;
-               for (row = 0; row < boardHeight; ++row)
-                       if (board1[row][col])
-                               height[col] = row + 1;
-               avgHeight2 += height[col] * height[col];
-               if (maxHeight < height[col])
-                       maxHeight = height[col];
-               if (col >= 2 && col < boardWidth - 2 && maxMidHeight < height[col])
-                       maxMidHeight = height[col];
-               holes[col] = 0;
-               holesTimesDepth[col] = 0;
-               for (row = 0; row < height[col]; ++row) {
-                       if (board1[row][col])
-                               holesTimesDepth[col] += holes[col];
-                       else
-                               holes[col]++;
-               }
-               avgHolesTimesDepth += holesTimesDepth[col];
-       }
-       avgHeight2 /= boardWidth;
-       avgHolesTimesDepth /= boardWidth;
-
-       /* Calculate dependencies */
-       for (row = maxHeight - 1; row >= 0; --row) {
-               depend[row] = 0;
-               for (col = 0; col < boardWidth; ++col) {
-                       if (board1[row][col])
-                               cover[col] |= 1 << row;
-                       else
-                               depend[row] |= cover[col];
-               }
-               for (i = row + 1; i < maxHeight; ++i)
-                       if (depend[row] & (1 << i))
-                               depend[row] |= depend[i];
-       }
-
-       /* Calculate hardness of fit */
-       for (row = maxHeight - 1; row >= 0; --row) {
-               hardFit[row] = 5;
-               count = 0;
-               for (col = 0; col < boardWidth; ++col) {
-                       if (board1[row][col]) {
-                               space += 0.5;
-                       }
-                       else if (!board1[row][col]) {
-                               count++;
-                               space += 1;
-                               hardFit[row]++;
-                               if (height[col] < row)
-                                       hardFit[row] += row - height[col];
-                               if (col > 0)
-                                       deltaLeft = height[col - 1] - row;
-                               else
-                                       deltaLeft = MAX_BOARD_HEIGHT;
-                               if (col < boardWidth - 1)
-                                       deltaRight = height[col + 1] - row;
-                               else
-                                       deltaRight = MAX_BOARD_HEIGHT;
-                               if (deltaLeft > 2 && deltaRight > 2)
-                                       hardFit[row] += 7;
-                               else if (deltaLeft > 2 || deltaRight > 2)
-                                       hardFit[row] += 2;
-                               else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
-                                       hardFit[row] += 2;
-                               else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
-                                       hardFit[row] += 3;
-                       }
-               }
-               maxHard = 0;
-               for (i = row + 1; i < row + 5 && i < maxHeight; ++i)
-                       if (depend[row] & (1 << i))
-                               if (maxHard < hardFit[i])
-                                       maxHard = hardFit[i];
-               fitProbs += maxHard * count;
-       }
-
-       /* Calculate score based on top shape */
-       for (col = 0; col < boardWidth; ++col) {
-               if (col > 0)
-                       deltaLeft = height[col - 1] - height[col];
-               else
-                       deltaLeft = MAX_BOARD_HEIGHT;
-               if (col < boardWidth - 1)
-                       deltaRight = height[col + 1] - height[col];
-               else
-                       deltaRight = MAX_BOARD_HEIGHT;
-               if (deltaLeft > 2 && deltaRight > 2)
-                       topShape += 15 + 15 * (min(deltaLeft, deltaRight) / 4);
-               else if (deltaLeft > 2 || deltaRight > 2)
-                       topShape += 2;
-               else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
-                       topShape += 2;
-               else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
-                       topShape += 3;
-       }
-
-       closeToTop = (pRow / (double)boardHeight);
-       closeToTop *= closeToTop;
-
-       closeToTop *= 200;
-       space /= 2;
-       score = space + closeToTop + topShape + fitProbs - linesCleared * 10;
-
-       if (verbose) {
-               WriteLine("Message space=%g, close=%g, shape=%g\n",
-                       space, closeToTop, topShape);
-               WriteLine("Message fitProbs=%g, cleared=%d\n",
-                       fitProbs, -linesCleared * 10);
-       }
-
-       return score;
-}
-
-void PrintGoal(void)
-{
-       char b[32];
-       int i, j, c;
-
-       c = 0;
-       for (i = 0; i < 4; ++i) {
-               b[c++] = ':';
-               for (j = 0; j < 4; ++j)
-                       b[c++] = pieceDest[i][j] ? '*' : ' ';
-       }
-       b[c++]=':';
-       b[c++]=0;
-       WriteLine("Message Goal %d %s\n", leftDest, b);
-}
-
-double MakeDecision(void)
-{
-       int row, col, rot;
-       int linesCleared;
-       int first = 1;
-       double minScore = 0, score;
-
-       memcpy(piece1, piece, sizeof(piece));
-       for (rot = 0; rot < 4; ++rot) {
-               RotatePiece1();
-               for (col = 0; col < boardWidth; ++col) {
-                       if (!PieceFits(pieceBottom, col))
-                               continue;
-                       for (row = pieceBottom; PieceFits(row-1, col); --row)
-                               ;
-                       linesCleared = SimPlacement(row, col);
-                       score = BoardScore(linesCleared, row, 0);
-                       if (first || minScore > score) {
-                               first = 0;
-                               minScore = score;
-                               memcpy(pieceDest, piece1, sizeof(piece));
-                               leftDest = col;
-                       }
-               }
-       }
-       PrintGoal();
-       return minScore;
-}
-
-double PeekScore(int verbose)
-{
-       int row, col, linesCleared;
-
-       memcpy(piece1, piece, sizeof(piece));
-       col = pieceLeft;
-       for (row = pieceBottom; PieceFits(row-1, col); --row)
-               ;
-       linesCleared = SimPlacement(row, col);
-       return BoardScore(linesCleared, row, verbose);
-}
-
-int main(int argc, char **argv)
-{
-       int ac;
-       char *av[32];
-
-       if (argc == 2 && !strcmp(argv[1], "-l")) {
-               logFile = fopen("log", "w");
-               if (!logFile) {
-                       perror("fopen log");
-                       exit(1);
-               }
-       }
-       setvbuf(stdout, NULL, _IOLBF, 0);
-       WriteLine("Version 1\n");
-       while(ReadLine(b, sizeof b)) {
-               av[0] = strtok(b, " ");
-               if (!av[0])
-                       continue;
-               ac = 1;
-               while ((av[ac] = strtok(NULL, " ")))
-                       ac++;
-               if (!strcmp(av[0], "Exit"))
-                       return 0;
-               else if (!strcmp(av[0], "NewPiece") && ac >= 2) {
-                       pieceCount = atoi(av[1]);
-                       pieceState = 0;
-               }
-               else if (!strcmp(av[0], "BoardSize") && ac >= 4) {
-                       if (atoi(av[1]) != 0)
-                               continue;
-                       boardHeight = atoi(av[2]);
-                       boardWidth = atoi(av[3]);
-               }
-               else if (!strcmp(av[0], "RowUpdate") && ac >= 3 + boardWidth) {
-                       int scr, row, col;
-
-                       scr = atoi(av[1]);
-                       if (scr != 0)
-                               continue;
-                       row = atoi(av[2]);
-                       for (col = 0; col < boardWidth; col++)
-                               board[row][col] = atoi(av[3 + col]);
-               }
-               else if (!strcmp(av[0], "UserKey") && ac >= 3) {
-                       char key;
-
-                       key = atoi(av[1]);
-                       switch (key) {
-                               case 'v':
-                               case 's':
-                                       FindPiece();
-                                       WriteLine("Message Score = %g\n", PeekScore(key == 'v'));
-                                       break;
-                               case 'e':
-                                       masterEnable = !masterEnable;
-                                       WriteLine("Message Enable = %d\n", masterEnable);
-                                       break;
-                               case 'd':
-                                       dropEnable = !dropEnable;
-                                       WriteLine("Message Drop Enable = %d\n", dropEnable);
-                                       break;
-                               default:
-                                       if (strcmp(av[2], "?"))
-                                               WriteLine("%s %d\n", av[2], pieceCount);
-                                       break;
-                       }
-               }
-               else if (!strcmp(av[0], "TimeStamp") && ac >= 2 && masterEnable) {
-                       curTime = atof(av[1]);
-                       FindPiece();
-                       if (pieceVisible < 4)
-                               continue;
-                       if (memcmp(piece, pieceLast, sizeof(piece)) ||
-                                       pieceLeft != pieceLeftLast) {
-                               if (pieceState == 2)
-                                       pieceState = 1;
-                               memcpy(pieceLast, piece, sizeof(piece));
-                               pieceLeftLast = pieceLeft;
-                       }
-                       if (pieceState == 0) {          /* Undecided */
-                               MakeDecision();
-                               pieceState = 1;
-                       }
-                       if (pieceState >= 2) {          /* Move or drop in progress */
-                               if (curTime >= moveTimeout)
-                                       pieceState = 1;
-                       }
-                       if (pieceState == 1) {          /* Decided */
-                               if (memcmp(piece, pieceDest, sizeof(piece))) {
-                                       WriteLine("RotRight %d\n", pieceCount);
-                                       pieceState = 2;
-                               }
-                               else if (pieceLeft != leftDest) {
-                                       if (pieceLeft < leftDest)
-                                               WriteLine("Right %d\n", pieceCount);
-                                       else
-                                               WriteLine("Left %d\n", pieceCount);
-                                       pieceState = 2;
-                               }
-                               else if (dropEnable) {
-                                       WriteLine("Drop %d\n", pieceCount);
-                                       pieceState = 3;
-                               }
-                               if (pieceState == 2)
-                                       moveTimeout = curTime + 0.5;
-                       }
-               }
-       }
-       return 0;
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
diff --git a/util.c b/util.c
index 2f7c2e5d7ad346b1f30562fbd43417c49763afe1..a55aeb0abc825fd1b64ec43198ebd7922ff049a3 100644 (file)
--- a/util.c
+++ b/util.c
@@ -28,6 +28,9 @@
 #include <sys/time.h>
 #include <netdb.h>
 #include <errno.h>
+#include <setjmp.h>
+
+#include "util.h"
 
 static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
 static EventGenRec alarmGen =
@@ -38,7 +41,8 @@ static int myRandSeed = 1;
 
 static long baseTimeval;
 
-ExtFunc void AtExit(void (*handler)(void))
+
+void AtExit(void (*handler)(void))
 {
 #ifdef HAS_ON_EXIT
        on_exit((void *)handler, NULL);
@@ -49,7 +53,7 @@ ExtFunc void AtExit(void (*handler)(void))
 
 ///////////// HELP MESSAGES /////////////
 
-ExtFunc void Header(void)
+void Header(void)
 {
        fprintf(stderr,
          "NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
@@ -57,7 +61,7 @@ ExtFunc void Header(void)
          version_string);
 } //Header
 
-ExtFunc void Usage(void)
+void Usage(void)
 {
        Header();
        fprintf(stderr,
@@ -85,7 +89,7 @@ ExtFunc void Usage(void)
          "\n", DEFAULT_PORT, DEFAULT_KEYS);
 }
 
-ExtFunc void DistInfo(void)
+void DistInfo(void)
 {
        Header();
        fprintf(stderr,
@@ -105,7 +109,7 @@ ExtFunc void DistInfo(void)
          "\n");
 } //DistInfo
 
-ExtFunc void Rules(void)
+void Rules(void)
 {
        Header();
        fprintf(stderr,
@@ -135,13 +139,13 @@ ExtFunc void Rules(void)
  * My really crappy random number generator follows
  * Should be more than sufficient for our purposes though
  */
-ExtFunc void SRandom(int seed)
+void SRandom(int seed)
 {
        Game.seed = seed;
        myRandSeed = seed % 31751 + 1;
 } //SRandom
 
-ExtFunc int Random(int min, int max1)
+int Random(int min, int max1)
 { //return a random value
        myRandSeed = (myRandSeed * 31751 + 15437) % 32767;
        return myRandSeed % (max1 - min) + min;
@@ -149,7 +153,7 @@ ExtFunc int Random(int min, int max1)
 
 ///////////// I/O /////////////
 
-ExtFunc int MyRead(int fd, void *data, int len)
+int MyRead(int fd, void *data, int len)
 {
        int result, left;
 
@@ -166,7 +170,7 @@ ExtFunc int MyRead(int fd, void *data, int len)
        return len;
 } //MyRead
 
-ExtFunc int MyWrite(int fd, void *data, int len)
+int MyWrite(int fd, void *data, int len)
 {
        int result, left;
 
@@ -185,7 +189,7 @@ ExtFunc int MyWrite(int fd, void *data, int len)
 
 ///////////// TIME /////////////
 
-ExtFunc void NormalizeTime(struct timeval *tv)
+void NormalizeTime(struct timeval *tv)
 {
        tv->tv_sec += tv->tv_usec / 1000000;
        tv->tv_usec %= 1000000;
@@ -195,7 +199,7 @@ ExtFunc void NormalizeTime(struct timeval *tv)
        }
 }
 
-ExtFunc void CatchAlarm(int sig)
+void CatchAlarm(int sig)
 {
        alarmGen.ready = 1;
        signal(SIGALRM, CatchAlarm);
@@ -206,18 +210,18 @@ static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event)
        return E_alarm;
 }
 
-ExtFunc void SetTimeval(struct timeval *tv, long usec)
+void SetTimeval(struct timeval *tv, long usec)
 {
        tv->tv_sec = usec / 1000000;
        tv->tv_usec = usec % 1000000;
 } //SetTimeval
 
-ExtFunc long GetTimeval(struct timeval *tv)
+long GetTimeval(struct timeval *tv)
 {
        return tv->tv_sec * 1000000 + tv->tv_usec;
 } //GetTimeval
 
-ExtFunc long AbsTimeval(void)
+long AbsTimeval(void)
 {
        struct timeval tv;
 
@@ -225,22 +229,22 @@ ExtFunc long AbsTimeval(void)
        return GetTimeval(&tv);
 } //CurTimeval
 
-ExtFunc void ResetBaseTime(void)
-{
+void ResetBaseTime(void)
+{ //Reset the timer
        baseTimeval = AbsTimeval();
 } //ResetBaseTime
 
-ExtFunc void PauseTime(void)
-{
+void PauseTime(void)
+{ //Pause the timer
        baseTimeval -= AbsTimeval();
 } //PauseTime
 
-ExtFunc void ResumeTime(void)
-{
+void ResumeTime(void)
+{ //Unpause timer
        baseTimeval += AbsTimeval();
 } //ResumeTime
 
-ExtFunc long CurTimeval(void)
+long CurTimeval(void)
 {
        struct timeval tv;
 
@@ -260,7 +264,7 @@ static long SetITimer1(long interval, long value)
        return GetTimeval(&old.it_value);
 }
 
-ExtFunc long SetITimer(long interval, long value)
+long SetITimer(long interval, long value)
 {
        long old;
 
@@ -272,19 +276,19 @@ ExtFunc long SetITimer(long interval, long value)
 
 ///////////// ... /////////////
 
-ExtFunc volatile void die(char *msg)
+volatile void die(char *msg)
 {
        perror(msg);
        exit(1);
 }
 
-ExtFunc volatile void fatal(char *msg)
+volatile void fatal(char *msg)
 {
        fprintf(stderr, "%s\n", msg);
        exit(1);
 } //fatal
 
-ExtFunc void BlockSignals(MySigSet *saved, ...)
+void BlockSignals(MySigSet *saved, ...)
 {
        MySigSet set;
        va_list args;
@@ -311,7 +315,7 @@ ExtFunc void BlockSignals(MySigSet *saved, ...)
        va_end(args);
 } //BlockSignals
 
-ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
+void RestoreSignals(MySigSet *saved, MySigSet *set)
 {
 #ifdef HAS_SIGPROCMASK
        sigprocmask(SIG_SETMASK, set, saved);
@@ -325,14 +329,14 @@ ExtFunc void RestoreSignals(MySigSet *saved, MySigSet *set)
 
 ///////////// EVENTS /////////////
 
-ExtFunc void AddEventGen(EventGenRec *gen)
+void AddEventGen(EventGenRec *gen)
 {
        assert(gen->next == NULL);
        gen->next = nextGen->next;
        nextGen->next = gen;
 } //AddEventGen
 
-ExtFunc void RemoveEventGen(EventGenRec *gen)
+void RemoveEventGen(EventGenRec *gen)
 {
        // assert(gen->next != NULL);   /* Be more forgiving, for SIGINTs */
        if (gen->next) {
@@ -343,7 +347,7 @@ ExtFunc void RemoveEventGen(EventGenRec *gen)
        }
 } //RemoveEventGen
 
-ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
+MyEventType WaitMyEvent(MyEvent *event, int mask)
 { //poll
        int i, retry = 0;
        fd_set fds[FT_len];
diff --git a/util.h b/util.h
new file mode 100644 (file)
index 0000000..fc24f77
--- /dev/null
+++ b/util.h
@@ -0,0 +1,33 @@
+#ifndef __UTIL_H
+#define __UTIL_H
+
+extern void AtExit(void (*handler)(void));
+extern void Header(void);
+extern void Usage(void);
+extern void DistInfo(void);
+extern void Rules(void);
+extern void SRandom(int seed);
+extern int Random(int min, int max1);
+extern int MyRead(int fd, void *data, int len);
+extern int MyWrite(int fd, void *data, int len);
+extern void NormalizeTime(struct timeval *tv);
+extern void CatchAlarm(int sig);
+extern void SetTimeval(struct timeval *tv, long usec);
+extern long GetTimeval(struct timeval *tv);
+extern long AbsTimeval(void);
+extern void ResetBaseTime(void);
+extern void PauseTime(void);
+extern void ResumeTime(void);
+extern long CurTimeval(void);
+extern long SetITimer(long interval, long value);
+extern volatile void die(char *msg);
+extern volatile void fatal(char *msg);
+extern void BlockSignals(MySigSet *saved, ...);
+extern void RestoreSignals(MySigSet *saved, MySigSet *set);
+extern void AddEventGen(EventGenRec *gen);
+extern void RemoveEventGen(EventGenRec *gen);
+extern MyEventType WaitMyEvent(MyEvent *event, int mask);
+extern void CatchInt(int sig);
+
+#endif //__UTIL_H
+