From: Mischa POSLAWSKY Date: Sun, 27 Oct 2002 22:12:00 +0000 (+0100) Subject: unofficial version 0.8: chat, code cleanup X-Git-Tag: v0.8 X-Git-Url: http://git.shiar.net/netris.git/commitdiff_plain/0e779d807aa1830dde2f4a75117fd16f5627dc76 unofficial version 0.8: chat, code cleanup - 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 --- diff --git a/.gitignore b/.gitignore index a746348..7a8b84c 100644 --- a/.gitignore +++ b/.gitignore @@ -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 be5e370..1455fab 100644 --- a/CHANGES +++ b/CHANGES @@ -25,12 +25,12 @@ * 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 @@ -140,7 +140,7 @@ * '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 @@ -151,7 +151,7 @@ * 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 @@ -160,4 +160,103 @@ * 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 + ------------------------------------------------------------------------------ diff --git a/Configure b/Configure index 537142f..1d0ce1c 100755 --- 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 index 0000000..97cf600 --- /dev/null +++ b/INSTALL @@ -0,0 +1,4 @@ +./configure +make +make install + diff --git a/TODO b/TODO index 819dfce..c3c58e3 100644 --- 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)) @@ -74,8 +80,11 @@ * 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 55983b4..c3a8d5c 100644 --- a/board.c +++ b/board.c @@ -22,22 +22,110 @@ #include "netris.h" #include -#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 + 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 + 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 + 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 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 to line 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; x1) + 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 junklines with hole at to by team 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 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 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 + diff --git a/curses.c b/curses.c index 8d500d9..aab808d 100644 --- a/curses.c +++ b/curses.c @@ -20,31 +20,45 @@ */ #include "netris.h" + #include #include #include #include #include +#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", + 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 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 de0d605..6ad7e8b 100644 --- a/game.c +++ b/game.c @@ -21,24 +21,28 @@ #define NOEXT #include "netris.h" + #include #include #include #include #include -#include + +#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; i0) + 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=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 1549aa0..8da9956 100644 --- a/inet.c +++ b/inet.c @@ -20,6 +20,7 @@ */ #include "netris.h" + #include #include #include @@ -28,20 +29,33 @@ #include #include #include +#include + +#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 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 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%%" + diff --git a/netris.conf b/netris.conf index b8a153c..edc7b30 100644 --- a/netris.conf +++ b/netris.conf @@ -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 diff --git a/netris.h b/netris.h index a361c2f..cab651c 100644 --- a/netris.h +++ b/netris.h @@ -19,18 +19,17 @@ * $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 #include #include #include -#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 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 - * - * 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 -#include -#include -#include -#include -#include -#include -#include - -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 index 53415b2..0000000 --- a/robot_desc +++ /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 " option to Netris, it launches -"/bin/sh -c " 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 " line to the other, and the lowest version is -used. Currently, the robot protocol version is 1. - -Next, Netris sends "GameType ", there is either OnePlayer -or ClassicTwo. There may be other games in the future. - -Then Netris sends "BoardSize " for each 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 ". - 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 ". Currently, the flags are "robot" and -"fairRobot". - -Next, Netris sends "TickLength ", where 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 --------------- -This command is never sent in "fair" robot mode. - -Every time a new piece is created, this command is sent to the robot. - is a positive integer uniquely identifying the piece. should -be sent as a parameter to each movement command (sent to Netris) in -order to prevent accidental movement of the wrong piece. - -TimeStamp -------------------- -This command may be sent to the robot at any time. 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 ... --------------------------------------------------------- -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". - - is 0 for the computer player and positive numbers for opponents. - is an integer from 0 to boardHeight-1. 0 is the bottom row. - - ... 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 ------------------------ -Whenever the user presses a key, this command is sent to the robot. The -key is not automatically interpreted by Netris. - - is the ascii value of the key, from 0 to 255. is one -of the following strings: "Left", "Rotate", "Right", "Drop", "Down", -"ToggleSpy", "Pause", or "?". When possible, you should use , -since it will pay attention to keyboard remappings. - -For each possible (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 " ". - -Pause ---------------------------------- - is 0 or 1, indicating whether the game is currently paused by -our side. 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 -Rotate -Right -Drop -Down -ToggleSpy -Pause ---------------- -These commands perform the equivalent of typing the corresponding command -on the keyboard, if you weren't in robot mode. - - 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 is ignored. - -These commands (except "Pause") are also ignored if the game is paused. - -Message ------------------ - is printed on the messages part of the display. Messages too -long to fit on the screen may be truncated. - - 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 diff --git a/server.c b/server.c index 6fe46f0..39222bf 100644 --- a/server.c +++ b/server.c @@ -21,6 +21,7 @@ #define NOEXT #include "netris.h" + #include #include #include @@ -32,11 +33,14 @@ #include #include +#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]), - ¤tpiece[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(¤tpiece[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 \n\n", version_string); -} //Header +} -ExtFunc void Usage(void) +void SUsage(void) { - Header(); + SHeader(); fprintf(stderr, "Usage: netris \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 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 - * - * 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 - -#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 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 - * - * 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 -#include -#include -#include -#include -#include - -/* 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 2f7c2e5..a55aeb0 100644 --- a/util.c +++ b/util.c @@ -28,6 +28,9 @@ #include #include #include +#include + +#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 \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 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 +