Makefile
config.h
-proto.h
-proto.chg
-.depend
version.c
*.o
netris
-server
-sr
+netrisserver
* counts score (as in gameboy version)
* reads default parameters from netris.conf (or other file specified with -f)
-
+
-- v0.6.83 -------
* conffile can have comments (#) and tabs instead of spaces
* level up every 10 lines (speed x1.2)
-
+
-- v0.6.84 -------
* same handler for configfile/parameters
* 'Close connection' message no longer displayed
* players in teams are displayed in their teamcolor
- -- v0.7.820
+ -- v0.7.820 ------
* server doesn't quit, but just stops game when 1 player/team left
* when a game stops, all players are paused and their fields reset
* players' scores and (next) pieces and stuff are reset at new game
* scores are erased instead of not drawn (apm/ppm remained at new game)
- -- v0.7.821
+ -- v0.7.821 ------
* colorcoding altered a bit (server messages white, player stuff colored)
* when no team specified, server assigns a team and sends it to player
* lag could delay changes to another game, desyncing clients
now game info is not transmitted when game has stopped
+ -- v0.7.825 ------
+
+ * shapes are now stored as bitmaps, and slightly altered to match quadra
+ * extensive simplification of many routines because of this
+ (binary just ~1500 bytes smaller)
+ * next piece indicator aligns piece to the right
+ * blocks of a piece are grouped horizontally
+ displays 1 block as [], 2 blocks [[]], 3 blocks [[[]]], stick [[[[]]]]
+ * falling blocks not stored differently from frozen blocks
+ (might cause problems with robot, but i'll deal with that later)
+ * if piece can't be rotated (ie near the edge) it tries to slide it right
+ * fix multiplay transmission of (new) pieces
+ * field reset to 'empty' when player leaves (not 'ready')
+
+ -- v0.7.826 ------
+
+ * new pieces appear near middle again
+ * junklines have the color of the player/team that added them
+ * fix bug causing wrong number of junklines being sent after 1st game
+ * --nick parameter changes nick from default login name
+ * can turn field spying back on on redraw
+ * new messages on top, old messages scroll down
+
+ -- v0.7.828 ------
+
+ * server places unteamed players in first unused team
+ * fields are resized to half width if they don't fit on screen
+ * instadrop is default (as in $any::decent::tetris)
+ * dropmodes as options --slidedrop and --dropmode (-d and -D)
+
+ -- v0.7.830 ------
+
+ * shapes stick vertically as well (not physically visible yet though)
+ * quadra style gravity (shape falls down when possible)
+ * alternate scoring method used in gravity mode
+ * junklines stick horizontally so they don't drop into each other
+
+ -- v0.7.831 ------
+
+ * fix bugs in free blocks detection routine
+ * correct J stickiness
+ * players' names displayed in teamcolor
+ * correct Z stickiness, correct check below mask
+ * client reports winner+time and player stats (ppm+apm), calc client-side
+
+ -- v0.7.91 -------
+
+ * buffered message history, can be redrawn
+ * you can send messages, enter key toggles chat mode
+ * messages can contain multiple color tags
+ * in chat mode, backspace backspaces, escape cancels message
+
+ -- v0.7.96 -------
+
+ * field messages were slightly corrupted sometimes, somehow :P
+ * handler which redraws when window resizes :)
+
+ -- v0.7.A2 -------
+
+ * different source identing, tabs of 8 chars
+ * a couple of botcalls removed
+ * server switches quadra mode with --quadra parameter
+
+ -- v0.7.A5 -------
+
+ * all robot-stuff removed
+ * standard includefiles for each file instead of generated proto.h
+
+ -- v0.7.A19 ------
+
+ * Sets struct for settings
+ * dropmode settings in single var, cleaned up
+
+ -- v0.7.A20 ------
+
+ * last gcc warning fixed
+ * messages now scroll bottom to top
+ * your own input is echoed on screen, _ marks cursor in typing mode
+ * long messages can be displayed over multiple lines
+ * typing messages longer than message window moves cursor over old text
+ * empty messages are escaped
+ * key and network handling in main loop in functions
+ * started moving messages to seperate file
+
+ -- v0.7.A21 ------
+
+ * used curses to invert pause text instead of stdout() so it works in screen
+ * some code cleaned up
+
+ -- v0.7.A27 ------
+
+ * clientspecific playerdata seperated from general playerdata (PlayerDisp[])
+ * player names printed over top field grid
+
+ -- v0.8 ----------
+
+ * gravity off by default
+ * revert stupid whitespace changes in 0.7.A2
+
------------------------------------------------------------------------------
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
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 $<
@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"; \
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"
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'
--- /dev/null
+./configure
+make
+make install
+
* 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
* r: remove 10 blocks at random
* s: swap fields
* suggested:
- * d: donate (next inv block given to other player)
- * f: flip (symetric vertical inversion)
+ * d (w): donate (next inv block given to other player)
+ * f (u): flip (symetric vertical inversion)
* h: hide (replaces inventory blocks by ?)
(one block restored per line added?)
* l: lower (all specials from field going down (g))
* x: seperate blocks (cut all shared pieces in quadra)
* quadra compatible?
* tetrinet compatible? (prolly not)
- * remove bot delay (make it humanplayer-like)
* new+better bot?
* ipv6
- * replay ability? (tspec replay or quadra rec compatible?)
+ * replay ability? (tspec replay and/or quadra rec compatible?)
+
+
+---- consider: ---------------------------------------------------------------
+ * colored shadows
#include "netris.h"
#include <stdlib.h>
-#ifdef DEBUG_FALLING
-# define B_OLD
-#else
-# define B_OLD abs
-#endif
-
-static BlockType board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-static BlockType oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
+#include "board.h"
+
+static const char shapes[7][4][4][4] = {
+ { { {0x00, 0x00, 0x00, 0x00}, {0x47, 0xC7, 0x97, 0x00},
+ {0x00, 0x00, 0x27, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal
+ { {0x00, 0x17, 0x00, 0x00}, {0x00, 0x37, 0x00, 0x00},
+ {0x47, 0xA7, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt vertical J
+ { {0x17, 0x00, 0x00, 0x00}, {0x67, 0xC7, 0x87, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal
+ { {0x00, 0x57, 0x87, 0x00}, {0x00, 0x37, 0x00, 0x00},
+ {0x00, 0x27, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //J (yellow)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x53, 0xC3, 0x83, 0x00},
+ {0x23, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp horizontal
+ { {0x43, 0x93, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00},
+ {0x00, 0x23, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //sharp vertical
+ { {0x00, 0x00, 0x13, 0x00}, {0x43, 0xC3, 0xA3, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //blunt horizontal
+ { {0x00, 0x13, 0x00, 0x00}, {0x00, 0x33, 0x00, 0x00},
+ {0x00, 0x63, 0x83, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //L (cyan)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x48, 0xD8, 0x88, 0x00},
+ {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing down
+ { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xB8, 0x00, 0x00},
+ {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing left
+ { {0x00, 0x18, 0x00, 0x00}, {0x48, 0xE8, 0x88, 0x00},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //pointing up
+ { {0x00, 0x18, 0x00, 0x00}, {0x00, 0x78, 0x88, 0x00},
+ {0x00, 0x28, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //T (white)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00},
+ {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+ { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00},
+ {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+ { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x52, 0x82, 0x00},
+ {0x42, 0xA2, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+ { {0x12, 0x00, 0x00, 0x00}, {0x62, 0x92, 0x00, 0x00},
+ {0x00, 0x22, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //S (green)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00},
+ {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+ { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00},
+ {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+ { {0x00, 0x00, 0x00, 0x00}, {0x46, 0x96, 0x00, 0x00},
+ {0x00, 0x66, 0x86, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+ { {0x00, 0x16, 0x00, 0x00}, {0x56, 0xA6, 0x00, 0x00},
+ {0x26, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} } }, //Z (red)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //lieing
+ { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00},
+ {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} }, //standing
+ { {0x00, 0x00, 0x00, 0x00}, {0x44, 0xC4, 0xC4, 0x84},
+ {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+ { {0x00, 0x14, 0x00, 0x00}, {0x00, 0x34, 0x00, 0x00},
+ {0x00, 0x34, 0x00, 0x00}, {0x00, 0x24, 0x00, 0x00} } }, //stick (blue)
+
+ { { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+ {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} },
+ { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+ {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+ { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+ {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} }, //rep
+ { {0x00, 0x00, 0x00, 0x00}, {0x00, 0x55, 0x95, 0x00},
+ {0x00, 0x65, 0xA5, 0x00}, {0x00, 0x00, 0x00, 0x00} } } //square (purple)
+};
+
+int ShapeIterate(char s, int scr, int y, int x, ShapeDrawFunc func)
+{ //Draw a certain shape using <ShapeDrawFunc>
+ int i, j, result;
+ char type, rotation;
+
+ type = s/4;
+ rotation = s&3;
+ for (i = 0; i<4; i++)
+ for (j = 0; j<4; j++)
+ if (shapes[type][rotation][i][j])
+ if (result = func(scr, y-i, x+j, shapes[type][rotation][i][j]))
+ return result;
+ return 0;
+}
+
+
+float stdOptions[7] = {1, 1, 1, 1, 1, 1, 1}; //stdOptions
+
+char ChooseOption(float options[7])
+{ //Return a random piece with given piece weight
+ int i;
+ float total = 0, val;
+
+ for (i = 0; i<7; i++) total += options[i];
+ val = Random(0, 32767)/32768.0*total;
+ for (i = 0; i<7; i++) if ((val -= options[i])<0) return i<<2;
+ return 0;
+}
+
+
+static unsigned char board[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
+static unsigned char oldBoard[MAX_SCREENS][MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
static unsigned int changed[MAX_SCREENS][MAX_BOARD_HEIGHT];
-static int falling[MAX_SCREENS][MAX_BOARD_WIDTH];
-static int oldFalling[MAX_SCREENS][MAX_BOARD_WIDTH];
static int shadowy;
-
-ExtFunc void ClearField(int scr)
-{
+void ClearField(int scr)
+{ //Empty the whole field (all blocks BT_none)
int y, x;
for (y = Players[scr].boardHeight - 1; y >= 0; --y)
}
} //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;
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;
Players[scr].curY, Players[scr].curX, 1);
while (ShapeFits(Players[scr].curShape, scr,
Players[scr].curY - 1, Players[scr].curX)) {
- --Players[scr].curY;
- ++count;
+ Players[scr].curY--;
+ count++;
}
PlotShape(Players[scr].curShape, scr,
- Players[scr].curY, Players[scr].curX, 1, 0);
+ Players[scr].curY, Players[scr].curX, 0);
return count;
} //DropPiece
-ExtFunc int LineIsFull(int scr, int y)
-{
+int BlockFree(int scr, int x, int y, unsigned char z)
+{ //Check if blocks are empty below block (x,y) and sticking to (x,y) mask <z>
+ unsigned char curblock;
+
+ if (y == 0) return 0; //at bottom
+ curblock = GetBlock(scr, y, x) & z;
+ if (curblock & 16 && !BlockFree(scr, x, y-1, z & 208)) return 0;
+ if (curblock & 32 && !BlockFree(scr, x, y+1, z & 224)) return 0;
+ if (curblock & 64 && !BlockFree(scr, x+1, y, z & 112)) return 0;
+ if (curblock & 128 && !BlockFree(scr, x-1, y, z & 176)) return 0;
+ if ((z = GetBlock(scr, y-1, x)) & 32) return 1; //stuck to block below
+ if (z > BT_none) return 0; //some other piece below
+ return 1; //nothing below
+}
+
+int BlockFall(int scr, int x, int y, unsigned char z)
+{ //Drop down block (x,y) and those sticking to it mask <z>
+ if (GetBlock(scr, y, x) & z & 16) BlockFall(scr, x, y-1, z & 208);
+ if (GetBlock(scr, y, x) & z & 32) BlockFall(scr, x, y+1, z & 224);
+ if (GetBlock(scr, y, x) & z & 64) BlockFall(scr, x+1, y, z & 112);
+ if (GetBlock(scr, y, x) & z & 128) BlockFall(scr, x-1, y, z & 174);
+ SetBlock(scr, y-1, x, GetBlock(scr, y, x));
+ SetBlock(scr, y, x, BT_none);
+}
+
+int CheckFall(int scr)
+{ //Drop any free blocks on field
+ int xloop, x, x2, y, fallen = 0;
+ unsigned char z;
+
+ if (!Game.gravity) return 0;
+ for (y = Players[scr].boardHeight-1; y > 0; y--)
+ for (x = 0; x < Players[scr].boardWidth; x++) {
+ if (((z = GetBlock(scr, y, x)) > BT_none) && ((z & 160) == 0)) {
+ //doesn't stick left/up => topleft block
+ if (BlockFree(scr, x, y, 240)) {
+ BlockFall(scr, x, y, 240);
+ fallen++;
+ } //move blocks down
+ } //block present
+ } //handle line
+ return fallen;
+}
+
+int LineIsFull(int scr, int y)
+{ //return 0 if any blocks present on line <y>
int x;
- for (x = 0; x < Players[scr].boardWidth; ++x)
+ for (x = 0; x < Players[scr].boardWidth; x++)
if (GetBlock(scr, y, x) <= BT_none)
return 0;
return 1;
}
-ExtFunc void CopyLine(int scr, int from, int to)
-{
+void CopyLine(int scr, int from, int to)
+{ //move blocks on line <from> to line <to>
int x;
if (from != to)
SetBlock(scr, to, x, GetBlock(scr, from, x));
}
-ExtFunc int ClearFullLines(int scr)
-{
- int from, to;
+int ClearFullLines(int scr)
+{ //remove full lines, return lines cleared
+ int from, to, x, linescleared = 0;
+ do {
from = to = 0;
while (to < Players[scr].boardHeight) {
- while (LineIsFull(scr, from))
- ++from;
+ while (LineIsFull(scr, from)) {
+ from++; //skip
+ for (x = 0; x<Players[scr].boardWidth; x++) {
+ SetBlock(scr, from, x, GetBlock(scr, from, x)&239);
+ if (from>1)
+ SetBlock(scr, from-2, x, GetBlock(scr, from-2, x)&223);
+ } //don't stick blocks to line which we'll remove
+ } //full lines
CopyLine(scr, from++, to++);
}
- return from - to;
+ linescleared += from - to;
+ } while (CheckFall(scr));
+ return linescleared;
}
-ExtFunc void FreezePiece(int scr)
+void FreezePiece(int scr)
{
- int y, x;
- BlockType type;
-
- for (y = 0; y < Players[scr].boardHeight; ++y)
- for (x = 0; x < Players[scr].boardWidth; ++x)
- if ((type = board[scr][y][x]) < 0)
- SetBlock(scr, y, x, -type);
+ // remove me! :)
}
-ExtFunc void InsertJunk(int scr, int count, int column)
-{
+void InsertJunk(int scr, int color, int count, int column)
+{ //add <count> junklines with hole at <column> to <scr> by team <color>
int y, x;
EraseShape(Players[scr].curShape, scr,
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
/*
--- /dev/null
+#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
+
--- /dev/null
+#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
+
*/
#include "netris.h"
+
#include <sys/types.h>
#include <unistd.h>
#include <curses.h>
#include <string.h>
#include <stdlib.h>
+#include "client.h"
+#include "curses.h"
+#include "util.h"
+#include "board.h"
+#include "msg.en.h"
+
#ifdef NCURSES_VERSION
# define HAVE_NCURSES
#endif
-ExtFunc void PlotBlock1(int scr, int y, int x, BlockType type);
-
static MyEventType KeyGenFunc(EventGenRec *gen, MyEvent *event);
static EventGenRec keyGen =
+// { NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
{ NULL, 0, FT_read, STDIN_FILENO, KeyGenFunc, EM_key };
static int boardYPos[MAX_SCREENS], boardXPos[MAX_SCREENS];
+static int boardSize[MAX_SCREENS];
+//^^^struct
static int statusYPos, statusXPos;
static int messageYPos, messageXPos, messageHeight, messageWidth;
+WINDOW *msgwin;
static int haveColor;
+int PlayerDisp[MAX_SCREENS];
+
+#define MSG_HEIGHT 64 //max history
+char *message[MSG_HEIGHT];
+char messages[MSG_HEIGHT][MSG_WIDTH];
static char *term_vi; /* String to make cursor invisible */
static char *term_ve; /* String to make cursor visible */
-ExtFunc void InitScreens(void)
+void InitScreens(void)
{
MySigSet oldMask;
#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 },
// keypad(stdscr, TRUE); //get arrow/functionkeys 'n stuff
OutputTermStr(term_vi, 0);
AddEventGen(&keyGen); //key handler
+ signal(SIGWINCH, CatchWinCh); //handle window resize
+// ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW);
standend(); //normal text
+
+ memset(messages, 0, sizeof(messages)); //empty messages
+ {
+ int i;
+ for (i = 0; i<MSG_HEIGHT; i++)
+ message[i] = messages[i]; //set pointers
+ }
} //InitScreens
-ExtFunc void CleanupScreens(void)
+void CleanupScreens(void)
{
RemoveEventGen(&keyGen);
endwin(); //end curses
OutputTermStr(term_ve, 1);
} //CleanupScreens
-ExtFunc void GetTermcapInfo(void)
+void GetTermcapInfo(void)
{
char *term, *buf, *data;
- int bufSize = 10240;
+ int bufSize = 8192;
+ char scratch[1024];
if (!(term = getenv("TERM")))
return;
term_vi = term_ve = NULL;
} //GetTermcapInfo
-ExtFunc void OutputTermStr(char *str, int flush)
+void OutputTermStr(char *str, int flush)
{
if (str) {
fputs(str, stdout);
}
} //OutputTermStr
-ExtFunc void DrawTitle(void)
+void DrawTitle(void)
{
int rows, cols;
char s[255];
standend(); //normal text
} //DrawTitle
-ExtFunc void DrawBox(int x1, int y1, int x2, int y2)
+void DrawBox(int x1, int y1, int x2, int y2)
{ //draw grid
int y, x;
for (y = y1 + 1; y < y2; y++) {
- mvaddch(y, x1, Game.ascii ? '|' : ACS_VLINE); //left
- mvaddch(y, x2, Game.ascii ? '|' : ACS_VLINE); //right
- }
+ mvaddch(y, x1, Sets.ascii ? '|' : ACS_VLINE); //left
+ mvaddch(y, x2, Sets.ascii ? '|' : ACS_VLINE); //right
+ } //draw vertical lines
move(y1, x1); //top
- addch(Game.ascii ? '+' : ACS_ULCORNER);
+ addch(Sets.ascii ? '+' : ACS_ULCORNER);
for (x = x1 + 1; x < x2; x++)
- addch(Game.ascii ? '-' : ACS_HLINE);
- addch(Game.ascii ? '+' : ACS_URCORNER);
+ addch(Sets.ascii ? '-' : ACS_HLINE);
+ addch(Sets.ascii ? '+' : ACS_URCORNER);
move(y2, x1); //bottom
- addch(Game.ascii ? '+' : ACS_LLCORNER);
+ addch(Sets.ascii ? '+' : ACS_LLCORNER);
for (x = x1 + 1; x < x2; x++)
- addch(Game.ascii ? '-' : ACS_HLINE);
- addch(Game.ascii ? '+' : ACS_LRCORNER);
+ addch(Sets.ascii ? '-' : ACS_HLINE);
+ addch(Sets.ascii ? '+' : ACS_LRCORNER);
} //DrawBox
-ExtFunc void DrawField(int scr)
+void DrawField(int scr)
{ //draw field for player scr
- if (!Players[scr].spy) return;
+ if (!PlayerDisp[scr]) return;
DrawBox(boardXPos[scr] - 1, boardYPos[scr] - Players[scr].boardVisible,
- boardXPos[scr] + 2 * Players[scr].boardWidth, boardYPos[scr] + 1);
+ boardXPos[scr] + boardSize[scr] * Players[scr].boardWidth, boardYPos[scr] + 1);
{
- char s[2*Players[scr].boardWidth];
+ char s[boardSize[scr]*Players[scr].boardWidth+1];
- memset(s, ' ', sizeof(s));
if (Players[scr].host && Players[scr].host[0])
- snprintf(s, sizeof(s), "%s <%s>",
+ snprintf(s, sizeof(s), " %s <%s> ",
Players[scr].name, Players[scr].host);
- else snprintf(s, sizeof(s), "%s", Players[scr].name);
- s[strlen(s)] = ' ';
- s[sizeof(s) - 7*((Players[scr].flags & SCF_usingRobot) != 0)
- - 5*((Players[scr].flags & SCF_fairRobot) != 0)] = 0;
+ else snprintf(s, sizeof(s), " %s ", Players[scr].name);
+ s[sizeof(s)] = 0;
+ if (haveColor && Players[scr].team > 0 && Players[scr].team <= 7)
+ attrset(A_REVERSE | COLOR_PAIR(Players[scr].team + 1));
mvaddstr(1, boardXPos[scr], s);
-
- if (Players[scr].flags & SCF_usingRobot) {
- addstr((Players[scr].flags & SCF_fairRobot)
- ? "(fair robot)" : "(robot)");
- } //add robot indicator
+ if (haveColor) standend();
} //display playername/host
{
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 {
} //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
} //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))
--- /dev/null
+#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
+
#define NOEXT
#include "netris.h"
+
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
-#include <setjmp.h>
+
+#include "client.h"
+#include "util.h"
+#include "board.h"
+#include "curses.h"
+#include "inet.h"
+#include "msg.en.h"
static struct option options[] = {
{ "ascii", 2, 0, 'a' },
{ "connect", 1, 0, 'c' },
{ "port", 1, 0, 'p' },
{ "level", 1, 0, 'l' },
+ { "nick", 1, 0, 'n' },
{ "team", 1, 0, 't' },
- { "spy", 1, 0, 1 },
- { "robot", 1, 0, 'r' },
- { "fair-robot", 0, 0, 'F' },
{ "dropmode", 2, 0, 'd' },
- { "instadrop", 2, 0, 'D' },
{ "color", 2, 0, 'C' },
{ "slowterm", 2, 0, 'S' },
{ "keys", 1, 0, 'k' },
"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];
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++) {
exit(1);
} //MapKeys
-ExtFunc void WriteConf(void)
+void WriteConf(void)
{
FILE *file_out;
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
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;
}
} //HandleParam
-ExtFunc void ReadConf(char *filename)
+void ReadConf(char *filename)
{
FILE *file_in;
char buf[513];
} //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--;
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;
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++)
if (Game.speed < SPEEDMINIMUM)
Game.speed = SPEEDMINIMUM;
ResetBaseTime(); //reset timer
- InitFields();
SetITimer(Game.speed, Game.speed);
Players[me].nextShape = ChooseOption(stdOptions);
- for (i = 1; i < MAX_SCREENS; i++) {
- Players[i].score.score = Players[i].score.drops
- = Players[i].score.lines = Players[i].score.adds = 0;
+ for (i = 1; i <= maxPlayer; i++) {
+ Players[i].score.score = Players[i].score.lines
+ = Players[i].score.adds = 0;
+ Players[i].score.pieces = -1;
ClearField(i);
- DrawField(i);
} //reset all players
+ InitFields();
} //StartGame
-ExtFunc void OneGame(void)
+void CheckClears(int scr)
+{ //check for full lines
+ int linesCleared;
+ int linevalues[] = { 40, 100, 400, 1200, }; //= 50*lines! - 10*(lines==1)
+// int linevaluesq[] = { 25, 50, 100, 200, 500, 720, 980, 1280, 1620, 2000,
+// 2420, 2880, 3380, 3920, 4500, 5120, 5780, 6480 };
+ int linevaluesq[] = { 20, 50, 100, 200, 500, 750, 1000, 1250, 1500, 2000,
+ 2500, 3000, 3500, 4000, 4500, 5000, 6000, 7500 };
+
+ if ((linesCleared = ClearFullLines(scr)) > 0) {
+ if (game == GT_onePlayer)
+ if ((Players[scr].score.lines / 10) <
+ ((Players[scr].score.lines+linesCleared)/10)) {
+ if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM)
+ Game.speed = SPEEDMINIMUM;
+ SetITimer(Game.speed, SetITimer(0, 0));
+ Players[scr].score.level++;
+ } //level up
+ Players[scr].score.score += Game.gravity
+ ? linevaluesq[linesCleared - 1] : linevalues[linesCleared - 1];
+ Players[scr].score.lines += linesCleared;
+ Players[scr].score.adds += linesCleared - (linesCleared < 4);
+ if (scr == me) {
+ if (game == GT_classicTwo) {
+ SendPacket(scr, NP_clear, 0, NULL);
+ if (linesCleared > 1) {
+ short junkLines;
+ netint4 data[1];
+
+ if (Game.gravity) junkLines = linesCleared - 1;
+ else junkLines = linesCleared - (linesCleared < 4);
+ data[0] = junkLines;
+ SendPacket(me, NP_giveJunk, sizeof(data), data);
+ Message("\\%dYou send %d lines",
+ Players[me].team > 7 ? 7 : Players[me].team, junkLines);
+ } //send junk to others
+ } //multiplayer
+ else {
+ Message("\\%dYou cleared %d lines",
+ Players[me].team > 7 ? 7 : Players[me].team, linesCleared);
+ } //singleplayer
+ } //IT'S YOU
+ } //lines cleared
+} //CheckClears
+
+void OneGame(void)
{
- MyEvent event;
- int linesCleared, changed = 0;
+ int changed = 0;
+ short gameStatus = 2; //2=loop; 1=new piece; 0=quit
int dropMode = 0;
+ int chatMode = 0;
+ char chatText[MSG_WIDTH] = "\0";
+
+ void GameKey(char key)
+ {
+ char *p;
+
+ if (key == 13) {
+ if (!(chatMode = !chatMode)) {
+ if (chatText[0]) {
+ Message("<\\%d%s\\7> %s",
+ Players[me].team > 7 ? 7 : Players[me].team,
+ Players[me].name, chatText);
+ if (game==GT_classicTwo)
+ SendPacket(me, NP_msg, strlen(chatText) + 1, chatText);
+ memset(chatText, 0, sizeof(chatText));
+ } //say it
+ else Messagetype(27, -1, NULL); //escape
+ return;
+ } //leave chat mode
+ } //enter pressed (start/stop chat mode)
+ if (chatMode) {
+ if (key == 27) //escape
+ chatMode = 0;
+ else if (key == 127 && chatText) //backspace
+ chatText[strlen(chatText) - 1] = 0;
+ else if (key != 13 && strlen(chatText) < MSG_WIDTH-1) //text
+ chatText[strlen(chatText)] = key;
+ Messagetype(key, strlen(chatText) - 1, chatText);
+ return;
+ } //key in chat mode
+ if (!(p = strchr(keyTable, tolower(key)))) return;
+ key = p - keyTable;
+ if (Players[me].alive <= 0 && key != KT_quit) return;
+ if (paused && key < KT_pause) return;
+ switch (key) {
+ case KT_left:
+ if (MovePiece(me, 0, -1) && spied) SendPacket(me, NP_left, 0, NULL);
+ break;
+ case KT_right:
+ if (MovePiece(me, 0, 1) && spied) SendPacket(me, NP_right, 0, NULL);
+ break;
+ case KT_rotleft:
+ if (RotatePiece(me, -1) && spied) SendPacket(me, NP_rotleft, 0, NULL);
+ break;
+ case KT_rotright:
+ if (RotatePiece(me, 1) && spied) SendPacket(me, NP_rotright, 0, NULL);
+ break;
+ case KT_down:
+ SetITimer(Game.speed, Game.speed);
+ if (MovePiece(me, -1, 0)) {
+ if (spied) SendPacket(me, NP_down, 0, NULL);
+ } //move one down
+ else
+ gameStatus = 1; //completely dropped
+ break;
+ case KT_drop:
+ SetITimer(Game.speed, Game.speed);
+ if (DropPiece(me)) {
+ if (spied) SendPacket(me, NP_drop, 0, NULL);
+ if (!Sets.dropmode) gameStatus = 1; //instadrop
+ }
+ else gameStatus = 1; //dropped
+ dropMode = Sets.dropmode>1;
+ break;
+ case KT_faster:
+ if (game != GT_onePlayer) break;
+ if ((Game.speed /= SPEEDINC) < SPEEDMINIMUM)
+ Game.speed = SPEEDMINIMUM;
+ SetITimer(Game.speed, SetITimer(0, 0));
+ Players[me].score.level++;
+ ShowScore(me, Players[me].score);
+ changed = 1;
+ break;
+ case KT_pause:
+ Players[me].flags ^= SCF_paused;
+ if (Game.started > 1)
+ Message(Players[me].flags & SCF_paused
+ ? "You paused the game" : "You unpaused the game");
+ else
+ Message(Players[me].flags & SCF_paused
+ ? "You are not ready" : "You are ready");
+ checkPaused();
+ if (game == GT_classicTwo)
+ SendPacket(me, NP_pause, 0, NULL);
+ ShowPause(me);
+ changed = 1;
+ break;
+ case KT_redraw:
+ clear();
+ InitFields();
+// ScheduleFullRedraw();
+ refresh();
+ break;
+ case KT_quit:
+ ShowPause(me);
+ refresh();
+ gameStatus = 0;
+ break;
+ } //E_key
+ if (dropMode && DropPiece(me) > 0) {
+ SetITimer(Game.speed, Game.speed);
+ if (spied) SendPacket(me, NP_drop, 0, NULL);
+ }
+ return;
+ } //GameKey
+
int oldPaused = 0;
+
+ void GameNet(_netEvent net)
+ {
+ switch(net.type) {
+ case NP_newPiece:
+ {
+ FreezePiece(net.uid);
+ memcpy(&Players[net.uid].nextShape, net.data,
+ sizeof(Players[0].nextShape));
+ StartNewPiece(net.uid, Players[net.uid].curShape);
+ break;
+ }
+ case NP_down:
+ MovePiece(net.uid, -1, 0);
+ break;
+ case NP_left:
+ MovePiece(net.uid, 0, -1);
+ break;
+ case NP_right:
+ MovePiece(net.uid, 0, 1);
+ break;
+ case NP_rotleft:
+ RotatePiece(net.uid, -1);
+ break;
+ case NP_rotright:
+ RotatePiece(net.uid, 1);
+ break;
+ case NP_drop:
+ DropPiece(net.uid);
+ break;
+ case NP_clear:
+ CheckClears(net.uid);
+ break;
+ case NP_insertJunk:
+ {
+ netint4 data[3];
+
+ memcpy(data, net.data, sizeof(data));
+ InsertJunk(net.uid, Players[data[2]].team, data[0], data[1]);
+ break;
+ } //player added junklines
+ case NP_giveJunk:
+ {
+ netint4 data[3];
+ short column;
+
+ if (Players[me].alive<=0) break;
+ memcpy(data, net.data, sizeof(data[0]));
+ column = Random(0, Players[me].boardWidth);
+ Message("\\%d%s sends %d lines",
+ Players[net.uid].team>7 ? 7 : Players[net.uid].team,
+ Players[net.uid].name, data[0]);
+ lastadd = net.uid;
+ InsertJunk(me, Players[net.uid].team, data[0], column);
+ if (spied) {
+ data[1] = column;
+ data[2] = net.uid;
+ SendPacket(me, NP_insertJunk, sizeof(data), data);
+ } //show changes to others
+ break;
+ } //receive junklines
+ case NP_msg:
+ {
+ Message("<\\%d%s\\7> %s",
+ Players[net.uid].team>7 ? 7 : Players[net.uid].team,
+ Players[net.uid].name, net.data, net.type);
+ break;
+ } //chat
+ case NP_start:
+ {
+ int i;
+
+ Game.started = 2;
+ paused = 0;
+ Message("The game has started");
+ for (i = 1; i<MAX_SCREENS; i++) if (Players[i].alive>0)
+ ShowPause(i);
+ break;
+ } //start game
+ case NP_stop:
+ {
+ if (Game.started>1) {
+ int winner;
+ float timer;
+ int i;
+
+ Message("The game has ended");
+ timer = CurTimeval()/1e6;
+ if (timer>5) {
+ for (i = MAX_SCREENS-1; i>0; i--) if (Players[i].alive>=0) {
+ Message("\\%d%10s%6.1fp%5.1fa",
+ Players[i].team>7 ? 7 : Players[i].team, Players[i].name,
+ Players[i].score.pieces/timer*60,
+ Players[i].score.adds/timer*60);
+ if (Players[i].alive>0) winner = i;
+ } //show player stats
+ if (winner)
+ Message("%s won after %0.0f'%02d\"",
+ Players[winner].name, timer/60, (int)timer%60);
+ } //show game stats
+ Message(NULL);
+ } //game was playing
+ Game.started = 0;
+ memcpy(&Game.seed, net.data, net.size);
+ {
+ int i;
+
+ for (i = 1; i<MAX_SCREENS; i++) if (Players[i].alive>=0) {
+ Players[i].alive = 1;
+ Players[i].flags |= SCF_paused;
+ } //reset players
+ }
+ StartGame(); //reset everything
+ ShowTime(); //redraw timer while unpaused
+ checkPaused(); //pause
+ oldPaused = 0; //reset pause
+ changed = 1;
+ gameStatus = 1;
+ break;
+ } //stop game
+ case NP_newPlayer:
+ {
+ char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple",
+ "Red", "Grey", "White", "*Orange" };
+
+ if (net.uid>maxPlayer) maxPlayer = net.uid;
+ memcpy(&Players[net.uid], net.data, net.size);
+ ClearField(net.uid);
+ InitFields();
+ if (Players[net.uid].team>7)
+ Message("%s joined the game", Players[net.uid].name);
+ else
+ Message("%s joined %s team", Players[net.uid].name,
+ teams[Players[net.uid].team]);
+ if (Players[net.uid].flags&SCF_paused) {
+ checkPaused();
+ } //player has paused
+// DrawField(net.uid);
+// ShowPause(net.uid);
+ changed = 1;
+ break;
+ } //player joined
+ case NP_pause:
+ {
+ char s[20];
+
+ Players[net.uid].flags ^= SCF_paused;
+ if (Game.started>1)
+ strcpy(s, Players[net.uid].flags&SCF_paused
+ ? "paused the game" : "unpaused the game");
+ else
+ strcpy(s, Players[net.uid].flags&SCF_paused
+ ? "is not ready" : "is ready");
+ Message("%s %s", Players[net.uid].name, s);
+ checkPaused();
+ ShowPause(net.uid);
+ changed = 1;
+ break;
+ } //(un)pause
+ case NP_part:
+ checkPaused();
+ oldPaused = 0;
+ {
+ Players[net.uid].alive = -1;
+ Message("%s left", Players[net.uid].name);
+ checkPaused();
+ ShowPause(net.uid);
+ changed = 1;
+ break;
+ } //player left
+ case NP_argghhh:
+ {
+ char i;
+ memcpy(&i, net.data, sizeof(i));
+ Players[net.uid].alive = 0;
+ if (i == me) Message("\\%dYou fragged %s",
+ Players[me].team>7 ? 7 : Players[me].team, Players[net.uid].name);
+ else if (i==net.uid)
+ Message("\\%d%s died",
+ Players[i].team>7 ? 7 : Players[i].team, Players[i].name);
+ else
+ Message("\\%d%s fragged %s",
+ Players[i].team>7 ? 7 : Players[i].team, Players[i].name,
+ Players[net.uid].name);
+ checkPaused();
+ ShowPause(net.uid);
+ changed = 1;
+ break;
+ } //G/O
+ default:
+ break;
+ } //E_net
+ } //GameNet
+
+ MyEvent event;
long pauseTimeLeft;
- int pieceCount = 0;
- int key;
- char *p, *cmd;
- int playercount;
- int linevalues[4] = { 40, 100, 400, 1200 }; //= 50*lines! - 10*(lines==1)
- char teams[10][7] = { "", "Green", "Cyan", "Blue", "Purple",
- "Red", "Grey", "White", "*Orange" };
int i;
StartGame();
- if (robotEnable) {
- int counter;
- RobotCmd(0, "GameType %s\n", gameNames[game]);
- RobotCmd(0, "BoardSize 0 %d %d\n",
- Players[me].boardVisible, Players[me].boardWidth);
- for (i = 1; i < MAX_SCREENS; i++)
- if ((Players[i].alive >= 0) && (i != me)) {
- RobotCmd(0, "BoardSize %d %d %d\n",
- counter, Players[i].boardVisible, Players[i].boardWidth);
- RobotCmd(0, "Opponent %d %s %s\n",
- counter, Players[i].name, Players[i].host);
- if (Players[i].flags & SCF_usingRobot)
- RobotCmd(0, "OpponentFlag %d robot\n", i);
- if (Players[i].flags & SCF_fairRobot)
- RobotCmd(0, "OpponentFlag %d fairRobot\n", i);
- counter++;
- } //enemy
- RobotCmd(0, "TickLength %.3f\n", Game.speed / 1.0e6);
- RobotCmd(0, "BeginGame\n");
- RobotTimeStamp();
- }
- while (1) {
+ while (gameStatus) {
GameLoop:
+ gameStatus = 2;
if (Players[me].alive > 0) {
if (!StartNewPiece(me, ChooseOption(stdOptions))) {
netint4 data[4];
Players[me].alive = 0;
- if (lastadd == me) Messagef("\\%dYou died",
+ if (lastadd == me) Message("\\%dYou died",
Players[me].team > 7 ? 7 : Players[me].team);
- else Messagef("\\%d%s fragged you",
+ else Message("\\%d%s fragged you",
Players[lastadd].team > 7 ? 7 : Players[lastadd].team,
Players[lastadd].name);
if (game == GT_classicTwo)
} //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) {
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;
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;
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')
// 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;
*/
#include "netris.h"
+
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
+#include <setjmp.h>
+
+#include "inet.h"
#define HEADER_SIZE sizeof(netint2[2])
#define HEADER_SIZE3 sizeof(netint4[3])
-ExtFunc MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
+MyEventType NetGenFunc(EventGenRec *gen, MyEvent *event);
EventGenRec netGen =
{ NULL, 0, FT_read, -1, NetGenFunc, EM_net, 0, "\0", 0, HEADER_SIZE3 };
-ExtFunc int InitiateConnection(char *hostStr, short port)
+static sigjmp_buf close_env;
+
+void CatchInt(int sig)
+{
+ siglongjmp(close_env, 1);
+} //CatchInt
+
+int InitiateConnection(char *hostStr, short port)
{ //connect to host
struct sockaddr_in addr;
struct hostent *host;
+ if (sigsetjmp(close_env, 1))
+ exit(0);
+ signal(SIGINT, CatchInt); //handle exit (^C)
AtExit(CloseNet);
host = gethostbyname(hostStr);
if (!host)
return 0;
} //InitiateConnection
-ExtFunc void HandShake(void)
+void HandShake(void)
{ //talk to your host
MyEvent event;
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;
}
} //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;
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];
die("write");
} //SendPacket
-ExtFunc void CloseNet(void)
+void CloseNet(void)
{ //kick some connection's ass!
MyEvent event;
--- /dev/null
+#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
+
--- /dev/null
+#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%%"
+
### 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
* $Id: netris.h,v 1.28 1999/05/16 06:56:29 mhw Exp $
*/
-#ifndef NETRIS_H
-#define NETRIS_H
+#ifndef __NETRIS_H
+#define __NETRIS_H
#include "config.h"
+
#include <sys/time.h>
#include <assert.h>
#include <stdio.h>
#include <signal.h>
-#define version_string "0.7.821"
-
-#define ExtFunc /* Marks functions that need prototypes */
+#define version_string "0.8"
#ifdef NOEXT //prevent re-declaration
# define EXT
/* Protocol versions */
#define MAJOR_VERSION 1
#define PROTOCOL_VERSION 4
-#define ROBOT_VERSION 1
#define DEFAULT_PORT 9284 /* Very arbitrary */
#define EM_alarm 000001
#define EM_key 000002
#define EM_net 000004
-#define EM_robot 000010
#define EM_connect 000020
#define EM_any 000777
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
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
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;
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;
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
#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
+++ /dev/null
-/*
- * Netris -- A free networked version of T*tris
- * Copyright (C) 1994,1995,1996 Mark H. Weaver <mhw@netris.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: robot.c,v 1.8 1996/02/09 08:22:15 mhw Exp $
- */
-
-#include "netris.h"
-#include <unistd.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <stdarg.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <errno.h>
-
-static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event);
-static EventGenRec robotGen =
- { NULL, 0, FT_read, -1, RobotGenFunc, EM_robot };
-
-static int robotProcess;
-static FILE *toRobot;
-static int toRobotFd, fromRobotFd;
-
-static char robotBuf[128];
-static int robotBufSize, robotBufMsg;
-
-static int gotSigPipe;
-
-ExtFunc void InitRobot(char *robotProg)
-{
- int to[2], from[2];
- int status;
- MyEvent event;
-
- signal(SIGPIPE, CatchPipe);
- AtExit(CloseRobot);
- if (pipe(to) || pipe(from))
- die("pipe");
- robotProcess = fork();
- if (robotProcess < 0)
- die("fork");
- if (robotProcess == 0) {
- dup2(to[0], STDIN_FILENO);
- dup2(from[1], STDOUT_FILENO);
- close(to[0]);
- close(to[1]);
- close(from[0]);
- close(from[1]);
- execl("/bin/sh", "sh", "-c", robotProg, NULL);
- die("execl failed");
- }
- close(to[0]);
- close(from[1]);
- toRobotFd = to[1];
- robotGen.fd = fromRobotFd = from[0];
- if (!(toRobot = fdopen(toRobotFd, "w")))
- die("fdopen");
- if ((status = fcntl(fromRobotFd, F_GETFL, 0)) < 0)
- die("fcntl/F_GETFL");
- status |= O_NONBLOCK;
- if (fcntl(fromRobotFd, F_SETFL, status) < 0)
- die("fcntl/F_SETFL");
- AddEventGen(&robotGen);
- RobotCmd(1, "Version %d\n", ROBOT_VERSION);
- if (WaitMyEvent(&event, EM_robot) != E_robot)
- fatal("Robot didn't start successfully");
- if (1 > sscanf(event.u.robot.data, "Version %d", &robotVersion)
- || robotVersion < 1)
- fatal("Invalid Version line from robot");
- if (robotVersion > ROBOT_VERSION)
- robotVersion = ROBOT_VERSION;
-}
-
-ExtFunc void CatchPipe(int sig)
-{
- robotGen.ready = gotSigPipe = 1;
-}
-
-ExtFunc void RobotCmd(int flush, char *fmt, ...)
-{
- va_list args;
-
- va_start(args, fmt);
- vfprintf(toRobot, fmt, args);
- va_end(args);
- if (flush)
- fflush(toRobot);
-}
-
-ExtFunc void RobotTimeStamp(void)
-{
- RobotCmd(1, "TimeStamp %.3f\n", CurTimeval() / 1.0e6);
-}
-
-ExtFunc void CloseRobot(void)
-{
- RemoveEventGen(&robotGen);
- if (robotProcess > 0)
- RobotCmd(1, "Exit\n");
- fclose(toRobot);
- close(fromRobotFd);
-}
-
-static MyEventType RobotGenFunc(EventGenRec *gen, MyEvent *event)
-{
- static int more;
- int result, i;
- char *p;
-
- if (gotSigPipe) {
- gotSigPipe = 0;
- robotGen.ready = more;
- return E_lostRobot;
- }
- if (robotBufMsg > 0) {
- /*
- * Grrrrrr! SunOS 4.1 doesn't have memmove (or atexit)
- * I'm told some others have a broken memmove
- *
- * memmove(robotBuf, robotBuf + robotBufMsg,
- * robotBufSize - robotBufMsg);
- */
- for (i = robotBufMsg; i < robotBufSize; ++i)
- robotBuf[i - robotBufMsg] = robotBuf[i];
-
- robotBufSize -= robotBufMsg;
- robotBufMsg = 0;
- }
- if (more)
- more = 0;
- else {
- do {
- result = read(fromRobotFd, robotBuf + robotBufSize,
- sizeof(robotBuf) - robotBufSize);
- } while (result < 0 && errno == EINTR);
- if (result <= 0)
- return E_lostRobot;
- robotBufSize += result;
- }
- if (!(p = memchr(robotBuf, '\n', robotBufSize))) {
- if (robotBufSize >= sizeof(robotBuf))
- fatal("Line from robot is too long");
- return E_none;
- }
- *p = 0;
- robotBufMsg = p - robotBuf + 1;
- robotGen.ready = more = (memchr(robotBuf + robotBufMsg, '\n',
- robotBufSize - robotBufMsg) != NULL);
- event->u.robot.size = p - robotBuf;
- event->u.robot.data = robotBuf;
- return E_robot;
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
+++ /dev/null
-$Id: robot_desc,v 1.4 1999/05/16 06:56:30 mhw Exp $
-
-
-GENERAL PROTOCOL
-================
-When you pass the "-r <robot>" option to Netris, it launches
-"/bin/sh -c <robot>" as a subprocess and communicates to it via pipes.
-
-The robot reads events from Netris through stdin, and writes commands to
-stdout. All exchanges are ASCII lines composed of tokens separated by
-spaces. The first token in a line is the name of the command.
-
-The robot should ignore commands which it doesn't recognize. The protocol
-may be extended by adding extra commands without incrementing the version
-number. The version number will only be increased when a command cannot
-be safely ignored.
-
-Netris will also ignore commands which it doesn't recognize, for the same
-reason.
-
-
-INITIALIZATION
-==============
-The initial exchange between Netris and the robot is Version negotiation.
-Each sends a "Version <num>" line to the other, and the lowest version is
-used. Currently, the robot protocol version is 1.
-
-Next, Netris sends "GameType <type>", there <type> is either OnePlayer
-or ClassicTwo. There may be other games in the future.
-
-Then Netris sends "BoardSize <player> <height> <width>" for each player.
-<player> is 0 for the computer player and 1 for the opponent, if any.
-Other numbers may be used in the future.
-
-For each opponent, Netris sends "Opponent <player> <username> <host>".
-<host> is not necessarily a fully qualified host name, unfortunately.
-It might even be something like "localhost".
-
-For each opponent, Netris may send 0 or more flags associated with the
-opponent. For each flag which is true, Netris sends
-"OpponentFlag <player> <flag>". Currently, the flags are "robot" and
-"fairRobot".
-
-Next, Netris sends "TickLength <seconds>", where <seconds> is the number
-of seconds between pieces stepping down.
-
-Finally, a "BeginGame" command is sent to the robot.
-
-
-NORMAL GAME (Netris --> robot)
-==============================
-Here's a list of commands sent from Netris to the robot, and a brief
-description of each one.
-
-Exit
-----
-This is always sent to the robot when the game is over, for any reason.
-The robot should exit immediately.
-
-NewPiece <num>
---------------
-This command is never sent in "fair" robot mode.
-
-Every time a new piece is created, this command is sent to the robot.
-<num> is a positive integer uniquely identifying the piece. <num> should
-be sent as a parameter to each movement command (sent to Netris) in
-order to prevent accidental movement of the wrong piece.
-
-TimeStamp <seconds>
--------------------
-This command may be sent to the robot at any time. <seconds> is
-a floating point number of seconds since the beginning of the game.
-One is always sent immediately after "BeginGame" and "RowUpdate" commands.
-One will be sent at least every tick (see "TickLength") unless the game
-is paused.
-
-RowUpdate <player> <row> <col0> <col1> <col2> ... <coln>
---------------------------------------------------------
-Whenever the screen changes, a group of these commands is sent to the
-robot followed by a "TimeStamp". After a "RowUpdate" command, the robot's
-view of the board is incorrect until the "TimeStamp".
-
-<player> is 0 for the computer player and positive numbers for opponents.
-<row> is an integer from 0 to boardHeight-1. 0 is the bottom row.
-
-<col0> ... <coln> are integers separated by spaces, one for each column.
-"0" indicates an empty square. Positive integers indicates blocks.
-Currently only "1" is used, but in the future there may be special kinds of
-blocks indicated by higher numbers. Negative integers indicate part of
-the currently falling piece. For each block, the absolute value of the
-number indicates the type of piece, and the sign indicates whether it is
-currently falling.
-
-If Netris is in "fair robot" (-F) mode, Netris will not highlight the
-falling piece with negative numbers. In this case, all numbers will
-be non-negative.
-
-UserKey <key> <keyname>
------------------------
-Whenever the user presses a key, this command is sent to the robot. The
-key is not automatically interpreted by Netris.
-
-<key> is the ascii value of the key, from 0 to 255. <keyname> is one
-of the following strings: "Left", "Rotate", "Right", "Drop", "Down",
-"ToggleSpy", "Pause", or "?". When possible, you should use <keyname>,
-since it will pay attention to keyboard remappings.
-
-For each possible <keyname> (other than "?"), there's an equivalent
-command recognized by Netris from the robot which performs the equivalent
-of the key. Therefore, if you want give the user "manual" control, you
-can send Netris "<keyname> <piecenum>".
-
-Pause <pausedByMe> <pausedByThem>
----------------------------------
-<pausedByMe> is 0 or 1, indicating whether the game is currently paused by
-our side. <pausedByThem> is 0 or 1, indicating whether any player other
-than our side has paused the game. If either is 1, the game is paused.
-
-You may actually receive this command even when neither of the flags change.
-
-
-NORMAL GAME (robot --> Netris)
-==============================
-Here's a list of commands recognized by Netris from the robot:
-
-Left <num>
-Rotate <num>
-Right <num>
-Drop <num>
-Down <num>
-ToggleSpy <num>
-Pause <num>
----------------
-These commands perform the equivalent of typing the corresponding command
-on the keyboard, if you weren't in robot mode.
-
-<num> is checked against the current piece number (the value sent along
-with "NewPiece" commands). If it doesn't match, the command is ignored.
-However, in "fair robot" mode, the <num> is ignored.
-
-These commands (except "Pause") are also ignored if the game is paused.
-
-Message <message>
------------------
-<message> is printed on the messages part of the display. Messages too
-long to fit on the screen may be truncated.
-
-<message> may contain spaces and printable characters only.
-
-
-EXAMPLE
-=======
-Here's a portion of an example log generated by the sample robot. The
-sample robot generates a log file in "log" if the "-l" is given to sr
-(eg "netris -r 'sr -l'").
-
-In this log file, every line is preceeded by two characters. Lines
-sent from Netris to the robot are preceeded by two spaces " ", and
-lines sent to Netris are preceeded by "> ".
-
-> Version 1
- Version 1
- GameType OnePlayer
- BoardSize 0 20 10
- TickLength 0.300
- BeginGame
- TimeStamp 0.009
- NewPiece 1
- RowUpdate 0 19 0 0 0 0 0 -1 -1 0 0 0
- TimeStamp 0.010
- RowUpdate 0 19 0 0 0 0 -1 -1 0 0 0 0
- RowUpdate 0 18 0 0 0 0 0 -1 -1 0 0 0
- TimeStamp 0.314
-> Message Goal 0 : ** :** : : :
-> Left 1
- TimeStamp 0.352
- RowUpdate 0 19 0 0 0 -1 -1 0 0 0 0 0
- RowUpdate 0 18 0 0 0 0 -1 -1 0 0 0 0
- TimeStamp 0.362
-> Left 1
- RowUpdate 0 19 0 0 -1 -1 0 0 0 0 0 0
- RowUpdate 0 18 0 0 0 -1 -1 0 0 0 0 0
- TimeStamp 0.375
-> Left 1
- RowUpdate 0 19 0 -1 -1 0 0 0 0 0 0 0
- RowUpdate 0 18 0 0 -1 -1 0 0 0 0 0 0
- TimeStamp 0.387
-> Left 1
- RowUpdate 0 19 -1 -1 0 0 0 0 0 0 0 0
- RowUpdate 0 18 0 -1 -1 0 0 0 0 0 0 0
- TimeStamp 0.399
-> Drop 1
- RowUpdate 0 19 0 0 0 0 0 0 0 0 0 0
- RowUpdate 0 18 0 0 0 0 0 0 0 0 0 0
- RowUpdate 0 1 -1 -1 0 0 0 0 0 0 0 0
- RowUpdate 0 0 0 -1 -1 0 0 0 0 0 0 0
- TimeStamp 0.413
- NewPiece 2
- RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
- RowUpdate 0 1 1 1 0 0 0 0 0 0 0 0
- RowUpdate 0 0 0 1 1 0 0 0 0 0 0 0
- TimeStamp 0.715
- RowUpdate 0 19 0 0 0 0 -1 -1 -1 0 0 0
- RowUpdate 0 18 0 0 0 0 0 -1 0 0 0 0
- TimeStamp 1.014
-> Message Goal 3 :*** : * : : :
-> Rotate 2
- TimeStamp 1.053
- RowUpdate 0 19 0 0 0 0 0 -1 -1 0 0 0
- RowUpdate 0 18 0 0 0 0 0 -1 0 0 0 0
- TimeStamp 1.062
- RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
- RowUpdate 0 18 0 0 0 0 0 -1 -1 0 0 0
- RowUpdate 0 17 0 0 0 0 0 -1 0 0 0 0
- TimeStamp 1.314
-> Rotate 2
- RowUpdate 0 19 0 0 0 0 0 -1 0 0 0 0
- RowUpdate 0 18 0 0 0 0 -1 -1 -1 0 0 0
- RowUpdate 0 17 0 0 0 0 0 0 0 0 0 0
- TimeStamp 1.326
-[...]
- Exit
-
-
-# vi: tw=70 ai
#define NOEXT
#include "netris.h"
+
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <errno.h>
#include <setjmp.h>
+#include "util.h"
+
#define HEADER_SIZE sizeof(netint4[3])
static struct option options[] = {
{ "wait", 0, 0, 'w' },
{ "port", 1, 0, 'p' },
+ { "quadra", 1, 0, 'q' },
{ "min-players",1, 0, 'm' },
{ "max-players",1, 0, 'x' },
{ "continuous", 1, 0, 'c' },
};
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 } };
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);
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;
RemoveEventGen(&netGen[playa]);
} //SCloseNet
-ExtFunc void CloseNets(void)
+void CloseNets(void)
{ //nou oogjes dicht en snaveltjes toe
int i;
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;
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)
return E_connect;
} //ConnGenFunc
-ExtFunc void CountPlayers(void)
+void CountPlayers(void)
{ //count number of players/teams
int i, j;
playercount = 0;
} //player alive
} //CountPlayers
-ExtFunc int StartServer(void)
+int StartServer(void)
{
MyEvent event;
netint2 currentpiece[MAX_SCREENS];
netint4 versiondata[2];
char data[255];
int major;
+ int protocolVersion;
memcpy(versiondata, event.u.net.data,
sizeof(versiondata));
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
{
static struct {
int playerflags;
- int maxplayers; //1
+ int gravity; //1
int started; //2
int continuous; //3
long seed; //4
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);
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,
} //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;
} //StartServer
-ExtFunc void Header(void)
+void SHeader(void)
{
fprintf(stderr,
"NETRIS Server %s\t(c) 2002 Shiar <shiar@shiar.org>\n\n",
version_string);
-} //Header
+}
-ExtFunc void Usage(void)
+void SUsage(void)
{
- Header();
+ SHeader();
fprintf(stderr,
"Usage: netris <options>\n"
"\n"
"\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"
"Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n"
"\n");
} //DistInfo
+*/
-ExtFunc void WriteConf(void)
+void WriteConf(void)
{
FILE *file_out;
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
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;
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];
} //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;
// 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;
+++ /dev/null
-/*
- * Netris -- A free networked version of T*tris
- * Copyright (C) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: shapes.c,v 1.16 1999/05/16 06:56:31 mhw Exp $
- */
-
-#include "netris.h"
-#include <stdlib.h>
-
-#define ShapeName(name, dir) \
- shape_ ## name ## _ ## dir
-
-#define PreDecl(name, dir) \
- static Shape ShapeName(name, dir)
-
-#define StdShape(name, cmdName, mirror, type, realDir, dir, nextDir, prevDir) \
- static Shape ShapeName(name, dir) = { \
- &ShapeName(name, nextDir), &ShapeName(name, prevDir), \
- 0, 0, mirror, D_ ## realDir, type, cmds_ ## cmdName \
- }
-
-#define FourWayDecl(name, cmdName, mirror, type) \
- PreDecl(name, down); \
- PreDecl(name, up); \
- StdShape(name, cmdName, mirror, type, left, left, up, down); \
- PreDecl(name, right); \
- StdShape(name, cmdName, mirror, type, up, up, right, left); \
- StdShape(name, cmdName, mirror, type, right, right, down, up); \
- StdShape(name, cmdName, mirror, type, down, down, left, right)
-
-#define TwoWayDecl(name, cmdName, mirror, type) \
- PreDecl(name, vert); \
- StdShape(name, cmdName, mirror, type, right, horiz, vert, vert); \
- StdShape(name, cmdName, mirror, type, down, vert, horiz, horiz)
-
-static Cmd cmds_long[] = { C_back, C_plot, C_forw, C_plot, C_forw, C_plot,
- C_forw, C_plot, C_end };
-TwoWayDecl(long, long, 0, BT_blue);
-
-static Cmd cmds_square[] = { C_plot, C_forw, C_left, C_plot, C_forw, C_left,
- C_plot, C_forw, C_left, C_plot, C_end };
-static Shape shape_square = { &shape_square, &shape_square, 0, 0, D_up, 0,
- BT_magenta, cmds_square };
-
-static Cmd cmds_l[] = { C_right, C_back, C_plot, C_forw, C_plot, C_forw,
- C_plot, C_left, C_forw, C_plot, C_end };
-FourWayDecl(l, l, 0, BT_cyan);
-FourWayDecl(l1, l, 1, BT_yellow);
-
-static Cmd cmds_t[] = { C_plot, C_forw, C_plot, C_back, C_right, C_forw,
- C_plot, C_back, C_back, C_plot, C_end };
-FourWayDecl(t, t, 0, BT_white);
-
-static Cmd cmds_s[] = { C_back, C_plot, C_forw, C_plot, C_left, C_forw,
- C_plot, C_right, C_forw, C_plot, C_end };
-TwoWayDecl(s, s, 0, BT_green);
-TwoWayDecl(s1, s, 1, BT_red);
-
-ShapeOption stdOptions[] = {
- {1, &shape_long_horiz},
- {1, &shape_square},
- {1, &shape_l_down},
- {1, &shape_l1_down},
- {1, &shape_t_down},
- {1, &shape_s_horiz},
- {1, &shape_s1_horiz},
- {0, NULL}};
-
-Shape *netMapping[] = {
- &shape_long_horiz,
- &shape_long_vert,
- &shape_square,
- &shape_l_down,
- &shape_l_right,
- &shape_l_up,
- &shape_l_left,
- &shape_l1_down,
- &shape_l1_right,
- &shape_l1_up,
- &shape_l1_left,
- &shape_t_down,
- &shape_t_right,
- &shape_t_up,
- &shape_t_left,
- &shape_s_horiz,
- &shape_s_vert,
- &shape_s1_horiz,
- &shape_s1_vert,
- NULL};
-
-ExtFunc void MoveInDir(Dir dir, int dist, int *y, int *x)
-{
- switch (dir) {
- case D_down: *y -= dist; break;
- case D_right: *x += dist; break;
- case D_up: *y += dist; break;
- case D_left: *x -= dist; break;
- default:
- assert(0);
- }
-}
-
-ExtFunc Dir RotateDir(Dir dir, int delta)
-{
- return 3 & (dir + delta);
-}
-
-ExtFunc int ShapeIterate(Shape *s, int scr, int y, int x, int falling,
-ExtFunc ShapeDrawFunc func, void *data)
-{
- int i, mirror, result;
- Dir dir;
- BlockType type;
-
- y += s->initY;
- x += s->initX;
- dir = s->initDir;
- type = falling ? -s->type : s->type;
- mirror = s->mirrored ? -1 : 1;
- for (i = 0; s->cmds[i] != C_end; ++i)
- switch (s->cmds[i]) {
- case C_forw:
- MoveInDir(dir, 1, &y, &x);
- break;
- case C_back:
- MoveInDir(dir, -1, &y, &x);
- break;
- case C_left:
- dir = RotateDir(dir, mirror);
- break;
- case C_right:
- dir = RotateDir(dir, -mirror);
- break;
- case C_plot:
- if ((result = func(scr, y, x, type, data)))
- return result;
- break;
- default:
- assert(0);
- }
- return 0;
-}
-
-ExtFunc Shape *ChooseOption(ShapeOption *options)
-{
- int i;
- float total = 0, val;
-
- for (i = 0; options[i].shape; ++i)
- total += options[i].weight;
- val = Random(0, 32767) / 32768.0 * total;
- for (i = 0; options[i].shape; ++i) {
- val -= options[i].weight;
- if (val < 0)
- return options[i].shape;
- }
- return options[0].shape;
-}
-
-ExtFunc short ShapeToNetNum(Shape *shape)
-{
- int num;
-
- for (num = 0; netMapping[num]; ++num)
- if (netMapping[num] == shape)
- return num;
- assert(0);
- return 0;
-}
-
-ExtFunc Shape *NetNumToShape(short num)
-{
- assert(num >= 0 && num < sizeof(netMapping) / sizeof(netMapping[0]) - 1);
- return netMapping[num];
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
+++ /dev/null
-/*
- * sr -- A sample robot for Netris
- * Copyright (C) 1994,1995,1996 Mark H. Weaver <mhw@netris.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: sr.c,v 1.10 1996/02/09 08:22:20 mhw Exp $
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <math.h>
-#include <limits.h>
-
-/* Both of these should be at least twice the actual max */
-#define MAX_BOARD_WIDTH 32
-#define MAX_BOARD_HEIGHT 64
-
-char b[1024];
-FILE *logFile;
-
-int twoPlayer;
-int boardHeight, boardWidth;
-int board[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-int piece[4][4];
-int pieceLast[4][4];
-
-int board1[MAX_BOARD_HEIGHT][MAX_BOARD_WIDTH];
-int piece1[4][4];
-int piece2[4][4];
-
-int pieceCount; /* Serial number of current piece, for sending commands */
-int pieceVisible; /* How many blocks of the current piece are visible */
-int pieceBottom, pieceLeft; /* Position of bottom-left square */
-int pieceBottomLast, pieceLeftLast;
-
-/*
- * 0 = Not decided yet
- * 1 = decided
- * 2 = move in progress
- * 3 = drop in progress
- */
-int pieceState;
-
-int leftDest;
-int pieceDest[4][4];
-
-int masterEnable = 1, dropEnable = 1;
-
-float curTime, moveTimeout;
-
-int min(int a, int b)
-{
- return a < b ? a : b;
-}
-
-char *ReadLine(char *buf, int size)
-{
- int len;
-
- if (!fgets(buf, size, stdin))
- return NULL;
- len = strlen(buf);
- if (len > 0 && buf[len-1] == '\n')
- buf[len-1] = 0;
- if (logFile)
- fprintf(logFile, " %s\n", buf);
- return buf;
-}
-
-int WriteLine(char *fmt, ...)
-{
- int result;
- va_list args;
-
- va_start(args, fmt);
- result = vfprintf(stdout, fmt, args);
- if (logFile) {
- fprintf(logFile, "> ");
- vfprintf(logFile, fmt, args);
- }
- va_end(args);
- return result;
-}
-
-void FindPiece(void)
-{
- int row, col;
-
- pieceVisible = 0;
- pieceBottom = MAX_BOARD_HEIGHT;
- pieceLeft = MAX_BOARD_WIDTH;
- for (row = boardHeight - 1; row >= 0; --row)
- for (col = boardWidth - 1; col >= 0; --col)
- if (board[row][col] < 0) {
- pieceBottom = row;
- if (pieceLeft > col)
- pieceLeft = col;
- pieceVisible++;
- }
- for (row = 0; row < 4; ++row)
- for (col = 0; col < 4; ++col)
- piece[row][col] = board[pieceBottom + row][pieceLeft + col] < 0;
-}
-
-void RotatePiece1(void)
-{
- int row, col, height = 0;
-
- for (row = 0; row < 4; ++row)
- for (col = 0; col < 4; ++col)
- {
- piece2[row][col] = piece1[row][col];
- piece1[row][col] = 0;
- if (piece2[row][col])
- height = row + 1;
- }
- for (row = 0; row < 4; ++row)
- for (col = 0; col < height; ++col)
- piece1[row][col] = piece2[height - col - 1][row];
-}
-
-int PieceFits(int row, int col)
-{
- int i, j;
-
- if (row < 0)
- return 0;
- for (i = 0; i < 4; ++i)
- for (j = 0; j < 4; ++j)
- if (piece1[i][j])
- if (col+j >= boardWidth || board[row+i][col+j] > 0)
- return 0;
- return 1;
-}
-
-int SimPlacement(int row, int col)
-{
- int i, j;
- int from, to, count;
-
- for (i = 0; i < boardHeight; ++i)
- for (j = 0; j < boardWidth; ++j) {
- board1[i][j] = board[i][j] > 0;
- if (i >= row && i < row+4 && j >= col && j < col+4)
- if (piece1[i - row][j - col])
- board1[i][j] = 1;
- }
- for (from = to = 0; to < boardHeight; ++from) {
- count = boardWidth;
- for (j = 0; j < boardWidth; ++j)
- count -= board1[to][j] = board1[from][j];
- to += (count > 0);
- }
- return from - to;
-}
-
-double BoardScore(int linesCleared, int pRow, int verbose)
-{
- double score = 0;
- double avgHeight2 = 0, avgHolesTimesDepth = 0;
- int maxMidHeight = 0, maxHeight = 0;
- int height[MAX_BOARD_WIDTH];
- int holesTimesDepth[MAX_BOARD_WIDTH];
- int holes[MAX_BOARD_WIDTH];
- double hardFit[MAX_BOARD_HEIGHT];
- int depend[MAX_BOARD_HEIGHT];
- int cover[MAX_BOARD_WIDTH];
- int row, col, count, i;
- int deltaLeft, deltaRight;
- double closeToTop, topShape = 0, fitProbs = 0, space = 0;
- double maxHard;
-
- for (col = 0; col < boardWidth; ++col) {
- cover[col] = 0;
- height[col] = 0;
- for (row = 0; row < boardHeight; ++row)
- if (board1[row][col])
- height[col] = row + 1;
- avgHeight2 += height[col] * height[col];
- if (maxHeight < height[col])
- maxHeight = height[col];
- if (col >= 2 && col < boardWidth - 2 && maxMidHeight < height[col])
- maxMidHeight = height[col];
- holes[col] = 0;
- holesTimesDepth[col] = 0;
- for (row = 0; row < height[col]; ++row) {
- if (board1[row][col])
- holesTimesDepth[col] += holes[col];
- else
- holes[col]++;
- }
- avgHolesTimesDepth += holesTimesDepth[col];
- }
- avgHeight2 /= boardWidth;
- avgHolesTimesDepth /= boardWidth;
-
- /* Calculate dependencies */
- for (row = maxHeight - 1; row >= 0; --row) {
- depend[row] = 0;
- for (col = 0; col < boardWidth; ++col) {
- if (board1[row][col])
- cover[col] |= 1 << row;
- else
- depend[row] |= cover[col];
- }
- for (i = row + 1; i < maxHeight; ++i)
- if (depend[row] & (1 << i))
- depend[row] |= depend[i];
- }
-
- /* Calculate hardness of fit */
- for (row = maxHeight - 1; row >= 0; --row) {
- hardFit[row] = 5;
- count = 0;
- for (col = 0; col < boardWidth; ++col) {
- if (board1[row][col]) {
- space += 0.5;
- }
- else if (!board1[row][col]) {
- count++;
- space += 1;
- hardFit[row]++;
- if (height[col] < row)
- hardFit[row] += row - height[col];
- if (col > 0)
- deltaLeft = height[col - 1] - row;
- else
- deltaLeft = MAX_BOARD_HEIGHT;
- if (col < boardWidth - 1)
- deltaRight = height[col + 1] - row;
- else
- deltaRight = MAX_BOARD_HEIGHT;
- if (deltaLeft > 2 && deltaRight > 2)
- hardFit[row] += 7;
- else if (deltaLeft > 2 || deltaRight > 2)
- hardFit[row] += 2;
- else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
- hardFit[row] += 2;
- else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
- hardFit[row] += 3;
- }
- }
- maxHard = 0;
- for (i = row + 1; i < row + 5 && i < maxHeight; ++i)
- if (depend[row] & (1 << i))
- if (maxHard < hardFit[i])
- maxHard = hardFit[i];
- fitProbs += maxHard * count;
- }
-
- /* Calculate score based on top shape */
- for (col = 0; col < boardWidth; ++col) {
- if (col > 0)
- deltaLeft = height[col - 1] - height[col];
- else
- deltaLeft = MAX_BOARD_HEIGHT;
- if (col < boardWidth - 1)
- deltaRight = height[col + 1] - height[col];
- else
- deltaRight = MAX_BOARD_HEIGHT;
- if (deltaLeft > 2 && deltaRight > 2)
- topShape += 15 + 15 * (min(deltaLeft, deltaRight) / 4);
- else if (deltaLeft > 2 || deltaRight > 2)
- topShape += 2;
- else if (abs(deltaLeft) == 2 && abs(deltaRight) == 2)
- topShape += 2;
- else if (abs(deltaLeft) == 2 || abs(deltaRight) == 2)
- topShape += 3;
- }
-
- closeToTop = (pRow / (double)boardHeight);
- closeToTop *= closeToTop;
-
- closeToTop *= 200;
- space /= 2;
- score = space + closeToTop + topShape + fitProbs - linesCleared * 10;
-
- if (verbose) {
- WriteLine("Message space=%g, close=%g, shape=%g\n",
- space, closeToTop, topShape);
- WriteLine("Message fitProbs=%g, cleared=%d\n",
- fitProbs, -linesCleared * 10);
- }
-
- return score;
-}
-
-void PrintGoal(void)
-{
- char b[32];
- int i, j, c;
-
- c = 0;
- for (i = 0; i < 4; ++i) {
- b[c++] = ':';
- for (j = 0; j < 4; ++j)
- b[c++] = pieceDest[i][j] ? '*' : ' ';
- }
- b[c++]=':';
- b[c++]=0;
- WriteLine("Message Goal %d %s\n", leftDest, b);
-}
-
-double MakeDecision(void)
-{
- int row, col, rot;
- int linesCleared;
- int first = 1;
- double minScore = 0, score;
-
- memcpy(piece1, piece, sizeof(piece));
- for (rot = 0; rot < 4; ++rot) {
- RotatePiece1();
- for (col = 0; col < boardWidth; ++col) {
- if (!PieceFits(pieceBottom, col))
- continue;
- for (row = pieceBottom; PieceFits(row-1, col); --row)
- ;
- linesCleared = SimPlacement(row, col);
- score = BoardScore(linesCleared, row, 0);
- if (first || minScore > score) {
- first = 0;
- minScore = score;
- memcpy(pieceDest, piece1, sizeof(piece));
- leftDest = col;
- }
- }
- }
- PrintGoal();
- return minScore;
-}
-
-double PeekScore(int verbose)
-{
- int row, col, linesCleared;
-
- memcpy(piece1, piece, sizeof(piece));
- col = pieceLeft;
- for (row = pieceBottom; PieceFits(row-1, col); --row)
- ;
- linesCleared = SimPlacement(row, col);
- return BoardScore(linesCleared, row, verbose);
-}
-
-int main(int argc, char **argv)
-{
- int ac;
- char *av[32];
-
- if (argc == 2 && !strcmp(argv[1], "-l")) {
- logFile = fopen("log", "w");
- if (!logFile) {
- perror("fopen log");
- exit(1);
- }
- }
- setvbuf(stdout, NULL, _IOLBF, 0);
- WriteLine("Version 1\n");
- while(ReadLine(b, sizeof b)) {
- av[0] = strtok(b, " ");
- if (!av[0])
- continue;
- ac = 1;
- while ((av[ac] = strtok(NULL, " ")))
- ac++;
- if (!strcmp(av[0], "Exit"))
- return 0;
- else if (!strcmp(av[0], "NewPiece") && ac >= 2) {
- pieceCount = atoi(av[1]);
- pieceState = 0;
- }
- else if (!strcmp(av[0], "BoardSize") && ac >= 4) {
- if (atoi(av[1]) != 0)
- continue;
- boardHeight = atoi(av[2]);
- boardWidth = atoi(av[3]);
- }
- else if (!strcmp(av[0], "RowUpdate") && ac >= 3 + boardWidth) {
- int scr, row, col;
-
- scr = atoi(av[1]);
- if (scr != 0)
- continue;
- row = atoi(av[2]);
- for (col = 0; col < boardWidth; col++)
- board[row][col] = atoi(av[3 + col]);
- }
- else if (!strcmp(av[0], "UserKey") && ac >= 3) {
- char key;
-
- key = atoi(av[1]);
- switch (key) {
- case 'v':
- case 's':
- FindPiece();
- WriteLine("Message Score = %g\n", PeekScore(key == 'v'));
- break;
- case 'e':
- masterEnable = !masterEnable;
- WriteLine("Message Enable = %d\n", masterEnable);
- break;
- case 'd':
- dropEnable = !dropEnable;
- WriteLine("Message Drop Enable = %d\n", dropEnable);
- break;
- default:
- if (strcmp(av[2], "?"))
- WriteLine("%s %d\n", av[2], pieceCount);
- break;
- }
- }
- else if (!strcmp(av[0], "TimeStamp") && ac >= 2 && masterEnable) {
- curTime = atof(av[1]);
- FindPiece();
- if (pieceVisible < 4)
- continue;
- if (memcmp(piece, pieceLast, sizeof(piece)) ||
- pieceLeft != pieceLeftLast) {
- if (pieceState == 2)
- pieceState = 1;
- memcpy(pieceLast, piece, sizeof(piece));
- pieceLeftLast = pieceLeft;
- }
- if (pieceState == 0) { /* Undecided */
- MakeDecision();
- pieceState = 1;
- }
- if (pieceState >= 2) { /* Move or drop in progress */
- if (curTime >= moveTimeout)
- pieceState = 1;
- }
- if (pieceState == 1) { /* Decided */
- if (memcmp(piece, pieceDest, sizeof(piece))) {
- WriteLine("RotRight %d\n", pieceCount);
- pieceState = 2;
- }
- else if (pieceLeft != leftDest) {
- if (pieceLeft < leftDest)
- WriteLine("Right %d\n", pieceCount);
- else
- WriteLine("Left %d\n", pieceCount);
- pieceState = 2;
- }
- else if (dropEnable) {
- WriteLine("Drop %d\n", pieceCount);
- pieceState = 3;
- }
- if (pieceState == 2)
- moveTimeout = curTime + 0.5;
- }
- }
- }
- return 0;
-}
-
-/*
- * vi: ts=4 ai
- * vim: noai si
- */
#include <sys/time.h>
#include <netdb.h>
#include <errno.h>
+#include <setjmp.h>
+
+#include "util.h"
static MyEventType AlarmGenFunc(EventGenRec *gen, MyEvent *event);
static EventGenRec alarmGen =
static long baseTimeval;
-ExtFunc void AtExit(void (*handler)(void))
+
+void AtExit(void (*handler)(void))
{
#ifdef HAS_ON_EXIT
on_exit((void *)handler, NULL);
///////////// HELP MESSAGES /////////////
-ExtFunc void Header(void)
+void Header(void)
{
fprintf(stderr,
"NETRIS %s\t(c) 1994-1996,1999 Mark H. Weaver <mhw@netris.org>\n"
version_string);
} //Header
-ExtFunc void Usage(void)
+void Usage(void)
{
Header();
fprintf(stderr,
"\n", DEFAULT_PORT, DEFAULT_KEYS);
}
-ExtFunc void DistInfo(void)
+void DistInfo(void)
{
Header();
fprintf(stderr,
"\n");
} //DistInfo
-ExtFunc void Rules(void)
+void Rules(void)
{
Header();
fprintf(stderr,
* 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;
///////////// I/O /////////////
-ExtFunc int MyRead(int fd, void *data, int len)
+int MyRead(int fd, void *data, int len)
{
int result, left;
return len;
} //MyRead
-ExtFunc int MyWrite(int fd, void *data, int len)
+int MyWrite(int fd, void *data, int len)
{
int result, left;
///////////// TIME /////////////
-ExtFunc void NormalizeTime(struct timeval *tv)
+void NormalizeTime(struct timeval *tv)
{
tv->tv_sec += tv->tv_usec / 1000000;
tv->tv_usec %= 1000000;
}
}
-ExtFunc void CatchAlarm(int sig)
+void CatchAlarm(int sig)
{
alarmGen.ready = 1;
signal(SIGALRM, CatchAlarm);
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;
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;
return GetTimeval(&old.it_value);
}
-ExtFunc long SetITimer(long interval, long value)
+long SetITimer(long interval, long value)
{
long old;
///////////// ... /////////////
-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;
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);
///////////// 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) {
}
} //RemoveEventGen
-ExtFunc MyEventType WaitMyEvent(MyEvent *event, int mask)
+MyEventType WaitMyEvent(MyEvent *event, int mask)
{ //poll
int i, retry = 0;
fd_set fds[FT_len];
--- /dev/null
+#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
+