From 0e779d807aa1830dde2f4a75117fd16f5627dc76 Mon Sep 17 00:00:00 2001 From: Mischa POSLAWSKY Date: Sun, 27 Oct 2002 23:12:00 +0100 Subject: [PATCH] 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 --- .gitignore | 6 +- CHANGES | 107 ++++++- Configure | 56 +--- INSTALL | 4 + TODO | 53 ++-- board.c | 327 ++++++++++++++------ board.h | 36 +++ client.h | 14 + curses.c | 429 +++++++++++++++++--------- curses.h | 30 ++ game.c | 860 +++++++++++++++++++++++++--------------------------- inet.c | 39 ++- inet.h | 12 + msg.en.h | 8 + netris.conf | 11 +- netris.h | 81 ++--- robot.c | 173 ----------- robot_desc | 225 -------------- server.c | 230 ++++---------- shapes.c | 195 ------------ sr.c | 474 ----------------------------- util.c | 62 ++-- util.h | 33 ++ 23 files changed, 1372 insertions(+), 2093 deletions(-) create mode 100644 INSTALL create mode 100644 board.h create mode 100644 client.h create mode 100644 curses.h create mode 100644 inet.h create mode 100644 msg.en.h delete mode 100644 robot.c delete mode 100644 robot_desc delete mode 100644 shapes.c delete mode 100644 sr.c create mode 100644 util.h 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 + -- 2.30.0