no message
[crow/jumpnbump.git] / main.c
diff --git a/main.c b/main.c
index 3dfb537..91b1b00 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,4 +1,38 @@
+/*
+ * main.c
+ * Copyright (C) 1998 Brainchild Design - http://brainchilddesign.com/
+ * 
+ * Copyright (C) 2001 Chuck Mason <cemason@users.sourceforge.net>
+ *
+ * Copyright (C) 2002 Florian Schulze <crow@icculus.org>
+ *
+ * Portions of this code are from the MPEG software simulation group
+ * idct implementation. This code will be replaced with a new
+ * implementation soon.
+ *
+ * This file is part of Jump'n'Bump.
+ *
+ * Jump'n'Bump 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.
+ *
+ * Jump'n'Bump 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
 #include "globals.h"
+#include <fcntl.h>
+
+#ifdef USE_NET
+#include "SDL_net.h"
+#endif /* USE_NET */
 
 #ifndef M_PI
 #define M_PI           3.14159265358979323846
@@ -9,6 +43,19 @@ gob_t font_gobs = { 0 };
 gob_t object_gobs = { 0 };
 gob_t number_gobs = { 0 };
 
+main_info_t main_info;
+player_t player[JNB_MAX_PLAYERS];
+player_anim_t player_anims[7];
+object_t objects[NUM_OBJECTS];
+joy_t joy;
+mouse_t mouse;
+
+char datfile_name[2048];
+
+char *background_pic;
+char *mask_pic;
+int flip = 0;
+
 unsigned int ban_map[17][22] = {
        {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
        {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0},
@@ -152,10 +199,13 @@ struct {
        }
 };
 
+int flies_enabled = 1;
+
 struct {
        int x, y;
        int old_x, old_y;
-       pixel_t back[2];
+       int old_draw_x, old_draw_y;
+       int back[2];
        int back_defined[2];
 } flies[NUM_FLIES];
 
@@ -172,18 +222,761 @@ struct {
 
 int pogostick, bunnies_in_space, jetpack, lord_of_the_flies, blood_is_thicker_than_water;
 
+
+#ifndef _MSC_VER
+int filelength(int handle)
+{
+       struct stat buf;
+
+       if (fstat(handle, &buf) == -1) {
+               perror("filelength");
+               exit(EXIT_FAILURE);
+       }
+
+       return buf.st_size;
+}
+#endif
+
+
+/* networking shite. */
+
+int client_player_num = -1;
+int is_server = 1;
+int is_net = 0;
+
+#ifdef USE_NET
+TCPsocket sock = NULL;
+SDLNet_SocketSet socketset = NULL;
+
+typedef struct
+{
+       TCPsocket sock;
+       IPaddress addr;
+       SDLNet_SocketSet socketset;
+} NetInfo;
+
+NetInfo net_info[JNB_MAX_PLAYERS];
+#endif
+
+typedef struct
+{
+       unsigned long cmd;
+       long arg;
+       long arg2;
+       long arg3;
+       long arg4;
+} NetPacket;
+
+#define NETPKTBUFSIZE (4 + 4 + 4 + 4 + 4)
+
+#define NETCMD_NACK         (0xF00DF00D + 0)
+#define NETCMD_ACK          (0xF00DF00D + 1)
+#define NETCMD_HELLO        (0xF00DF00D + 2)
+#define NETCMD_GREENLIGHT   (0xF00DF00D + 3)
+#define NETCMD_MOVE         (0xF00DF00D + 4)
+#define NETCMD_BYE          (0xF00DF00D + 5)
+#define NETCMD_POSITION     (0xF00DF00D + 6)
+#define NETCMD_ALIVE        (0xF00DF00D + 7)
+#define NETCMD_KILL         (0xF00DF00D + 8)
+
+
+#ifdef USE_NET
+void bufToPacket(const char *buf, NetPacket *pkt)
+{
+       SDLNet_Write32(*((unsigned long *) (buf +  0)), &pkt->cmd);
+       SDLNet_Write32(*((unsigned long *) (buf +  4)), &pkt->arg);
+       SDLNet_Write32(*((unsigned long *) (buf +  8)), &pkt->arg2);
+       SDLNet_Write32(*((unsigned long *) (buf + 12)), &pkt->arg3);
+       SDLNet_Write32(*((unsigned long *) (buf + 16)), &pkt->arg4);
+/*
+       pkt->cmd               =        ntohl(*((unsigned long *) (buf +  0)));
+       pkt->arg               = (long) ntohl(*((unsigned long *) (buf +  4)));
+       pkt->arg2              = (long) ntohl(*((unsigned long *) (buf +  8)));
+       pkt->arg3              = (long) ntohl(*((unsigned long *) (buf + 12)));
+       pkt->arg4              = (long) ntohl(*((unsigned long *) (buf + 16)));
+*/
+}
+
+
+void packetToBuf(const NetPacket *pkt, char *buf)
+{
+       *((unsigned long *) (buf +  0)) = SDLNet_Read32(&pkt->cmd);
+       *((unsigned long *) (buf +  4)) = SDLNet_Read32(&pkt->arg);
+       *((unsigned long *) (buf +  8)) = SDLNet_Read32(&pkt->arg2);
+       *((unsigned long *) (buf + 12)) = SDLNet_Read32(&pkt->arg3);
+       *((unsigned long *) (buf + 16)) = SDLNet_Read32(&pkt->arg4);
+/*
+       *((unsigned long *) (buf +  0)) = htonl(pkt->cmd);
+       *((unsigned long *) (buf +  4)) = htonl((unsigned long) pkt->arg);
+       *((unsigned long *) (buf +  8)) = htonl((unsigned long) pkt->arg2);
+       *((unsigned long *) (buf + 12)) = htonl((unsigned long) pkt->arg3);
+       *((unsigned long *) (buf + 16)) = htonl((unsigned long) pkt->arg4);
+*/
+}
+
+
+void sendPacketToSock(TCPsocket s, NetPacket *pkt)
+{
+       int bytes_left = NETPKTBUFSIZE;
+       int bw;
+       char buf[NETPKTBUFSIZE];
+       char *ptr = buf;
+
+       packetToBuf(pkt, buf);
+       while (bytes_left > 0) {
+               bw = SDLNet_TCP_Send(s, ptr, bytes_left);
+               if (bw < 0) {
+                       fprintf(stderr, "SERVER: SDLNet_TCP_Send(): %s\n", SDLNet_GetError());
+                       SDLNet_TCP_Close(s);
+                       exit(42);
+               } else if (bw == 0) {
+                       SDL_Delay(1);
+               } else {
+                       bytes_left -= bw;
+                       ptr += bw;
+               }
+       }
+}
+
+
+void sendPacket(int playerid, NetPacket *pkt)
+{
+       if ( playerid < JNB_MAX_PLAYERS ) {
+               if ((player[playerid].enabled) && (playerid != client_player_num)) {
+                       sendPacketToSock(net_info[playerid].sock, pkt);
+               }
+       }
+}
+
+
+void sendPacketToAll(NetPacket *pkt)
+{
+       int i;
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               sendPacket(i, pkt);
+       }
+}
+
+
+int grabPacket(TCPsocket s, SDLNet_SocketSet ss, NetPacket *pkt)
+{
+       static char buf[NETPKTBUFSIZE];
+       static int buf_count = 0;
+       int rc;
+       int retval = 0;
+
+       if (SDLNet_CheckSockets(ss, 0) > 0) {
+               rc = SDLNet_TCP_Recv(s, &buf[buf_count], NETPKTBUFSIZE - buf_count);
+               if (rc <= 0) {  /* closed connection? */
+                       retval = -1;
+               } else if (rc != NETPKTBUFSIZE) {
+                       buf_count = rc;
+               } else {
+                       buf_count = 0;
+                       bufToPacket(buf, pkt);
+                       retval = 1;
+               }
+       }
+
+       return(retval);
+}
+
+
+int serverRecvPacket(NetPacket *pkt)
+{
+       int rc;
+       int i;
+
+       assert(is_server);
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               TCPsocket s = net_info[i].sock;
+
+               if ((i == client_player_num) || (!player[i].enabled))
+                       continue;
+
+               rc = grabPacket(s, net_info[i].socketset, pkt);
+               if (rc < 0) {
+                       NetPacket pkt;
+
+                       player[i].enabled = 0;
+                       SDLNet_TCP_Close(s);
+                       pkt.cmd = NETCMD_BYE;
+                       pkt.arg = i;
+                       pkt.arg2 = 0;
+                       pkt.arg3 = 0;
+                       pkt.arg4 = 0;
+                       sendPacketToAll(&pkt);
+               } else if (rc > 0) {
+                       return(i);  /* it's all good. */
+               }
+       }
+
+       return(-1);  /* no packets available currently. */
+}
+
+
+void wait_for_greenlight(void)
+{
+       NetPacket pkt;
+       int i;
+
+       printf("CLIENT: Waiting for greenlight...\n");
+
+       do {
+               int rc;
+               while ((rc = grabPacket(sock, socketset, &pkt)) == 0) {
+                       SDL_Delay(100);  /* nap and then try again. */
+               }
+
+               if (rc < 0) {
+                       printf("CLIENT: Lost connection.\n");
+                       SDLNet_TCP_Close(sock);
+                       exit(42);
+               }
+       } while (pkt.cmd != NETCMD_GREENLIGHT);
+
+       printf("CLIENT: Got greenlight.\n");
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               if (pkt.arg & (1 << i)) {
+                       printf("CLIENT: There is a player #%d.\n", i);
+                       player[i].enabled = 1;
+               }
+       }
+}
+
+
+static int buggered_off = 0;
+
+
+void tellServerGoodbye(void)
+{
+       NetPacket pkt;
+
+       if (!buggered_off) {
+               buggered_off = 1;
+               pkt.cmd = NETCMD_BYE;
+               pkt.arg = client_player_num;
+               pkt.arg2 = 0;
+               pkt.arg3 = 0;
+               pkt.arg4 = 0;
+               sendPacketToSock(sock, &pkt);
+       }
+}
+#endif /* USE_NET */
+
+
+void processMovePacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+       int movetype = ((pkt->arg2 >> 16) & 0xFF);
+       int newval   = ((pkt->arg2 >>  0) & 0xFF);
+
+       if (movetype == MOVEMENT_LEFT) {
+               player[playerid].action_left = newval;
+       } else if (movetype == MOVEMENT_RIGHT) {
+               player[playerid].action_right = newval;
+       } else if (movetype == MOVEMENT_UP) {
+               player[playerid].action_up = newval;
+       } else {
+               printf("bogus MOVE packet!\n");
+       }
+
+       player[playerid].x = pkt->arg3;
+       player[playerid].y = pkt->arg4;
+}
+
+
+void tellServerPlayerMoved(int playerid, int movement_type, int newval)
+{
+       NetPacket pkt;
+
+       pkt.cmd = NETCMD_MOVE;
+       pkt.arg = playerid;
+       pkt.arg2 = ( ((movement_type & 0xFF) << 16) | ((newval & 0xFF) << 0) );
+       pkt.arg3 = player[playerid].x;
+       pkt.arg4 = player[playerid].y;
+
+       if (is_server) {
+               processMovePacket(&pkt);
+#ifdef USE_NET
+               if (is_net)
+                       sendPacketToAll(&pkt);
+       } else {
+               sendPacketToSock(sock, &pkt);
+#endif
+       }
+}
+
+
+#ifdef USE_NET
+void tellServerNewPosition(void)
+{
+       NetPacket pkt;
+       pkt.cmd = NETCMD_POSITION;
+       pkt.arg = client_player_num;
+       pkt.arg2 = player[client_player_num].x;
+       pkt.arg3 = player[client_player_num].y;
+
+       if (is_server) {
+               sendPacketToAll(&pkt);
+       } else {
+               sendPacketToSock(sock, &pkt);
+       }
+}
+#endif /* USE_NET */
+
+
+void processKillPacket(NetPacket *pkt)
+{
+       int c1 = pkt->arg;
+       int c2 = pkt->arg2;
+       int x = pkt->arg3;
+       int y = pkt->arg4;
+       int c4 = 0;
+       int s1 = 0;
+
+       player[c1].y_add = -player[c1].y_add;
+       if (player[c1].y_add > -262144L)
+               player[c1].y_add = -262144L;
+       player[c1].jump_abort = 1;
+       player[c2].dead_flag = 1;
+       if (player[c2].anim != 6) {
+               player[c2].anim = 6;
+               player[c2].frame = 0;
+               player[c2].frame_tick = 0;
+               player[c2].image = player_anims[player[c2].anim].frame[player[c2].frame].image + player[c2].direction * 9;
+               if (main_info.no_gore == 0) {
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FUR, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 44 + c2 * 8);
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 76);
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 77);
+                       for (c4 = 0; c4 < 8; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 78);
+                       for (c4 = 0; c4 < 10; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 79);
+               }
+               dj_play_sfx(SFX_DEATH, (unsigned short)(SFX_DEATH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
+               player[c1].bumps++;
+               player[c1].bumped[c2]++;
+               s1 = player[c1].bumps % 100;
+               add_leftovers(0, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
+               add_leftovers(1, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
+               add_leftovers(0, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+               add_leftovers(1, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+       }
+}
+
+
+#ifdef USE_NET
+void processPositionPacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+
+       player[playerid].x = pkt->arg2;
+       player[playerid].y = pkt->arg3;
+}
+
+
+void processAlivePacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+
+       player[playerid].dead_flag = 0;
+       player[playerid].x = pkt->arg2;
+       player[playerid].y = pkt->arg3;
+}
+
+
+void serverTellEveryoneGoodbye(void)
+{
+       int i;
+
+       if (!buggered_off) {
+               buggered_off = 1;
+               for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+                       if (player[i].enabled) {
+                               NetPacket pkt;
+
+                               pkt.cmd = NETCMD_BYE;
+                               pkt.arg = i;
+                               pkt.arg2 = 0;
+                               pkt.arg3 = 0;
+                               pkt.arg4 = 0;
+                               sendPacketToAll(&pkt);
+                       }
+               }
+       }
+}
+
+
+int server_said_bye = 0;
+
+
+int update_players_from_server(void)
+{
+       NetPacket pkt;
+       int rc;
+
+       assert(!is_server);
+
+       while ((rc = grabPacket(sock, socketset, &pkt)) != 0) {
+               if (rc < 0) {
+                       printf("CLIENT: Lost connection.\n");
+                       pkt.cmd = NETCMD_BYE;
+                       pkt.arg = client_player_num;
+               }
+
+               if (pkt.cmd == NETCMD_BYE) {
+                       if (pkt.arg == client_player_num) {
+                               SDLNet_FreeSocketSet(socketset);
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                               server_said_bye = 1;
+                               return(0);
+                       } else {
+                               player[pkt.arg].enabled = 0;
+                       }
+               } else if (pkt.cmd == NETCMD_MOVE) {
+                       processMovePacket(&pkt);
+               } else if (pkt.cmd == NETCMD_ALIVE) {
+                       processAlivePacket(&pkt);
+               } else if (pkt.cmd == NETCMD_POSITION) {
+                       processPositionPacket(&pkt);
+               } else if (pkt.cmd == NETCMD_KILL) {
+                       processKillPacket(&pkt);
+               } else {
+                       printf("CLIENT: Got an unknown packet: 0x%lX.\n", pkt.cmd);
+               }
+       }
+
+       return(1);
+}
+
+
+void serverSendAlive(int playerid)
+{
+       NetPacket pkt;
+
+       assert(is_server);
+       pkt.cmd = NETCMD_ALIVE;
+       pkt.arg = playerid;
+       pkt.arg2 = player[playerid].x;
+       pkt.arg3 = player[playerid].y;
+       sendPacketToAll(&pkt);
+}
+#endif /* USE_NET */
+
+
+void serverSendKillPacket(int killer, int victim)
+{
+       NetPacket pkt;
+
+       assert(is_server);
+       pkt.cmd = NETCMD_KILL;
+       pkt.arg = killer;
+       pkt.arg2 = victim;
+       pkt.arg3 = player[victim].x;
+       pkt.arg4 = player[victim].y;
+       processKillPacket(&pkt);
+#ifdef USE_NET
+       if (is_net)
+               sendPacketToAll(&pkt);
+#endif
+}
+
+
+#ifdef USE_NET
+void update_players_from_clients(void)
+{
+       int i;
+       NetPacket pkt;
+       int playerid;
+
+       assert(is_server);
+
+       while ((playerid = serverRecvPacket(&pkt)) >= 0) {
+               if (pkt.cmd == NETCMD_BYE) {
+                       pkt.arg = playerid;  /* just in case. */
+                       sendPacketToAll(&pkt);
+                       player[playerid].enabled = 0;
+                       SDLNet_FreeSocketSet(net_info[playerid].socketset);
+                       SDLNet_TCP_Close(net_info[playerid].sock);
+               } else if (pkt.cmd == NETCMD_POSITION) {
+                       pkt.arg = playerid;  /* just in case. */
+                       processPositionPacket(&pkt);
+                       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+                               if (i != playerid) {
+                                       sendPacket(i, &pkt);
+                               }
+                       }
+               } else if (pkt.cmd == NETCMD_MOVE) {
+                       pkt.arg = playerid;  /* just in case. */
+                       /*
+                       pkt.arg3 = player[playerid].x;
+                       pkt.arg4 = player[playerid].y;
+                       */
+                       processMovePacket(&pkt);
+                       sendPacketToAll(&pkt);
+               } else {
+                       printf("SERVER: Got unknown packet (0x%lX).\n", pkt.cmd);
+               }
+       }
+}
+
+
+void init_server(const char *netarg)
+{
+       NetPacket pkt;
+       IPaddress addr;
+       int i;
+       int wait_for_clients = ((netarg == NULL) ? 0 : atoi(netarg));
+       char *ipstr;
+
+       if ((wait_for_clients > (JNB_MAX_PLAYERS - 1)) || (wait_for_clients < 0)) {
+               printf("SERVER: Waiting for bogus client count (%d).\n", wait_for_clients);
+               exit(42);
+       }
+
+       if (SDLNet_Init() < 0) {
+               exit(42);
+       }
+       atexit(SDLNet_Quit);
+       
+       SDLNet_ResolveHost(&addr, NULL, JNB_INETPORT);
+       ipstr = SDLNet_ResolveIP(&addr);
+       SDLNet_ResolveHost(&addr, ipstr, JNB_INETPORT);
+       printf("SERVER: we are %s (%i.%i.%i.%i:%i).\n", ipstr, (addr.host >> 0) & 0xff, (addr.host >> 8) & 0xff, (addr.host >> 16) & 0xff, (addr.host >> 24) & 0xff, addr.port);
+       net_info[client_player_num].addr = addr;
+
+       addr.host = INADDR_ANY;
+       sock = SDLNet_TCP_Open(&addr);
+       if (sock == NULL) {
+               fprintf(stderr, "SERVER: SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       player[client_player_num].enabled = 1;
+
+       printf("SERVER: waiting for (%d) clients...\n", wait_for_clients);
+
+       socketset = SDLNet_AllocSocketSet(JNB_MAX_PLAYERS + 1);
+       SDLNet_TCP_AddSocket(socketset, sock);
+
+       while (wait_for_clients > 0)
+       {
+               char buf[NETPKTBUFSIZE];
+               IPaddress *from;
+               int negatory = 1;
+               int br;
+               TCPsocket s;
+
+               /* Wait for events */
+               SDLNet_CheckSockets(socketset, ~0);
+               if ( SDLNet_SocketReady(sock) ) {
+                       s = SDLNet_TCP_Accept(sock);
+
+                       if (s == NULL)
+                       {
+                               fprintf(stderr, "SERVER: SDLNet_TCP_Accept(): %s", SDLNet_GetError());
+                               SDLNet_TCP_Close(sock);
+                               exit(42);
+                       }
+               } else
+                       continue;
+
+               br = SDLNet_TCP_Recv(s, buf, NETPKTBUFSIZE);
+               if (br < 0) {
+                       fprintf(stderr, "SERVER: SDLNet_TCP_Recv(): %s\n", SDLNet_GetError());
+                       SDLNet_TCP_Close(s);
+                       SDLNet_TCP_Close(sock);
+                       exit(42);
+               }
+
+               from = SDLNet_TCP_GetPeerAddress(s);
+               ipstr = SDLNet_ResolveIP(from);
+               printf("SERVER: Got data from %s (%i.%i.%i.%i:%i).\n", ipstr, (from->host >> 0) & 0xff, (from->host >> 8) & 0xff, (from->host >> 16) & 0xff, (from->host >> 24) & 0xff, from->port);
+
+               if (br != NETPKTBUFSIZE) {
+                       printf("SERVER: Bogus packet.\n");
+                       continue;
+               }
+
+               bufToPacket(buf, &pkt);
+               if (pkt.cmd != NETCMD_HELLO) {
+                       printf("SERVER: Bogus packet.\n");
+                       continue;
+               }
+
+               printf("SERVER: Client claims to be player #%ld.\n", pkt.arg);
+
+               if (pkt.arg > JNB_MAX_PLAYERS) {
+                       printf("SERVER:  (that's an invalid player number.)\n");
+               } else {
+                       if (player[pkt.arg].enabled) {
+                               printf("SERVER:  (that player number is already taken.)\n");
+                       } else {
+                               negatory = 0;
+                       }
+               }
+
+               if (negatory) {
+                       printf("SERVER: Forbidding connection.\n");
+                       pkt.cmd = NETCMD_NACK;
+                       sendPacketToSock(s, &pkt);
+                       SDLNet_TCP_Close(s);
+               } else {
+                       player[pkt.arg].enabled = 1;
+                       net_info[pkt.arg].sock = s;
+                       net_info[pkt.arg].addr = *from;
+                       net_info[pkt.arg].socketset = SDLNet_AllocSocketSet(1);
+                       SDLNet_TCP_AddSocket(net_info[pkt.arg].socketset, net_info[pkt.arg].sock);
+                       wait_for_clients--;
+                       printf("SERVER: Granting connection. (%d) to go.\n", wait_for_clients);
+                       pkt.cmd = NETCMD_ACK;
+                       sendPacket(pkt.arg, &pkt);
+               }
+       }
+
+       SDLNet_TCP_Close(sock);  /* done with the listen socket. */
+       SDLNet_FreeSocketSet(socketset);
+       sock = NULL;
+       socketset = NULL;
+
+       printf("SERVER: Got all our connections. Greenlighting clients...\n");
+
+       pkt.cmd = NETCMD_GREENLIGHT;
+       pkt.arg = 0;
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               if (player[i].enabled) {
+                       pkt.arg |= (1 << i);
+               }
+       }
+       sendPacketToAll(&pkt);
+}
+
+
+void connect_to_server(char *netarg)
+{
+       NetPacket pkt;
+       char buf[NETPKTBUFSIZE];
+       char *ipstr;
+       IPaddress hent;
+       IPaddress addr;
+       int br;
+
+       if (netarg == NULL) {
+               printf("CLIENT: Need to specify host to connect to.\n");
+               exit(42);
+       }
+
+       if (SDLNet_Init() < 0) {
+               exit(42);
+       }
+       atexit(SDLNet_Quit);
+       
+       player[client_player_num].enabled = 1;
+
+       SDLNet_ResolveHost(&addr, NULL, JNB_INETPORT);
+       ipstr = SDLNet_ResolveIP(&addr);
+       SDLNet_ResolveHost(&addr, ipstr, JNB_INETPORT);
+       printf("CLIENT: we are %s (%i.%i.%i.%i:%i).\n", ipstr, (addr.host >> 0) & 0xff, (addr.host >> 8) & 0xff, (addr.host >> 16) & 0xff, (addr.host >> 24) & 0xff, addr.port);
+       net_info[client_player_num].addr = addr;
+
+       if (SDLNet_ResolveHost(&hent, netarg, JNB_INETPORT) < 0) {
+               fprintf(stderr, "CLIENT: couldn't find host: %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       sock = SDLNet_TCP_Open(&hent);
+       if (sock == NULL) {
+               fprintf(stderr, "CLIENT: SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       socketset = SDLNet_AllocSocketSet(1);
+       SDLNet_TCP_AddSocket(socketset, sock);
+
+       printf("CLIENT: connected to %s...\n", SDLNet_ResolveIP(&hent));
+
+       printf("CLIENT: Sending HELLO packet...\n");
+       pkt.cmd = NETCMD_HELLO;
+       pkt.arg = client_player_num;
+       sendPacketToSock(sock, &pkt);
+
+       printf("CLIENT: Waiting for ACK from server...\n");
+
+       br = SDLNet_TCP_Recv(sock, buf, NETPKTBUFSIZE);
+       if (br < 0) {
+               fprintf(stderr, "CLIENT: recv(): %s\n", SDLNet_GetError());
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       if (br != NETPKTBUFSIZE) {
+               printf("CLIENT: Bogus packet size (%d of %d). FIXME.\n", br, NETPKTBUFSIZE);
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       bufToPacket(buf, &pkt);
+
+       if (pkt.cmd == NETCMD_NACK) {
+               printf("CLIENT: Server forbid us from playing.\n");
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       if (pkt.cmd != NETCMD_ACK) {
+               printf("CLIENT: Unexpected packet (cmd=0x%lX).\n", pkt.cmd);
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       printf("CLIENT: Server accepted our connection.\n");
+
+       wait_for_greenlight();
+}
+#endif /* USE_NET */
+
+
+static void flip_pixels(unsigned char *pixels)
+{
+       int x,y;
+       unsigned char temp;
+
+       assert(pixels);
+       for (y = 0; y < JNB_HEIGHT; y++) {
+               for (x = 0; x < (352/2); x++) {
+                       temp = pixels[y*JNB_WIDTH+x];
+                       pixels[y*JNB_WIDTH+x] = pixels[y*JNB_WIDTH+(352-x)-1];
+                       pixels[y*JNB_WIDTH+(352-x)-1] = temp;
+               }
+       }
+}
+
+
 int main(int argc, char *argv[])
 {
-       FILE *handle;
-       int c1, c2 = 0, c3, c4;
+       unsigned char *handle;
+       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
        int l1;
        int s1, s2, s3, s4;
-       int closest_player = 0, dist, cur_dist;
-       int end_loop_flag, fade_flag;
+       int closest_player = 0, dist, cur_dist = 0;
+       int end_loop_flag = 0, fade_flag = 0;
        int mod_vol, sfx_vol, mod_fade_direction;
        char str1[100];
        char pal[768];
        char cur_pal[768];
+       int update_count;
 
        if (init_program(argc, argv, pal) != 0)
                deinit_program();
@@ -195,8 +988,9 @@ int main(int argc, char *argv[])
 
        while (1) {
 
-               if (menu() != 0)
-                       deinit_program();
+               if (!is_net)
+                       if (menu() != 0)
+                               deinit_program();
 
                if (key_pressed(1) == 1) {
                        break;
@@ -210,7 +1004,6 @@ int main(int argc, char *argv[])
                setpalette(0, 256, cur_pal);
 
                recalculate_gob(&rabbit_gobs, pal);
-               recalculate_gob(&font_gobs, pal);
                recalculate_gob(&object_gobs, pal);
                recalculate_gob(&number_gobs, pal);
 
@@ -218,17 +1011,20 @@ int main(int argc, char *argv[])
                register_background(background_pic, pal);
                flippage(0);
 
-               s1 = rnd(250) + 50;
-               s2 = rnd(150) + 50;
-               for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                       while (1) {
-                               flies[c1].x = s1 + rnd(101) - 50;
-                               flies[c1].y = s2 + rnd(101) - 50;
-                               if (ban_map[flies[c1].y >> 4][flies[c1].x >> 4] == BAN_VOID)
-                                       break;
+               if (flies_enabled) {
+                       s1 = rnd(250) + 50;
+                       s2 = rnd(150) + 50;
+
+                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
+                               while (1) {
+                                       flies[c1].x = s1 + rnd(101) - 50;
+                                       flies[c1].y = s2 + rnd(101) - 50;
+                                       if (ban_map[flies[c1].y >> 4][flies[c1].x >> 4] == BAN_VOID)
+                                               break;
+                               }
+                               flies[c1].back_defined[0] = 0;
+                               flies[c1].back_defined[1] = 0;
                        }
-                       flies[c1].back_defined[0] = 0;
-                       flies[c1].back_defined[1] = 0;
                }
 
                mod_vol = sfx_vol = 10;
@@ -237,7 +1033,10 @@ int main(int argc, char *argv[])
                dj_set_mod_volume((char)mod_vol);
                dj_set_sfx_volume((char)mod_vol);
                dj_start_mod();
-               dj_play_sfx(SFX_FLY, SFX_FLY_FREQ, 0, 0, 0, 4);
+
+               if (flies_enabled)
+                       dj_play_sfx(SFX_FLY, SFX_FLY_FREQ, 0, 0, 0, 4);
+
                dj_set_nosound(0);
 
                lord_of_the_flies = bunnies_in_space = jetpack = pogostick = blood_is_thicker_than_water = 0;
@@ -247,417 +1046,439 @@ int main(int argc, char *argv[])
                main_info.view_page = 0;
                main_info.draw_page = 1;
 
+               update_count = 1;
                while (1) {
+                       while (update_count) {
 
-                       if (key_pressed(1) == 1) {
-                               end_loop_flag = 1;
-                               memset(pal, 0, 768);
-                               mod_fade_direction = 0;
-                       }
-
-                       if (strncmp(last_keys, "kcitsogop", strlen("kcitsogop")) == 0) {
-                               pogostick ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "ecapsniseinnub", strlen("ecapsniseinnub")) == 0) {
-                               bunnies_in_space ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "kcaptej", strlen("kcaptej")) == 0) {
-                               jetpack ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "seilfehtfodrol", strlen("seilfehtfodrol")) == 0) {
-                               lord_of_the_flies ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "retawnahtrekcihtsidoolb", strlen("retawnahtrekcihtsidoolb")) == 0) {
-                               blood_is_thicker_than_water ^= 1;
-                               if (blood_is_thicker_than_water == 1) {
-                                       pal[432] = 63;
-                                       pal[433] = 32;
-                                       pal[434] = 32;
-                                       pal[435] = 53;
-                                       pal[436] = 17;
-                                       pal[437] = 17;
-                                       pal[438] = 42;
-                                       pal[439] = 7;
-                                       pal[440] = 7;
-                                       pal[441] = 28;
-                                       pal[442] = 0;
-                                       pal[443] = 0;
-                                       pal[444] = 24;
-                                       pal[445] = 0;
-                                       pal[446] = 0;
-                                       pal[447] = 19;
-                                       pal[448] = 0;
-                                       pal[449] = 0;
-                                       pal[450] = 12;
-                                       pal[451] = 0;
-                                       pal[452] = 0;
-                                       pal[453] = 7;
-                                       pal[454] = 0;
-                                       pal[455] = 0;
-                               } else {
-                                       pal[432] = 63;
-                                       pal[433] = 63;
-                                       pal[434] = 63;
-                                       pal[435] = 40;
-                                       pal[436] = 53;
-                                       pal[437] = 62;
-                                       pal[438] = 19;
-                                       pal[439] = 42;
-                                       pal[440] = 60;
-                                       pal[441] = 0;
-                                       pal[442] = 33;
-                                       pal[443] = 60;
-                                       pal[444] = 3;
-                                       pal[445] = 32;
-                                       pal[446] = 46;
-                                       pal[447] = 3;
-                                       pal[448] = 26;
-                                       pal[449] = 33;
-                                       pal[450] = 3;
-                                       pal[451] = 19;
-                                       pal[452] = 21;
-                                       pal[453] = 1;
-                                       pal[454] = 8;
-                                       pal[455] = 8;
+                               if (key_pressed(1) == 1) {
+#ifdef USE_NET
+                                       if (is_net) {
+                                               if (is_server) {
+                                                       serverTellEveryoneGoodbye();
+                                               } else {
+                                                       tellServerGoodbye();
+                                               }
+                                       }
+#endif
+                                       end_loop_flag = 1;
+                                       memset(pal, 0, 768);
+                                       mod_fade_direction = 0;
                                }
-                               last_keys[0] = 0;
-                       }
 
-                       steer_players();
-
-                       dj_mix();
+                               if (strncmp(last_keys, "kcitsogop", strlen("kcitsogop")) == 0) {
+                                       pogostick ^= 1;
+                                       last_keys[0] = 0;
+                               }
+                               if (strncmp(last_keys, "ecapsniseinnub", strlen("ecapsniseinnub")) == 0) {
+                                       bunnies_in_space ^= 1;
+                                       last_keys[0] = 0;
+                               }
+                               if (strncmp(last_keys, "kcaptej", strlen("kcaptej")) == 0) {
+                                       jetpack ^= 1;
+                                       last_keys[0] = 0;
+                               }
+                               if (strncmp(last_keys, "seilfehtfodrol", strlen("seilfehtfodrol")) == 0) {
+                                       lord_of_the_flies ^= 1;
+                                       last_keys[0] = 0;
+                               }
+                               if (strncmp(last_keys, "retawnahtrekcihtsidoolb", strlen("retawnahtrekcihtsidoolb")) == 0) {
+                                       blood_is_thicker_than_water ^= 1;
+                                       if (blood_is_thicker_than_water == 1) {
+                                               pal[432] = 63;
+                                               pal[433] = 32;
+                                               pal[434] = 32;
+                                               pal[435] = 53;
+                                               pal[436] = 17;
+                                               pal[437] = 17;
+                                               pal[438] = 42;
+                                               pal[439] = 7;
+                                               pal[440] = 7;
+                                               pal[441] = 28;
+                                               pal[442] = 0;
+                                               pal[443] = 0;
+                                               pal[444] = 24;
+                                               pal[445] = 0;
+                                               pal[446] = 0;
+                                               pal[447] = 19;
+                                               pal[448] = 0;
+                                               pal[449] = 0;
+                                               pal[450] = 12;
+                                               pal[451] = 0;
+                                               pal[452] = 0;
+                                               pal[453] = 7;
+                                               pal[454] = 0;
+                                               pal[455] = 0;
+                                       } else {
+                                               pal[432] = 63;
+                                               pal[433] = 63;
+                                               pal[434] = 63;
+                                               pal[435] = 40;
+                                               pal[436] = 53;
+                                               pal[437] = 62;
+                                               pal[438] = 19;
+                                               pal[439] = 42;
+                                               pal[440] = 60;
+                                               pal[441] = 0;
+                                               pal[442] = 33;
+                                               pal[443] = 60;
+                                               pal[444] = 3;
+                                               pal[445] = 32;
+                                               pal[446] = 46;
+                                               pal[447] = 3;
+                                               pal[448] = 26;
+                                               pal[449] = 33;
+                                               pal[450] = 3;
+                                               pal[451] = 19;
+                                               pal[452] = 21;
+                                               pal[453] = 1;
+                                               pal[454] = 8;
+                                               pal[455] = 8;
+                                       }
+                                       register_background(background_pic, pal);
+                                       recalculate_gob(&object_gobs, pal);
+                                       last_keys[0] = 0;
+                               }
 
-                       for (c3 = 0; c3 < 6; c3++) {
-                               if (c3 == 0) {
-                                       c1 = 0;
-                                       c2 = 1;
-                               } else if (c3 == 1) {
-                                       c1 = 0;
-                                       c2 = 2;
-                               } else if (c3 == 2) {
-                                       c1 = 0;
-                                       c2 = 3;
-                               } else if (c3 == 3) {
-                                       c1 = 1;
-                                       c2 = 2;
-                               } else if (c3 == 4) {
-                                       c1 = 1;
-                                       c2 = 3;
-                               } else if (c3 == 5) {
-                                       c1 = 2;
-                                       c2 = 3;
+#ifdef USE_NET
+                               if (is_net) {
+                                       if (is_server) {
+                                               update_players_from_clients();
+                                       } else {
+                                               if (!update_players_from_server()) {
+                                                       break;  /* got a BYE packet */
+                                               }
+                                       }
                                }
-                               if (player[c1].enabled == 1 && player[c2].enabled == 1) {
-                                       if (labs(player[c1].x - player[c2].x) < (12L << 16) && labs(player[c1].y - player[c2].y) < (12L << 16)) {
-                                               if ((labs(player[c1].y - player[c2].y) >> 16) > 5) {
-                                                       if (player[c1].y < player[c2].y) {
-                                                               if (player[c1].y_add >= 0) {
-                                                                       player[c1].y_add = -player[c1].y_add;
-                                                                       if (player[c1].y_add > -262144L)
-                                                                               player[c1].y_add = -262144L;
-                                                                       player[c1].jump_abort = 1;
-                                                                       player[c2].dead_flag = 1;
-                                                                       if (player[c2].anim != 6) {
-                                                                               player[c2].anim = 6;
-                                                                               player[c2].frame = 0;
-                                                                               player[c2].frame_tick = 0;
-                                                                               player[c2].image = player_anims[player[c2].anim].frame[player[c2].frame].image + player[c2].direction * 9;
-                                                                               if (main_info.no_gore == 0) {
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FUR, (player[c2].x >> 16) + 6 + rnd(5), (player[c2].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 44 + c2 * 8);
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c2].x >> 16) + 6 + rnd(5), (player[c2].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 76);
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c2].x >> 16) + 6 + rnd(5), (player[c2].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 77);
-                                                                                       for (c4 = 0; c4 < 8; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c2].x >> 16) + 6 + rnd(5), (player[c2].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 78);
-                                                                                       for (c4 = 0; c4 < 10; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c2].x >> 16) + 6 + rnd(5), (player[c2].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 79);
-                                                                               }
-                                                                               dj_play_sfx(SFX_DEATH, (unsigned short)(SFX_DEATH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
-                                                                               player[c1].bumps++;
-                                                                               player[c1].bumped[c2]++;
-                                                                               s1 = player[c1].bumps % 100;
-                                                                               add_leftovers(0, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
-                                                                               add_leftovers(1, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
-                                                                               add_leftovers(0, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
-                                                                               add_leftovers(1, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+#endif
+
+                               steer_players();
+
+                               dj_mix();
+
+                               for (c3 = 0; c3 < 6; c3++) {
+                                       if (c3 == 0) {
+                                               c1 = 0;
+                                               c2 = 1;
+                                       } else if (c3 == 1) {
+                                               c1 = 0;
+                                               c2 = 2;
+                                       } else if (c3 == 2) {
+                                               c1 = 0;
+                                               c2 = 3;
+                                       } else if (c3 == 3) {
+                                               c1 = 1;
+                                               c2 = 2;
+                                       } else if (c3 == 4) {
+                                               c1 = 1;
+                                               c2 = 3;
+                                       } else if (c3 == 5) {
+                                               c1 = 2;
+                                               c2 = 3;
+                                       }
+                                       if (player[c1].enabled == 1 && player[c2].enabled == 1) {
+                                               if (labs(player[c1].x - player[c2].x) < (12L << 16) && labs(player[c1].y - player[c2].y) < (12L << 16)) {
+                                                       if ((labs(player[c1].y - player[c2].y) >> 16) > 5) {
+                                                               if (player[c1].y < player[c2].y) {
+                                                                       if (player[c1].y_add >= 0) {
+                                                                               if (is_server)
+                                                                                       serverSendKillPacket(c1, c2);
+                                                                       } else {
+                                                                               if (player[c2].y_add < 0)
+                                                                                       player[c2].y_add = 0;
                                                                        }
                                                                } else {
-                                                                       if (player[c2].y_add < 0)
-                                                                               player[c2].y_add = 0;
+                                                                       if (player[c2].y_add >= 0) {
+                                                                               if (is_server)
+                                                                                       serverSendKillPacket(c2, c1);
+                                                                       } else {
+                                                                               if (player[c1].y_add < 0)
+                                                                                       player[c1].y_add = 0;
+                                                                       }
                                                                }
                                                        } else {
-                                                               if (player[c2].y_add >= 0) {
-                                                                       player[c2].y_add = -player[c2].y_add;
-                                                                       if (player[c2].y_add > -262144L)
-                                                                               player[c2].y_add = -262144L;
-                                                                       player[c2].jump_abort = 1;
-                                                                       player[c1].dead_flag = 1;
-                                                                       if (player[c1].anim != 6) {
-                                                                               player[c1].anim = 6;
-                                                                               player[c1].frame = 0;
-                                                                               player[c1].frame_tick = 0;
-                                                                               player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
-                                                                               if (main_info.no_gore == 0) {
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FUR, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 44 + c1 * 8);
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 76);
-                                                                                       for (c4 = 0; c4 < 7; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 77);
-                                                                                       for (c4 = 0; c4 < 8; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 78);
-                                                                                       for (c4 = 0; c4 < 10; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 79);
-                                                                               }
-                                                                               dj_play_sfx(SFX_DEATH, (unsigned short)(SFX_DEATH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
-                                                                               player[c2].bumps++;
-                                                                               player[c2].bumped[c1]++;
-                                                                               s1 = player[c2].bumps % 100;
-                                                                               add_leftovers(0, 360, 34 + c2 * 64, s1 / 10, &number_gobs);
-                                                                               add_leftovers(1, 360, 34 + c2 * 64, s1 / 10, &number_gobs);
-                                                                               add_leftovers(0, 376, 34 + c2 * 64, s1 - (s1 / 10) * 10, &number_gobs);
-                                                                               add_leftovers(1, 376, 34 + c2 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+                                                               if (player[c1].x < player[c2].x) {
+                                                                       if (player[c1].x_add > 0)
+                                                                               player[c1].x = player[c2].x - (12L << 16);
+                                                                       else if (player[c2].x_add < 0)
+                                                                               player[c2].x = player[c1].x + (12L << 16);
+                                                                       else {
+                                                                               player[c1].x -= player[c1].x_add;
+                                                                               player[c2].x -= player[c2].x_add;
                                                                        }
+                                                                       l1 = player[c2].x_add;
+                                                                       player[c2].x_add = player[c1].x_add;
+                                                                       player[c1].x_add = l1;
+                                                                       if (player[c1].x_add > 0)
+                                                                               player[c1].x_add = -player[c1].x_add;
+                                                                       if (player[c2].x_add < 0)
+                                                                               player[c2].x_add = -player[c2].x_add;
                                                                } else {
-                                                                       if (player[c1].y_add < 0)
-                                                                               player[c1].y_add = 0;
-                                                               }
-                                                       }
-                                               } else {
-                                                       if (player[c1].x < player[c2].x) {
-                                                               if (player[c1].x_add > 0)
-                                                                       player[c1].x = player[c2].x - (12L << 16);
-                                                               else if (player[c2].x_add < 0)
-                                                                       player[c2].x = player[c1].x + (12L << 16);
-                                                               else {
-                                                                       player[c1].x -= player[c1].x_add;
-                                                                       player[c2].x -= player[c2].x_add;
-                                                               }
-                                                               l1 = player[c2].x_add;
-                                                               player[c2].x_add = player[c1].x_add;
-                                                               player[c1].x_add = l1;
-                                                               if (player[c1].x_add > 0)
-                                                                       player[c1].x_add = -player[c1].x_add;
-                                                               if (player[c2].x_add < 0)
-                                                                       player[c2].x_add = -player[c2].x_add;
-                                                       } else {
-                                                               if (player[c1].x_add > 0)
-                                                                       player[c2].x = player[c1].x - (12L << 16);
-                                                               else if (player[c2].x_add < 0)
-                                                                       player[c1].x = player[c2].x + (12L << 16);
-                                                               else {
-                                                                       player[c1].x -= player[c1].x_add;
-                                                                       player[c2].x -= player[c2].x_add;
+                                                                       if (player[c1].x_add > 0)
+                                                                               player[c2].x = player[c1].x - (12L << 16);
+                                                                       else if (player[c2].x_add < 0)
+                                                                               player[c1].x = player[c2].x + (12L << 16);
+                                                                       else {
+                                                                               player[c1].x -= player[c1].x_add;
+                                                                               player[c2].x -= player[c2].x_add;
+                                                                       }
+                                                                       l1 = player[c2].x_add;
+                                                                       player[c2].x_add = player[c1].x_add;
+                                                                       player[c1].x_add = l1;
+                                                                       if (player[c1].x_add < 0)
+                                                                               player[c1].x_add = -player[c1].x_add;
+                                                                       if (player[c2].x_add > 0)
+                                                                               player[c2].x_add = -player[c2].x_add;
                                                                }
-                                                               l1 = player[c2].x_add;
-                                                               player[c2].x_add = player[c1].x_add;
-                                                               player[c1].x_add = l1;
-                                                               if (player[c1].x_add < 0)
-                                                                       player[c1].x_add = -player[c1].x_add;
-                                                               if (player[c2].x_add > 0)
-                                                                       player[c2].x_add = -player[c2].x_add;
                                                        }
                                                }
                                        }
                                }
-                       }
 
-                       dj_mix();
+                               dj_mix();
 
-                       main_info.page_info[main_info.draw_page].num_pobs = 0;
-                       for (c1 = 0; c1 < 4; c1++) {
-                               if (player[c1].enabled == 1)
-                                       main_info.page_info[main_info.draw_page].num_pobs++;
-                       }
+                               main_info.page_info[main_info.draw_page].num_pobs = 0;
+                               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
+                                       if (player[c1].enabled == 1)
+                                               main_info.page_info[main_info.draw_page].num_pobs++;
+                               }
 
-                       update_objects();
+                               update_objects();
 
-                       dj_mix();
+                               dj_mix();
 
-                       /* get center of fly swarm */
-                       s1 = s2 = 0;
-                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                               s1 += flies[c1].x;
-                               s2 += flies[c1].y;
-                       }
-                       s1 /= NUM_FLIES;
-                       s2 /= NUM_FLIES;
-
-                       /* get closest player to fly swarm */
-                       dist = 0x7fff;
-                       for (c1 = 0; c1 < 4; c1++) {
-                               if (player[c1].enabled == 1) {
-                                       cur_dist = (int)sqrt((s1 - ((player[c1].x >> 16) + 8)) * (s1 - ((player[c1].x >> 16) + 8)) + (s2 - ((player[c1].y >> 16) + 8)) * (s2 - ((player[c1].y >> 16) + 8)));
-                                       if (cur_dist < dist) {
-                                               closest_player = c1;
-                                               dist = cur_dist;
+                               if (flies_enabled) {
+                                       /* get center of fly swarm */
+                                       s1 = s2 = 0;
+                                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
+                                               s1 += flies[c1].x;
+                                               s2 += flies[c1].y;
                                        }
-                               }
-                       }
-                       /* update fly swarm sound */
-                       s3 = 32 - dist / 3;
-                       if (s3 < 0)
-                               s3 = 0;
-                       dj_set_sfx_channel_volume(4, (char)(s3));
-
-                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                               /* get closest player to fly */
-                               dist = 0x7fff;
-                               for (c2 = 0; c2 < 4; c2++) {
-                                       if (player[c2].enabled == 1) {
-                                               cur_dist = (int)sqrt((flies[c1].x - ((player[c2].x >> 16) + 8)) * (flies[c1].x - ((player[c2].x >> 16) + 8)) + (flies[c1].y - ((player[c2].y >> 16) + 8)) * (flies[c1].y - ((player[c2].y >> 16) + 8)));
-                                               if (cur_dist < dist) {
-                                                       closest_player = c2;
-                                                       dist = cur_dist;
+                                       s1 /= NUM_FLIES;
+                                       s2 /= NUM_FLIES;
+
+                                       if (update_count == 1) {
+                                               /* get closest player to fly swarm */
+                                               dist = 0x7fff;
+                                               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
+                                                       if (player[c1].enabled == 1) {
+                                                               cur_dist = (int)sqrt((s1 - ((player[c1].x >> 16) + 8)) * (s1 - ((player[c1].x >> 16) + 8)) + (s2 - ((player[c1].y >> 16) + 8)) * (s2 - ((player[c1].y >> 16) + 8)));
+                                                               if (cur_dist < dist) {
+                                                                       closest_player = c1;
+                                                                       dist = cur_dist;
+                                                               }
+                                                       }
                                                }
+                                               /* update fly swarm sound */
+                                               s3 = 32 - dist / 3;
+                                               if (s3 < 0)
+                                                       s3 = 0;
+                                               dj_set_sfx_channel_volume(4, (char)(s3));
                                        }
-                               }
-                               flies[c1].old_x = flies[c1].x;
-                               flies[c1].old_y = flies[c1].y;
-                               s3 = 0;
-                               if ((s1 - flies[c1].x) > 30)
-                                       s3 += 1;
-                               else if ((s1 - flies[c1].x) < -30)
-                                       s3 -= 1;
-                               if (dist < 30) {
-                                       if (((player[closest_player].x >> 16) + 8) > flies[c1].x) {
-                                               if (lord_of_the_flies == 0)
-                                                       s3 -= 1;
-                                               else
-                                                       s3 += 1;
-                                       } else {
-                                               if (lord_of_the_flies == 0)
+
+                                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
+                                               /* get closest player to fly */
+                                               dist = 0x7fff;
+                                               for (c2 = 0; c2 < JNB_MAX_PLAYERS; c2++) {
+                                                       if (player[c2].enabled == 1) {
+                                                               cur_dist = (int)sqrt((flies[c1].x - ((player[c2].x >> 16) + 8)) * (flies[c1].x - ((player[c2].x >> 16) + 8)) + (flies[c1].y - ((player[c2].y >> 16) + 8)) * (flies[c1].y - ((player[c2].y >> 16) + 8)));
+                                                               if (cur_dist < dist) {
+                                                                       closest_player = c2;
+                                                                       dist = cur_dist;
+                                                               }
+                                                       }
+                                               }
+                                               flies[c1].old_x = flies[c1].x;
+                                               flies[c1].old_y = flies[c1].y;
+                                               s3 = 0;
+                                               if ((s1 - flies[c1].x) > 30)
                                                        s3 += 1;
-                                               else
+                                               else if ((s1 - flies[c1].x) < -30)
                                                        s3 -= 1;
-                                       }
-                               }
-                               s4 = rnd(3) - 1 + s3;
-                               if ((flies[c1].x + s4) < 16)
-                                       s4 = 0;
-                               if ((flies[c1].x + s4) > 351)
-                                       s4 = 0;
-                               if (ban_map[flies[c1].y >> 4][(flies[c1].x + s4) >> 4] != BAN_VOID)
-                                       s4 = 0;
-                               flies[c1].x += s4;
-                               s3 = 0;
-                               if ((s2 - flies[c1].y) > 30)
-                                       s3 += 1;
-                               else if ((s2 - flies[c1].y) < -30)
-                                       s3 -= 1;
-                               if (dist < 30) {
-                                       if (((player[closest_player].y >> 16) + 8) > flies[c1].y) {
-                                               if (lord_of_the_flies == 0)
-                                                       s3 -= 1;
-                                               else
-                                                       s3 += 1;
-                                       } else {
-                                               if (lord_of_the_flies == 0)
+                                               if (dist < 30) {
+                                                       if (((player[closest_player].x >> 16) + 8) > flies[c1].x) {
+                                                               if (lord_of_the_flies == 0)
+                                                                       s3 -= 1;
+                                                               else
+                                                                       s3 += 1;
+                                                       } else {
+                                                               if (lord_of_the_flies == 0)
+                                                                       s3 += 1;
+                                                               else
+                                                                       s3 -= 1;
+                                                       }
+                                               }
+                                               s4 = rnd(3) - 1 + s3;
+                                               if ((flies[c1].x + s4) < 16)
+                                                       s4 = 0;
+                                               if ((flies[c1].x + s4) > 351)
+                                                       s4 = 0;
+                                               if (ban_map[flies[c1].y >> 4][(flies[c1].x + s4) >> 4] != BAN_VOID)
+                                                       s4 = 0;
+                                               flies[c1].x += s4;
+                                               s3 = 0;
+                                               if ((s2 - flies[c1].y) > 30)
                                                        s3 += 1;
-                                               else
+                                               else if ((s2 - flies[c1].y) < -30)
                                                        s3 -= 1;
+                                               if (dist < 30) {
+                                                       if (((player[closest_player].y >> 16) + 8) > flies[c1].y) {
+                                                               if (lord_of_the_flies == 0)
+                                                                       s3 -= 1;
+                                                               else
+                                                                       s3 += 1;
+                                                       } else {
+                                                               if (lord_of_the_flies == 0)
+                                                                       s3 += 1;
+                                                               else
+                                                                       s3 -= 1;
+                                                       }
+                                               }
+                                               s4 = rnd(3) - 1 + s3;
+                                               if ((flies[c1].y + s4) < 0)
+                                                       s4 = 0;
+                                               if ((flies[c1].y + s4) > 239)
+                                                       s4 = 0;
+                                               if (ban_map[(flies[c1].y + s4) >> 4][flies[c1].x >> 4] != BAN_VOID)
+                                                       s4 = 0;
+                                               flies[c1].y += s4;
                                        }
                                }
-                               s4 = rnd(3) - 1 + s3;
-                               if ((flies[c1].y + s4) < 0)
-                                       s4 = 0;
-                               if ((flies[c1].y + s4) > 239)
-                                       s4 = 0;
-                               if (ban_map[(flies[c1].y + s4) >> 4][flies[c1].x >> 4] != BAN_VOID)
-                                       s4 = 0;
-                               flies[c1].y += s4;
-                       }
 
-                       dj_mix();
+                               dj_mix();
 
-                       s1 = 0;
-                       for (c1 = 0; c1 < 4; c1++) {
-                               if (player[c1].enabled == 1) {
-                                       main_info.page_info[main_info.draw_page].pobs[s1].x = player[c1].x >> 16;
-                                       main_info.page_info[main_info.draw_page].pobs[s1].y = player[c1].y >> 16;
-                                       main_info.page_info[main_info.draw_page].pobs[s1].image = player[c1].image + c1 * 18;
-                                       main_info.page_info[main_info.draw_page].pobs[s1].pob_data = &rabbit_gobs;
-                                       s1++;
+                               s1 = 0;
+                               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
+                                       if (player[c1].enabled == 1) {
+                                               main_info.page_info[main_info.draw_page].pobs[s1].x = player[c1].x >> 16;
+                                               main_info.page_info[main_info.draw_page].pobs[s1].y = player[c1].y >> 16;
+                                               main_info.page_info[main_info.draw_page].pobs[s1].image = player[c1].image + c1 * 18;
+                                               main_info.page_info[main_info.draw_page].pobs[s1].pob_data = &rabbit_gobs;
+                                               s1++;
+                                       }
                                }
-                       }
 
-                       draw_begin();
+                               if (update_count == 1) {
+                                       draw_begin();
 
-                       draw_pobs(main_info.draw_page);
+                                       draw_pobs(main_info.draw_page);
 
-                       dj_mix();
-
-                       draw_flies(main_info.draw_page);
+                                       dj_mix();
 
-                       draw_end();
+                                       if (flies_enabled)
+                                               draw_flies(main_info.draw_page);
 
-                       if (mod_fade_direction == 1) {
-                               if (mod_vol < 30) {
-                                       mod_vol++;
-                                       dj_set_mod_volume((char)mod_vol);
-                               }
-                       } else {
-                               if (mod_vol > 0) {
-                                       mod_vol--;
-                                       dj_set_mod_volume((char)mod_vol);
+                                       draw_end();
                                }
-                       }
 
-                       if (mod_fade_direction == 1) {
-                               if (sfx_vol < 64) {
-                                       sfx_vol++;
-                                       dj_set_sfx_volume((char)sfx_vol);
+                               if (mod_fade_direction == 1) {
+                                       if (mod_vol < 30) {
+                                               mod_vol++;
+                                               dj_set_mod_volume((char)mod_vol);
+                                       }
+                               } else {
+                                       if (mod_vol > 0) {
+                                               mod_vol--;
+                                               dj_set_mod_volume((char)mod_vol);
+                                       }
                                }
-                       } else {
-                               if (sfx_vol > 0) {
-                                       sfx_vol--;
-                                       dj_set_sfx_volume((char)sfx_vol);
+
+                               if (mod_fade_direction == 1) {
+                                       if (sfx_vol < 64) {
+                                               sfx_vol++;
+                                               dj_set_sfx_volume((char)sfx_vol);
+                                       }
+                               } else {
+                                       if (sfx_vol > 0) {
+                                               sfx_vol--;
+                                               dj_set_sfx_volume((char)sfx_vol);
+                                       }
                                }
-                       }
 
-                       fade_flag = 0;
-                       for (c1 = 0; c1 < 768; c1++) {
-                               if (cur_pal[c1] < pal[c1]) {
-                                       cur_pal[c1]++;
-                                       fade_flag = 1;
-                               } else if (cur_pal[c1] > pal[c1]) {
-                                       cur_pal[c1]--;
-                                       fade_flag = 1;
+                               fade_flag = 0;
+                               for (c1 = 0; c1 < 768; c1++) {
+                                       if (cur_pal[c1] < pal[c1]) {
+                                               cur_pal[c1]++;
+                                               fade_flag = 1;
+                                       } else if (cur_pal[c1] > pal[c1]) {
+                                               cur_pal[c1]--;
+                                               fade_flag = 1;
+                                       }
                                }
-                       }
-                       if (fade_flag == 0 && end_loop_flag == 1)
-                               break;
+                               if (fade_flag == 0 && end_loop_flag == 1)
+                                       break;
 
-                       main_info.draw_page ^= 1;
-                       main_info.view_page ^= 1;
+                               if (update_count == 1) {
+                                       main_info.draw_page ^= 1;
+                                       main_info.view_page ^= 1;
 
-                       flippage(main_info.view_page);
+                                       flippage(main_info.view_page);
+       
+                                       wait_vrt(1);
+                               }
 
-                       wait_vrt(1);
+                               if (fade_flag == 1)
+                                       setpalette(0, 256, cur_pal);
 
-                       if (fade_flag == 1)
-                               setpalette(0, 256, cur_pal);
+                               if (update_count == 1) {
+                                       draw_begin();
 
-                       draw_begin();
+                                       if (flies_enabled)
+                                               redraw_flies_background(main_info.draw_page);
 
-                       redraw_flies_background(main_info.draw_page);
+                                       redraw_pob_backgrounds(main_info.draw_page);
 
-                       redraw_pob_backgrounds(main_info.draw_page);
+                                       draw_leftovers(main_info.draw_page);
 
-                       draw_leftovers(main_info.draw_page);
+                                       draw_end();
+                               }
 
-                       draw_end();
+                               update_count--;
+                       }
 
-                       intr_sysupdate();
+#ifdef USE_NET
+                       if (is_net) {
+                               if ( (player[client_player_num].dead_flag == 0) &&
+                                       (
+                                        (player[client_player_num].action_left) ||
+                                        (player[client_player_num].action_right) ||
+                                        (player[client_player_num].action_up) ||
+                                        (player[client_player_num].jump_ready == 0)
+                                       )
+                                  ) {
+                                       tellServerNewPosition();
+                               }
+                       }
+#endif
+
+                       update_count = intr_sysupdate();
 
+#ifdef USE_NET
+                       if (is_net) {
+                               if ((server_said_bye) || ((fade_flag == 0) && (end_loop_flag == 1)))
+                                       break;
+                       } else
+#endif
+                       if ((fade_flag == 0) && (end_loop_flag == 1))
+                               break;
                }
 
+#ifdef USE_NET
+               if (is_net) {
+                       if (is_server) {
+                               serverTellEveryoneGoodbye();
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                       } else {
+                               if (!server_said_bye) {
+                                       tellServerGoodbye();
+                               }
+
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                       }
+               }
+#endif
+               
                main_info.view_page = 0;
                main_info.draw_page = 1;
 
@@ -665,10 +1486,9 @@ int main(int argc, char *argv[])
 
                deinit_level();
 
-               memset(mask_pic, 0, 102400L);
+               memset(mask_pic, 0, JNB_WIDTH*JNB_HEIGHT);
                register_mask(mask_pic);
 
-               recalculate_gob(&font_gobs, pal);
                register_background(NULL, NULL);
 
                draw_begin();
@@ -682,8 +1502,8 @@ int main(int argc, char *argv[])
                put_text(main_info.view_page, 40, 140, "FIZZ", 2);
                put_text(main_info.view_page, 40, 170, "MIJJI", 2);
 
-               for (c1 = 0; c1 < 4; c1++) {
-                       for (c2 = 0; c2 < 4; c2++) {
+               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
+                       for (c2 = 0; c2 < JNB_MAX_PLAYERS; c2++) {
                                if (c2 != c1) {
                                        sprintf(str1, "%d", player[c1].bumped[c2]);
                                        put_text(main_info.view_page, 100 + c2 * 60, 80 + c1 * 30, str1, 2);
@@ -704,11 +1524,17 @@ int main(int argc, char *argv[])
                        strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
                        return 1;
                }
-               if (read_pcx(handle, background_pic, 102400L, pal) != 0) {
+               if (read_pcx(handle, background_pic, JNB_WIDTH*JNB_HEIGHT, pal) != 0) {
                        strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
                        return 1;
                }
-               fclose(handle);
+
+               /* fix dark font */
+               for (c1 = 0; c1 < 16; c1++) {
+                       pal[(240 + c1) * 3 + 0] = c1 << 2;
+                       pal[(240 + c1) * 3 + 1] = c1 << 2;
+                       pal[(240 + c1) * 3 + 2] = c1 << 2;
+               }
 
                memset(cur_pal, 0, 768);
 
@@ -759,6 +1585,8 @@ int main(int argc, char *argv[])
                dj_set_nosound(1);
                dj_stop_mod();
 
+               if (is_net)
+                       break; /* don't go back to menu if in net game. */
        }
 
        deinit_program();
@@ -774,7 +1602,7 @@ void steer_players(void)
 
        update_player_actions();
 
-       for (c1 = 0; c1 < 4; c1++) {
+       for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
 
                if (player[c1].enabled == 1) {
 
@@ -1179,14 +2007,13 @@ void position_player(int player_num)
                        if (ban_map[s2][s1] == BAN_VOID && (ban_map[s2 + 1][s1] == BAN_SOLID || ban_map[s2 + 1][s1] == BAN_ICE))
                                break;
                }
-               for (c1 = 0; c1 < 4; c1++) {
+               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
                        if (c1 != player_num && player[c1].enabled == 1) {
                                if (abs((s1 << 4) - (player[c1].x >> 16)) < 32 && abs((s2 << 4) - (player[c1].y >> 16)) < 32)
                                        break;
                        }
                }
-               if (c1 == 4) {
-                       player[player_num].dead_flag = 0;
+               if (c1 == JNB_MAX_PLAYERS) {
                        player[player_num].x = (long) s1 << 20;
                        player[player_num].y = (long) s2 << 20;
                        player[player_num].x_add = player[player_num].y_add = 0;
@@ -1197,6 +2024,15 @@ void position_player(int player_num)
                        player[player_num].frame = 0;
                        player[player_num].frame_tick = 0;
                        player[player_num].image = player_anims[player[player_num].anim].frame[player[player_num].frame].image;
+
+                       if (is_server) {
+#ifdef USE_NET
+                               if (is_net)
+                                       serverSendAlive(player_num);
+#endif
+                               player[player_num].dead_flag = 0;
+                       }
+
                        break;
                }
        }
@@ -1601,12 +2437,11 @@ void draw_pobs(int page)
 
        for (c1 = main_info.page_info[page].num_pobs - 1; c1 >= 0; c1--) {
                main_info.page_info[page].pobs[c1].back_buf_ofs = back_buf_ofs;
-               get_block(page, main_info.page_info[page].pobs[c1].x - pob_hs_x(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), main_info.page_info[page].pobs[c1].y - pob_hs_y(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), &main_info.pob_backbuf[page][back_buf_ofs]);
-#ifdef SCALE_UP2
-               back_buf_ofs += pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * 4 * JNB_BYTESPP;
-#else
-               back_buf_ofs += pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data);
-#endif
+               get_block(page, main_info.page_info[page].pobs[c1].x - pob_hs_x(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), main_info.page_info[page].pobs[c1].y - pob_hs_y(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), (unsigned char *)main_info.pob_backbuf[page] + back_buf_ofs);
+               if (scale_up)
+                       back_buf_ofs += pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * 4 * bytes_per_pixel;
+               else
+                       back_buf_ofs += pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data) * bytes_per_pixel;
                put_pob(page, main_info.page_info[page].pobs[c1].x, main_info.page_info[page].pobs[c1].y, main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data, 1, mask_pic);
        }
 
@@ -1619,7 +2454,9 @@ void redraw_flies_background(int page)
 
        for (c2 = NUM_FLIES - 1; c2 >= 0; c2--) {
                if (flies[c2].back_defined[page] == 1)
-                       set_pixel(page, flies[c2].old_x, flies[c2].old_y, flies[c2].back[page]);
+                       set_pixel(page, flies[c2].old_draw_x, flies[c2].old_draw_y, flies[c2].back[page]);
+               flies[c2].old_draw_x = flies[c2].x;
+               flies[c2].old_draw_y = flies[c2].y;
        }
 }
 
@@ -1629,7 +2466,7 @@ void redraw_pob_backgrounds(int page)
        int c1;
 
        for (c1 = 0; c1 < main_info.page_info[page].num_pobs; c1++)
-               put_block(page, main_info.page_info[page].pobs[c1].x - pob_hs_x(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), main_info.page_info[page].pobs[c1].y - pob_hs_y(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), &main_info.pob_backbuf[page][main_info.page_info[page].pobs[c1].back_buf_ofs]);
+               put_block(page, main_info.page_info[page].pobs[c1].x - pob_hs_x(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), main_info.page_info[page].pobs[c1].y - pob_hs_y(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), (unsigned char *)main_info.pob_backbuf[page] + main_info.page_info[page].pobs[c1].back_buf_ofs);
 
 }
 
@@ -1665,7 +2502,7 @@ void draw_leftovers(int page)
 
 int init_level(int level, char *pal)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
        int s1, s2;
 
@@ -1673,29 +2510,29 @@ int init_level(int level, char *pal)
                strcpy(main_info.error_str, "Error loading 'level.pcx', aborting...\n");
                return 1;
        }
-       if (read_pcx(handle, background_pic, 102400L, pal) != 0) {
+       if (read_pcx(handle, background_pic, JNB_WIDTH*JNB_HEIGHT, pal) != 0) {
                strcpy(main_info.error_str, "Error loading 'level.pcx', aborting...\n");
                return 1;
        }
-       fclose(handle);
+       if (flip)
+               flip_pixels(background_pic);
        if ((handle = dat_open("mask.pcx", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'mask.pcx', aborting...\n");
                return 1;
        }
-       if (read_pcx(handle, mask_pic, 102400L, 0) != 0) {
+       if (read_pcx(handle, mask_pic, JNB_WIDTH*JNB_HEIGHT, 0) != 0) {
                strcpy(main_info.error_str, "Error loading 'mask.pcx', aborting...\n");
                return 1;
        }
-       fclose(handle);
+       if (flip)
+               flip_pixels(mask_pic);
        register_mask(mask_pic);
 
-       for (c1 = 0; c1 < 4; c1++) {
+       for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
                if (player[c1].enabled == 1) {
                        player[c1].bumps = 0;
-                       player[c1].bumped[0] = 0;
-                       player[c1].bumped[1] = 0;
-                       player[c1].bumped[2] = 0;
-                       player[c1].bumped[3] = 0;
+                       for (c2 = 0; c2 < JNB_MAX_PLAYERS; c2++)
+                               player[c1].bumped[c2] = 0;
                        position_player(c1);
                }
        }
@@ -1755,9 +2592,93 @@ void deinit_level(void)
 }
 
 
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+unsigned char *datafile_buffer = NULL;
+
+static void preread_datafile(const char *fname)
+{
+    int fd = 0;
+    int len;
+
+#ifdef ZLIB_SUPPORT
+    char *gzfilename = alloca(strlen(fname) + 4);
+    int bufsize = 0;
+    int bufpos = 0;
+    gzFile gzf;
+
+    strcpy(gzfilename, fname);
+    strcat(gzfilename, ".gz");
+
+    gzf = gzopen(gzfilename, "rb");
+    if (gzf != NULL) {
+        unsigned char *ptr;
+        do {
+            int br;
+            if (bufpos >= bufsize) {
+                bufsize += 1024 * 1024;
+                datafile_buffer = (unsigned char *) realloc(datafile_buffer, bufsize);
+                if (datafile_buffer == NULL) {
+                    perror("realloc()");
+                    exit(42);
+                }
+            }
+
+            br = gzread(gzf, datafile_buffer + bufpos, bufsize - bufpos);
+            if (br == -1) {
+                fprintf(stderr, "gzread failed.\n");
+                exit(42);
+            }
+
+            bufpos += br;
+        } while (!gzeof(gzf));
+
+        /* try to shrink buffer... */
+        ptr = (unsigned char *) realloc(datafile_buffer, bufpos);
+        if (ptr != NULL)
+            datafile_buffer = ptr;
+
+        gzclose(gzf);
+        return;
+    }
+
+    /* drop through and try for an uncompressed datafile... */
+#endif
+
+    fd = open(fname, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        fprintf(stderr, "can't open %s:", fname);
+       perror("");
+        exit(42);
+    }
+
+    len = filelength(fd);
+    datafile_buffer = (unsigned char *) malloc(len);
+    if (datafile_buffer == NULL) {
+        perror("malloc()");
+        close(fd);
+        exit(42);
+    }
+
+    if (read(fd, datafile_buffer, len) != len) {
+        perror("read()");
+        close(fd);
+        exit(42);
+    }
+
+    close(fd);
+}
+
+
 int init_program(int argc, char *argv[], char *pal)
 {
-       FILE *handle = (FILE *) NULL;
+       char *netarg = NULL;
+       unsigned char *handle = (unsigned char *) NULL;
        int c1 = 0, c2 = 0;
        int load_flag = 0;
        int force2, force3;
@@ -1772,6 +2693,10 @@ int init_program(int argc, char *argv[], char *pal)
                1, 0, 8, 5, 0, 0, 0, 0, 0, 0
        };
 
+#ifdef USE_NET
+       memset(&net_info, 0, sizeof(net_info));
+#endif
+
 #ifdef DOS
        if (__djgpp_nearptr_enable() == 0)
                return 1;
@@ -1784,7 +2709,7 @@ int init_program(int argc, char *argv[], char *pal)
 
        memset(&main_info, 0, sizeof(main_info));
 
-       strcpy(datfile_name, "data/jumpbump.dat");
+       strcpy(datfile_name, DATA_PATH);
 
        force2 = force3 = 0;
 
@@ -1792,8 +2717,12 @@ int init_program(int argc, char *argv[], char *pal)
                for (c1 = 1; c1 < argc; c1++) {
                        if (stricmp(argv[c1], "-nosound") == 0)
                                main_info.no_sound = 1;
+                       else if (stricmp(argv[c1], "-musicnosound") == 0)
+                               main_info.music_no_sound = 1;
                        else if (stricmp(argv[c1], "-nogore") == 0)
                                main_info.no_gore = 1;
+                       else if (stricmp(argv[c1], "-noflies") == 0)
+                               flies_enabled = 0;
                        else if (stricmp(argv[c1], "-nojoy") == 0)
                                main_info.joy_enabled = 0;
                        else if (stricmp(argv[c1], "-fireworks") == 0)
@@ -1802,13 +2731,38 @@ int init_program(int argc, char *argv[], char *pal)
                        else if (stricmp(argv[c1], "-fullscreen") == 0)
                                fs_toggle();
 #endif
+                       else if (stricmp(argv[c1], "-scaleup") == 0)
+                               set_scaling(1);
+                       else if (stricmp(argv[c1], "-mirror") == 0)
+                               flip = 1;
                        else if (stricmp(argv[c1], "-dat") == 0) {
                                if (c1 < (argc - 1)) {
-                                       if ((handle = fopen(argv[c1 + 1], "rb")) != NULL) {
-                                               fclose(handle);
+                                       FILE *f;
+
+                                       if ((f = fopen(argv[c1 + 1], "rb")) != NULL) {
+                                               fclose(f);
                                                strcpy(datfile_name, argv[c1 + 1]);
                                        }
                                }
+                       } else if (stricmp(argv[c1], "-player") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       if (client_player_num < 0)
+                                               client_player_num = atoi(argv[c1 + 1]);
+                               }
+#ifdef USE_NET
+                       } else if (stricmp(argv[c1], "-server") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       is_server = 1;
+                                       is_net = 1;
+                                       netarg = argv[c1 + 1];
+                               }
+                       } else if (stricmp(argv[c1], "-connect") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       is_server = 0;
+                                       is_net = 1;
+                                       netarg = argv[c1 + 1];
+                               }
+#endif
                        } else if (stricmp(argv[c1], "-mouse") == 0) {
                                if (c1 < (argc - 1)) {
                                        if (stricmp(argv[c1 + 1], "2") == 0)
@@ -1817,9 +2771,50 @@ int init_program(int argc, char *argv[], char *pal)
                                                force3 = 1;
                                }
                        }
+                       else if (strstr(argv[1],"-v")) {
+                               printf("jumpnbump %s compiled %s at %s with",JNB_VERSION,__DATE__,__TIME__);
+#ifndef USE_NET
+                               printf("out");
+#endif
+                               printf(" network support.\n");
+                               return 1;
+                       }
+                       else if (strstr(argv[1],"-h")) {
+                               printf("Usage: jumpnbump [OPTION]...\n");
+                               printf("\n");
+                               printf("  -h                       this help\n");
+                               printf("  -v                       print version\n");
+                               printf("  -dat level.dat           play a different level\n");
+#ifdef USE_NET
+                               printf("  -server playercount      start as server waiting for players\n");
+                               printf("  -connect host            connect to server\n");
+#endif
+                               printf("  -player num              set main player to num (0-3). Needed for networking\n");
+                               printf("  -fireworks               screensaver mode\n");
+                               printf("  -fullscreen              run in fullscreen mode\n");
+                               printf("  -nosound                 play without sound\n");
+                               printf("  -nogore                  play without blood\n");
+                               printf("  -noflies                 disable flies\n");
+                               printf("  -mirror                  play with mirrored level\n");
+                               printf("  -scaleup                 play with doubled resolution (800x512)\n");
+                               printf("  -musicnosound            play with music but without sound\n");
+                               printf("\n");
+                               return 1;
+                       }
                }
        }
 
+       preread_datafile(datfile_name);
+
+       if (is_net) {
+               if (client_player_num < 0)
+                       client_player_num = 0;
+               player[client_player_num].enabled = 1;
+       }
+
+       main_info.pob_backbuf[0] = malloc(screen_pitch*screen_height*bytes_per_pixel);
+       main_info.pob_backbuf[1] = malloc(screen_pitch*screen_height*bytes_per_pixel);
+
        for (c1 = 0; c1 < 7; c1++) {
                player_anims[c1].num_frames = player_anim_data[c1 * 10];
                player_anims[c1].restart_frame = player_anim_data[c1 * 10 + 1];
@@ -1833,11 +2828,10 @@ int init_program(int argc, char *argv[], char *pal)
                strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
                return 1;
        }
-       if (read_pcx(handle, background_pic, 102400L, pal) != 0) {
+       if (read_pcx(handle, background_pic, JNB_WIDTH*JNB_HEIGHT, pal) != 0) {
                strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
                return 1;
        }
-       fclose(handle);
 
        if ((handle = dat_open("rabbit.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'rabbit.gob', aborting...\n");
@@ -1845,10 +2839,8 @@ int init_program(int argc, char *argv[], char *pal)
        }
        if (register_gob(handle, &rabbit_gobs, dat_filelen("rabbit.gob", datfile_name))) {
                /* error */
-               fclose(handle);
                return 1;
        }
-       fclose(handle);
 
        if ((handle = dat_open("objects.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'objects.gob', aborting...\n");
@@ -1856,10 +2848,8 @@ int init_program(int argc, char *argv[], char *pal)
        }
        if (register_gob(handle, &object_gobs, dat_filelen("objects.gob", datfile_name))) {
                /* error */
-               fclose(handle);
                return 1;
        }
-       fclose(handle);
 
        if ((handle = dat_open("font.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'font.gob', aborting...\n");
@@ -1867,10 +2857,8 @@ int init_program(int argc, char *argv[], char *pal)
        }
        if (register_gob(handle, &font_gobs, dat_filelen("font.gob", datfile_name))) {
                /* error */
-               fclose(handle);
                return 1;
        }
-       fclose(handle);
 
        if ((handle = dat_open("numbers.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'numbers.gob', aborting...\n");
@@ -1878,14 +2866,11 @@ int init_program(int argc, char *argv[], char *pal)
        }
        if (register_gob(handle, &number_gobs, dat_filelen("numbers.gob", datfile_name))) {
                /* error */
-               fclose(handle);
                return 1;
        }
-       fclose(handle);
 
        if (read_level() != 0) {
                strcpy(main_info.error_str, "Error loading 'levelmap.txt', aborting...\n");
-               fclose(handle);
                return 1;
        }
 
@@ -1910,7 +2895,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'jump.mod', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("bump.mod", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'bump.mod', aborting...\n");
@@ -1920,7 +2904,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'bump.mod', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("scores.mod", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'scores.mod', aborting...\n");
@@ -1930,7 +2913,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'scores.mod', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("jump.smp", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'jump.smp', aborting...\n");
@@ -1940,7 +2922,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'jump.smp', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("death.smp", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'death.smp', aborting...\n");
@@ -1950,7 +2931,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'death.smp', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("spring.smp", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'spring.smp', aborting...\n");
@@ -1960,7 +2940,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'spring.smp', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("splash.smp", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'splash.smp', aborting...\n");
@@ -1970,7 +2949,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'splash.smp', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                if ((handle = dat_open("fly.smp", datfile_name, "rb")) == 0) {
                        strcpy(main_info.error_str, "Error loading 'fly.smp', aborting...\n");
@@ -1980,7 +2958,6 @@ int init_program(int argc, char *argv[], char *pal)
                        strcpy(main_info.error_str, "Error loading 'fly.smp', aborting...\n");
                        return 1;
                }
-               fclose(handle);
 
                dj_get_sfx_settings(SFX_FLY, &fly);
                fly.priority = 10;
@@ -1991,17 +2968,26 @@ int init_program(int argc, char *argv[], char *pal)
                dj_set_sfx_settings(SFX_FLY, &fly);
        }
 
-       if ((background_pic = malloc(102400)) == NULL)
+       if ((background_pic = malloc(JNB_WIDTH*JNB_HEIGHT)) == NULL)
                return 1;
-       if ((mask_pic = malloc(102400)) == NULL)
+       if ((mask_pic = malloc(JNB_WIDTH*JNB_HEIGHT)) == NULL)
                return 1;
-       memset(mask_pic, 0, 102400);
+       memset(mask_pic, 0, JNB_WIDTH*JNB_HEIGHT);
        register_mask(mask_pic);
 
+       /* fix dark font */
+       for (c1 = 0; c1 < 16; c1++) {
+               pal[(240 + c1) * 3 + 0] = c1 << 2;
+               pal[(240 + c1) * 3 + 1] = c1 << 2;
+               pal[(240 + c1) * 3 + 2] = c1 << 2;
+       }
+
        setpalette(0, 256, pal);
 
        init_inputs();
 
+       recalculate_gob(&font_gobs, pal);
+
        if (main_info.joy_enabled == 1 && main_info.fireworks == 0) {
                load_flag = 0;
                put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
@@ -2013,7 +2999,6 @@ int init_program(int argc, char *argv[], char *pal)
                if (calib_joy(0) != 0)
                        load_flag = 1;
                else {
-                       recalculate_gob(&font_gobs, pal);
                        register_background(NULL, NULL);
 
                        main_info.view_page = 1;
@@ -2030,7 +3015,6 @@ int init_program(int argc, char *argv[], char *pal)
                        if (calib_joy(1) != 0)
                                load_flag = 1;
                        else {
-                               recalculate_gob(&font_gobs, pal);
                                register_background(NULL, NULL);
                                flippage(0);
 
@@ -2062,21 +3046,29 @@ int init_program(int argc, char *argv[], char *pal)
                                strcpy(main_info.error_str, "Error loading 'calib.dat', aborting...\n");
                                return 1;
                        }
-                       joy.calib_data.x1 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       joy.calib_data.x2 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       joy.calib_data.x3 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       joy.calib_data.y1 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       joy.calib_data.y2 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       joy.calib_data.y3 = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-                       fclose(handle);
+                       joy.calib_data.x1 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
+                       joy.calib_data.x2 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
+                       joy.calib_data.x3 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
+                       joy.calib_data.y1 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
+                       joy.calib_data.y2 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
+                       joy.calib_data.y3 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
                }
        }
 
+#ifdef USE_NET
+       if (is_net) {
+               if (is_server) {
+                       init_server(netarg);
+               } else {
+                       connect_to_server(netarg);
+               }
+       }
+#endif
+
        return 0;
 
 }
 
-
 void deinit_program(void)
 {
 #ifdef DOS
@@ -2105,6 +3097,9 @@ void deinit_program(void)
 
        if (main_info.error_str[0] != 0) {
                printf(main_info.error_str);
+#ifdef _MSC_VER
+               MessageBox(0, main_info.error_str, "Jump'n'Bump", 0);
+#endif
                exit(1);
        } else
                exit(0);
@@ -2114,13 +3109,19 @@ void deinit_program(void)
 
 unsigned short rnd(unsigned short max)
 {
-       return (rand() % max);
+#if (RAND_MAX < 0x7fff)
+#error "rand returns too small values"
+#elif (RAND_MAX == 0x7fff)
+       return (unsigned short)((rand()*2) % (int)max);
+#else
+       return (unsigned short)(rand() % (int)max);
+#endif
 }
 
 
 int read_level(void)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
        int chr;
 
@@ -2132,119 +3133,104 @@ int read_level(void)
        for (c1 = 0; c1 < 16; c1++) {
                for (c2 = 0; c2 < 22; c2++) {
                        while (1) {
-                               chr = fgetc(handle);
-                               if (chr == EOF) {
-                                       fclose(handle);
-                                       return 1;
-                               }
+                               chr = (int) *(handle++);
                                if (chr >= '0' && chr <= '4')
                                        break;
                        }
-                       ban_map[c1][c2] = chr - '0';
+                       if (flip)
+                               ban_map[c1][21-c2] = chr - '0';
+                       else
+                               ban_map[c1][c2] = chr - '0';
                }
        }
 
        for (c2 = 0; c2 < 22; c2++)
                ban_map[16][c2] = BAN_SOLID;
 
-       fclose(handle);
        return 0;
 
 }
 
 
-FILE *dat_open(char *file_name, char *dat_name, char *mode)
+unsigned char *dat_open(char *file_name, char *dat_name, char *mode)
 {
-       FILE *handle;
        int num;
        int c1;
        char name[21];
        int ofs;
+       unsigned char *ptr;
 
-       handle = fopen(dat_name, mode);
-       if (!handle)
+       if (datafile_buffer == NULL)
                return 0;
 
        memset(name, 0, sizeof(name));
 
-       num = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
-       
+       num = ( (datafile_buffer[0] <<  0) +
+               (datafile_buffer[1] <<  8) +
+               (datafile_buffer[2] << 16) +
+               (datafile_buffer[3] << 24) );
+
+       ptr = datafile_buffer + 4;
+
        for (c1 = 0; c1 < num; c1++) {
-               if (!fread(name, 1, 12, handle)) {
-                       fclose(handle);
-                       return 0;
-               }
+
+               memcpy(name, ptr, 12);
+               ptr += 12;
+
                if (strnicmp(name, file_name, strlen(file_name)) == 0) {
-                       ofs = fgetc(handle);
-                       ofs += (fgetc(handle) << 8);
-                       ofs += (fgetc(handle) << 16);
-                       ofs += (fgetc(handle) << 24);
-                       fseek(handle, ofs, SEEK_SET);
-                       return handle;
+                       ofs = ( (ptr[0] <<  0) +
+                               (ptr[1] <<  8) +
+                               (ptr[2] << 16) +
+                               (ptr[3] << 24) );
+
+                       return (datafile_buffer + ofs);
                }
-               fseek(handle, 8, SEEK_CUR);
+               ptr += 8;
        }
 
-       fclose(handle);
-
        return 0;
 }
 
 
 int dat_filelen(char *file_name, char *dat_name)
 {
-       FILE *handle;
+       unsigned char *ptr;
        int num;
        int c1;
        char name[21];
        int len;
 
-       handle = fopen(dat_name, "rb");
-       if (!handle)
-               return 0;
-
        memset(name, 0, sizeof(name));
        
-       num = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
+       num = ( (datafile_buffer[0] <<  0) +
+               (datafile_buffer[1] <<  8) +
+               (datafile_buffer[2] << 16) +
+               (datafile_buffer[3] << 24) );
+
+       ptr = datafile_buffer + 4;
 
        for (c1 = 0; c1 < num; c1++) {
-               if (!fread(name, 1, 12, handle)) {
-                       fclose(handle);
-                       return 0;
-               }
+
+               memcpy(name, ptr, 12);
+               ptr += 12;
+
                if (strnicmp(name, file_name, strlen(file_name)) == 0) {
-                       fseek(handle, 4, SEEK_CUR);
-                       len = fgetc(handle);
-                       len += (fgetc(handle) << 8);
-                       len += (fgetc(handle) << 16);
-                       len += (fgetc(handle) << 24);
 
-                       fclose(handle);
+                       ptr += 4;
+                       len = ( (ptr[0] <<  0) +
+                               (ptr[1] <<  8) +
+                               (ptr[2] << 16) +
+                               (ptr[3] << 24) );
+
                        return len;
                }
-               fseek(handle, 8, SEEK_CUR);
+               ptr += 8;
        }
 
-       fclose(handle);
        return 0;
 }
 
 
-#ifndef _MSC_VER
-int filelength(int handle)
-{
-       struct stat buf;
-
-       if (fstat(handle, &buf) == -1) {
-               perror("filelength");
-               exit(EXIT_FAILURE);
-       }
-
-       return buf.st_size;
-}
-#endif
-
-
 void write_calib_data(void)
 {
        FILE *handle;