First try on network implementation.
[crow/jumpnbump.git] / main.c
diff --git a/main.c b/main.c
index 17a0f3a..8315aa6 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,31 +1,98 @@
-#include "globals.h"
-
+/*
+ * 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
+ */
 
-__dpmi_regs regs;
-
-char *object_gobs;
-char *number_gobs;
-
-char pal[768];
-char cur_pal[768];
-
-char 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,
-       1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1,
-       1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-       1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
-       1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 1,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1,
-       1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1,
-       1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
-       1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
-       2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 1, 3, 3, 3, 1, 1, 1,
-       2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+#include "globals.h"
+#include <fcntl.h>
+
+#define USE_NET
+
+#ifdef USE_NET
+#ifdef _MSC_VER
+#include <winsock2.h>
+#define EAGAIN TRY_AGAIN
+#define net_error WSAGetLastError()
+#else // _MSC_VER
+#include <unistd.h>
+#include <netdb.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define net_error errno
+#endif
+#endif // USE_NET
+
+#ifndef M_PI
+#define M_PI           3.14159265358979323846
+#endif
+
+gob_t rabbit_gobs = { 0 };
+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},
+       {1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1},
+       {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+       {1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
+       {1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 1},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1},
+       {1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1},
+       {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
+       {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
+       {2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 1, 3, 3, 3, 1, 1, 1},
+       {2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
+       {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
 };
 
 struct {
@@ -36,12 +103,129 @@ struct {
                int ticks;
        } frame[10];
 } object_anims[8] = {
-6, 0, 0, 3, 1, 3, 2, 3, 3, 3, 4, 3, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 6, 2, 7, 2, 8, 2, 9, 2, 10, 2, 11, 2, 12, 2, 13, 2, 14, 2, 0, 0, 5, 0, 15, 3, 16, 3, 16, 3, 17, 3, 18, 3, 19, 3, 0, 0, 0, 0, 0, 0, 0, 0, 10, 0, 20, 2, 21, 2, 22, 2, 23, 2, 24, 2, 25, 2, 24, 2, 23, 2, 22, 2, 21, 2, 10, 0, 26, 2, 27, 2, 28, 2, 29, 2, 30, 2, 31, 2, 30, 2, 29, 2, 28, 2, 27, 2, 10, 0, 32, 2, 33, 2, 34, 2, 35, 2, 36, 2, 37, 2, 36, 2, 35, 2, 34, 2, 33, 2, 10, 0, 38, 2, 39, 2, 40, 2, 41, 2, 42, 2, 43, 2, 42, 2, 41, 2, 40, 2, 39, 2, 4, 0, 76, 4, 77, 4, 78, 4, 79, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+       {
+               6, 0, {
+                       {
+                       0, 3}, {
+                       1, 3}, {
+                       2, 3}, {
+                       3, 3}, {
+                       4, 3}, {
+                       5, 3}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}
+               }
+       }, {
+               9, 0, {
+                       {
+                       6, 2}, {
+                       7, 2}, {
+                       8, 2}, {
+                       9, 2}, {
+                       10, 2}, {
+                       11, 2}, {
+                       12, 2}, {
+                       13, 2}, {
+                       14, 2}, {
+                       0, 0}
+               }
+       }, {
+               5, 0, {
+                       {
+                       15, 3}, {
+                       16, 3}, {
+                       16, 3}, {
+                       17, 3}, {
+                       18, 3}, {
+                       19, 3}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}
+               }
+       }, {
+               10, 0, {
+                       {
+                       20, 2}, {
+                       21, 2}, {
+                       22, 2}, {
+                       23, 2}, {
+                       24, 2}, {
+                       25, 2}, {
+                       24, 2}, {
+                       23, 2}, {
+                       22, 2}, {
+                       21, 2}
+               }
+       }, {
+               10, 0, {
+                       {
+                       26, 2}, {
+                       27, 2}, {
+                       28, 2}, {
+                       29, 2}, {
+                       30, 2}, {
+                       31, 2}, {
+                       30, 2}, {
+                       29, 2}, {
+                       28, 2}, {
+                       27, 2}
+               }
+       }, {
+               10, 0, {
+                       {
+                       32, 2}, {
+                       33, 2}, {
+                       34, 2}, {
+                       35, 2}, {
+                       36, 2}, {
+                       37, 2}, {
+                       36, 2}, {
+                       35, 2}, {
+                       34, 2}, {
+                       33, 2}
+               }
+       }, {
+               10, 0, {
+                       {
+                       38, 2}, {
+                       39, 2}, {
+                       40, 2}, {
+                       41, 2}, {
+                       42, 2}, {
+                       43, 2}, {
+                       42, 2}, {
+                       41, 2}, {
+                       40, 2}, {
+                       39, 2}
+               }
+       }, {
+               4, 0, {
+                       {
+                       76, 4}, {
+                       77, 4}, {
+                       78, 4}, {
+                       79, 4}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}, {
+                       0, 0}
+               }
+       }
+};
+
+int flies_enabled = 1;
 
 struct {
        int x, y;
        int old_x, old_y;
-       char back[2], back_defined[2];
+       int old_draw_x, old_draw_y;
+       int back[2];
+       int back_defined[2];
 } flies[NUM_FLIES];
 
 struct {
@@ -50,28 +234,842 @@ struct {
                struct {
                        int x, y;
                        int image;
-                       char *pob_data;
+                       gob_t *pob_data;
                } pobs[NUM_LEFTOVERS];
        } page[2];
 } leftovers;
 
-char pogostick, bunnies_in_space, jetpack, lord_of_the_flies, blood_is_thicker_than_water;
+int pogostick, bunnies_in_space, jetpack, lord_of_the_flies, blood_is_thicker_than_water;
 
 
-char main(int argc, char *argv[])
+#ifndef _MSC_VER
+int filelength(int handle)
 {
-       FILE *handle;
-       int c1, c2, c3, c4;
-       int l1, l2;
+       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;
+int sock = -1;
+
+#ifdef USE_NET
+typedef struct
+{
+    int sock;
+    /*struct timeval last_timestamp;*/
+    struct sockaddr *addr;
+    int addrlen;
+} 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((unsigned long) pkt->arg);
+       *((unsigned long *) (buf +  8)) = SDLNet_Read32((unsigned long) pkt->arg2);
+       *((unsigned long *) (buf + 12)) = SDLNet_Read32((unsigned long) pkt->arg3);
+       *((unsigned long *) (buf + 16)) = SDLNet_Read32((unsigned long) 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(int s, NetPacket *pkt)
+{
+#ifdef USE_NET
+    int bytes_left = NETPKTBUFSIZE;
+    int bw;
+    char buf[NETPKTBUFSIZE];
+    char *ptr = buf;
+
+    packetToBuf(pkt, buf);
+    while (bytes_left > 0) {
+        bw = send(s, ptr, bytes_left, 0);  /* this might block. For now, we'll deal. */
+        if (bw < 0) {
+            if (h_errno != EAGAIN) {
+               fprintf(stderr, "SERVER: send(): %i", net_error);
+                //perror("SERVER: write()");
+                close(s);
+                exit(42);
+            }
+        } else if (bw == 0) {
+            SDL_Delay(1);
+        } else {
+            bytes_left -= bw;
+            ptr += bw;
+        }
+    }
+#endif
+}
+
+
+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(int s, NetPacket *pkt)
+{
+#ifdef USE_NET
+    char buf[NETPKTBUFSIZE];
+    struct timeval tv;
+    fd_set rfds;
+    int rc;
+    int retval = 0;
+
+    FD_ZERO(&rfds);
+    FD_SET(s, &rfds);
+    tv.tv_sec = tv.tv_usec = 0;    /* don't block. */
+    if (select(s + 1, &rfds, NULL, NULL, &tv)) {
+        rc = recv(s, buf, NETPKTBUFSIZE, 0);
+        if (rc <= 0) {  /* closed connection? */
+            retval = -1;
+        } else if (rc != NETPKTBUFSIZE) { // !!! FIXME: buffer these?
+            printf("NETWORK: -BUG- ... dropped a packet! (had %d of %d bytes).\b",
+                    rc, NETPKTBUFSIZE);
+        } else {
+            bufToPacket(buf, pkt);
+            retval = 1;
+        }
+    }
+
+    return(retval);
+#endif
+
+    return 0;
+}
+
+
+int serverRecvPacket(NetPacket *pkt)
+{
+       int rc;
+       int i;
+
+       assert(is_server);
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               int s = net_info[i].sock;
+
+               if ((i == client_player_num) || (!player[i].enabled))
+                       continue;
+
+               rc = grabPacket(s, pkt);
+               if (rc < 0) {
+                       NetPacket pkt;
+
+                       player[i].enabled = 0;
+                       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, &pkt)) == 0) {
+                       SDL_Delay(100);  /* nap and then try again. */
+               }
+
+               if (rc < 0) {
+                       printf("CLIENT: Lost connection.\n");
+                       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
+               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, &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) {
+                               close(sock);
+                               sock = -1;
+                               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
+       sendPacketToAll(&pkt);
+#endif
+}
+
+
+#ifdef USE_NET
+void update_players_from_clients(void)
+{
+#ifdef USE_NET
+    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;
+            close(net_info[playerid].sock);
+        } else if (pkt.cmd == NETCMD_POSITION) {
+            pkt.arg = playerid;  /* just in case. */
+            processPositionPacket(&pkt);
+            for (i = 0; i < (sizeof (net_info) / sizeof (net_info[0])); 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);
+        }
+    }
+#endif
+}
+
+
+void init_server(const char *netarg)
+{
+#ifdef USE_NET
+    NetPacket pkt;
+    char ipstr[128];
+    struct hostent *hent;
+    struct sockaddr_in addr;
+    struct in_addr inaddr;
+    int i;
+    int wait_for_clients = ((netarg == NULL) ? 0 : atoi(netarg));
+#ifdef _MSC_VER
+WORD wVersionRequested;
+WSADATA wsaData;
+int err;
+wVersionRequested = MAKEWORD( 2, 2 );
+err = WSAStartup( wVersionRequested, &wsaData );
+if ( err != 0 ) {
+    /* Tell the user that we could not find a usable */
+    /* WinSock DLL.                                  */
+        fprintf(stderr, "SERVER: WSAStartup failed!");
+    return;
+}
+#endif
+
+    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);
+    }
+
+    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock < 0) {
+        fprintf(stderr, "SERVER: socket(): %i", net_error);
+       //perror("SERVER: socket()");
+        exit(42);
+    }
+
+    memset(&addr, '\0', sizeof (addr));
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(JNB_INETPORT);
+    addr.sin_addr.s_addr = INADDR_ANY;
+    if (bind(sock, (struct sockaddr *) &addr,
+            sizeof (addr)) == -1) {
+               fprintf(stderr, "SERVER: bind(): %i", net_error);
+        //perror("SERVER: bind()");
+        close(sock);
+        exit(42);
+    }
+
+    if (listen(sock, wait_for_clients) == -1) {
+               fprintf(stderr, "SERVER: listen(): %i", net_error);
+        //perror("SERVER: listen()");
+        close(sock);
+        exit(42);
+    }
+
+    player[client_player_num].enabled = 1;
+
+    gethostname(ipstr, sizeof (ipstr));
+    hent = gethostbyname(ipstr);
+    if (hent != NULL) {
+        memcpy(&inaddr, hent->h_addr, hent->h_length);
+        strncpy(ipstr, inet_ntoa(inaddr), sizeof (ipstr));
+    }
+
+    printf("SERVER: we are [%s].\n", ipstr);
+
+    addr.sin_addr.s_addr = inaddr.s_addr;
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(JNB_INETPORT);
+    net_info[client_player_num].addr = malloc(sizeof (addr));
+    memcpy(net_info[client_player_num].addr, &addr, sizeof (addr));
+    net_info[client_player_num].addrlen = sizeof (addr);
+    /*gettimeofday(&net_info[client_player_num].last_timestamp, NULL);*/
+
+    printf("SERVER: waiting for (%d) clients...\n", wait_for_clients);
+
+    while (wait_for_clients > 0)
+    {
+        char buf[NETPKTBUFSIZE];
+        struct sockaddr_in from;
+        int fromlen = sizeof (from);
+        int negatory = 1;
+        int br;
+        int s;
+
+        s = accept(sock, (struct sockaddr *) &from, &fromlen);
+        if (s < 0)
+        {
+               fprintf(stderr, "SERVER: accept(): %i", net_error);
+            //perror("SERVER: accept()");
+            close(sock);
+            exit(42);
+        } /* if */
+
+        br = recv(s, buf, NETPKTBUFSIZE, 0);
+        if (br < 0) {
+               fprintf(stderr, "SERVER: recv(): %i", net_error);
+            close(s);
+            close(sock);
+            exit(42);
+        }
+
+        strncpy(ipstr, inet_ntoa(from.sin_addr), sizeof (ipstr));
+        printf("SERVER: Got data from [%s].\n", ipstr);
+
+        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 > (sizeof (player) / sizeof (player[0]))) {
+            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);
+            close(s);
+        } else {
+            player[pkt.arg].enabled = 1;
+            net_info[pkt.arg].sock = s;
+            net_info[pkt.arg].addr = malloc(fromlen);
+            memcpy(net_info[pkt.arg].addr, &from, fromlen);
+            net_info[pkt.arg].addrlen = fromlen;
+            /*memcpy(&net_info[pkt.arg].last_timestamp, &pkt.timestamp, sizeof (pkt.timestamp));*/
+            wait_for_clients--;
+            printf("SERVER: Granting connection. (%d) to go.\n", wait_for_clients);
+            pkt.cmd = NETCMD_ACK;
+            sendPacket(pkt.arg, &pkt);
+        }
+    }
+
+    close(sock);  /* done with the listen socket. */
+    sock = -1;
+
+    printf("SERVER: Got all our connections. Greenlighting clients...\n");
+
+    pkt.cmd = NETCMD_GREENLIGHT;
+    pkt.arg = 0;
+    for (i = 0; i < (sizeof (net_info) / sizeof (net_info[0])); i++) {
+        if (player[i].enabled) {
+            pkt.arg |= (1 << i);
+        }
+    }
+    sendPacketToAll(&pkt);
+#endif
+}
+
+
+void connect_to_server(char *netarg)
+{
+#ifdef USE_NET
+    NetPacket pkt;
+    char buf[NETPKTBUFSIZE];
+    char ipstr[128];
+    struct hostent *hent;
+    struct sockaddr_in addr;
+    struct in_addr inaddr;
+    int addrlen;
+    int br;
+#ifdef _MSC_VER
+WORD wVersionRequested;
+WSADATA wsaData;
+int err;
+wVersionRequested = MAKEWORD( 2, 2 );
+err = WSAStartup( wVersionRequested, &wsaData );
+if ( err != 0 ) {
+    /* Tell the user that we could not find a usable */
+    /* WinSock DLL.                                  */
+        fprintf(stderr, "SERVER: WSAStartup failed!");
+    return;
+}
+#endif
+
+    if (netarg == NULL) {
+        printf("CLIENT: Need to specify host to connect to.\n");
+        exit(42);
+    }
+
+    player[client_player_num].enabled = 1;
+    gethostname(ipstr, sizeof (ipstr));
+    hent = gethostbyname(ipstr);
+    if (hent != NULL) {
+        net_info[client_player_num].addr = malloc(hent->h_length);
+        memcpy(&net_info[client_player_num].addr, &hent->h_addr, hent->h_length);
+        net_info[client_player_num].addrlen = hent->h_length;
+        memcpy(&inaddr, hent->h_addr, hent->h_length);
+        strncpy(ipstr, inet_ntoa(inaddr), sizeof (ipstr));
+    }
+    printf("CLIENT: we are [%s].\n", ipstr);
+
+    /*gettimeofday(&net_info[client_player_num].last_timestamp, NULL);*/
+
+    hent = gethostbyname(netarg);
+    if (hent == NULL) {
+               fprintf(stderr, "CLIENT: couldn't find host: %i", net_error);
+        //perror("CLIENT: couldn't find host");
+        exit(42);
+    }
+
+    sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (sock < 0) {
+               fprintf(stderr, "CLIENT: socket(): %i", net_error);
+        //perror("CLIENT: socket()");
+        exit(42);
+    }
+
+    memcpy(&inaddr, hent->h_addr, hent->h_length);
+    printf("CLIENT: connecting to [%s]...\n", inet_ntoa(inaddr));
+
+    addr.sin_family = AF_INET;
+    addr.sin_port = htons(JNB_INETPORT);
+    memcpy(&addr.sin_addr.s_addr, hent->h_addr, hent->h_length);
+    if (connect(sock, (struct sockaddr *) &addr, sizeof (addr)) == -1) {
+               fprintf(stderr, "CLIENT: connect(): %i", net_error);
+        //perror("CLIENT: connect()");
+        exit(42);
+    }
+
+    printf("CLIENT: Got socket. Sending HELLO packet...\n");
+    pkt.cmd = NETCMD_HELLO;
+    pkt.arg = client_player_num;
+    sendPacketToSock(sock, &pkt);
+
+    printf("CLIENT: Waiting for ACK from server...\n");
+    
+    addrlen = sizeof (addr);
+    br = recv(sock, buf, NETPKTBUFSIZE, 0);
+    if (br < 0) {
+               fprintf(stderr, "CLIENT: recv(): %i", net_error);
+        //perror("CLIENT: recv()");
+        close(sock);
+        exit(42);
+    }
+
+    if (br != NETPKTBUFSIZE) {
+        printf("CLIENT: Bogus packet size (%d of %d). FIXME.\n",
+                br, NETPKTBUFSIZE);
+        close(sock);
+        exit(42);
+    }
+
+    bufToPacket(buf, &pkt);
+
+    if (pkt.cmd == NETCMD_NACK) {
+        printf("CLIENT: Server forbid us from playing.\n");
+        close(sock);
+        exit(42);
+    }
+
+    if (pkt.cmd != NETCMD_ACK) {
+        printf("CLIENT: Unexpected packet (cmd=0x%lX).\n", pkt.cmd);
+        close(sock);
+        exit(42);
+    }
+
+    printf("CLIENT: Server accepted our connection.\n");
+
+    wait_for_greenlight();
+#endif
+}
+#endif // USE_NET
+
+
+static 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[])
+{
+       unsigned char *handle;
+       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
+       int l1;
        int s1, s2, s3, s4;
-       int closest_player, dist, cur_dist;
-       char end_loop_flag, fade_flag;
-       char mod_vol, sfx_vol, mod_fade_direction;
-       sfx_data fly;
-       char *ptr1;
+       int closest_player = 0, dist, cur_dist = 0;
+       int end_loop_flag = 0, fade_flag;
+       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) != 0)
+       if (init_program(argc, argv, pal) != 0)
                deinit_program();
 
        if (main_info.fireworks == 1) {
@@ -81,51 +1079,56 @@ char 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)
+               if (key_pressed(1) == 1) {
                        break;
-
-               if (init_level(0) != 0) {
+               }
+               if (init_level(0, pal) != 0) {
                        deinit_level();
                        deinit_program();
                }
 
-               outportb(0x3c8, 0);
-               for (c1 = 0; c1 < 768; c1++)
-                       outportb(0x3c9, cur_pal[c1]);
+               memset(cur_pal, 0, 768);
+               setpalette(0, 256, cur_pal);
 
-               for (c1 = 0; c1 < 4; c1++) {
-                       outportw(0x3c4, ((1 << c1) << 8) + 0x02);
-                       l1 = c1;
-                       for (l2 = 0; l2 < 25600; l2++) {
-                               *(char *) (0xa0000 + l2 + __djgpp_conventional_base) = *(char *) (background_pic + l1);
-                               *(char *) (0xa0000 + 32768 + l2 + __djgpp_conventional_base) = *(char *) (background_pic + l1);
-                               l1 += 4;
-                       }
-               }
+               recalculate_gob(&rabbit_gobs, pal);
+               //recalculate_gob(&font_gobs, pal);
+               recalculate_gob(&object_gobs, pal);
+               recalculate_gob(&number_gobs, pal);
 
-               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] == 0)
-                                       break;
+               flippage(1);
+               register_background(background_pic, pal);
+               flippage(0);
+
+               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;
                mod_fade_direction = 1;
                dj_ready_mod(MOD_GAME);
-               dj_set_mod_volume(mod_vol);
-               dj_set_sfx_volume(mod_vol);
+               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;
@@ -135,437 +1138,445 @@ char 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 (key_pressed(1) == 1) {
+#ifdef USE_NET
+                                       if (is_server) {
+                                               serverTellEveryoneGoodbye();
+                                       } else {
+                                               tellServerGoodbye();
+                                       }
+#endif
+                                       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;
+                               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;
+                               }
+
+#ifdef USE_NET
+                               if (is_server) {
+                                       update_players_from_clients();
                                } 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 (!update_players_from_server()) {
+                                               break;  /* got a BYE packet */
+                                       }
                                }
-                               last_keys[0] = 0;
-                       }
+#endif
 
-                       steer_players();
+                               steer_players();
 
-                       dj_mix();
+                               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) {
-                                                                       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, 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);
+                               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, 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();
 
-                       s1 = s2 = 0;
-                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                               s1 += flies[c1].x;
-                               s2 += flies[c1].y;
-                       }
-                       s1 /= NUM_FLIES;
-                       s2 /= NUM_FLIES;
-
-                       dist = 0x7fff;
-                       for (c1 = 0; c1 < 4; c1++) {
-                               if (player[c1].enabled == 1) {
-                                       cur_dist = 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;
                                        }
-                               }
-                       }
-                       s3 = 32 - dist / 3;
-                       if (s3 < 0)
-                               s3 = 0;
-                       dj_set_sfx_channel_volume(4, s3);
-
-                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                               dist = 0x7fff;
-                               for (c2 = 0; c2 < 4; c2++) {
-                                       if (player[c2].enabled == 1) {
-                                               cur_dist = 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
-                                                       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] != 0)
-                                       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)
+                                               else if ((s1 - flies[c1].x) < -30)
                                                        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] != 0)
-                                       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_pobs(main_info.draw_page);
+                               if (update_count == 1) {
+                                       draw_begin();
 
-                       dj_mix();
+                                       draw_pobs(main_info.draw_page);
 
-                       ptr1 = (char *) (0xa0000 + ((long) main_info.draw_page << 15) - __djgpp_base_address);
-                       for (c1 = 0; c1 < 4; c1++) {
-                               outportw(0x3ce, (c1 << 8) + 0x04);
-                               outportw(0x3c4, ((1 << c1) << 8) + 0x02);
-                               for (c2 = 0; c2 < NUM_FLIES; c2++) {
-                                       if ((flies[c2].x & 3) == c1) {
-                                               flies[c2].back[main_info.draw_page] = *(char *) (ptr1 + flies[c2].y * 100 + (flies[c2].x >> 2));
-                                               flies[c2].back_defined[main_info.draw_page] = 1;
-                                               if (mask_pic[flies[c2].y * 400 + flies[c2].x] == 0)
-                                                       *(char *) (ptr1 + flies[c2].y * 100 + (flies[c2].x >> 2)) = 0;
-                                       }
-                               }
-                       }
+                                       dj_mix();
 
-                       if (mod_fade_direction == 1) {
-                               if (mod_vol < 30) {
-                                       mod_vol++;
-                                       dj_set_mod_volume(mod_vol);
+                                       if (flies_enabled)
+                                               draw_flies(main_info.draw_page);
+
+                                       draw_end();
                                }
-                       } else {
-                               if (mod_vol > 0) {
-                                       mod_vol--;
-                                       dj_set_mod_volume(mod_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);
+                                       }
                                }
-                       }
 
-                       if (mod_fade_direction == 1) {
-                               if (sfx_vol < 64) {
-                                       sfx_vol++;
-                                       dj_set_sfx_volume(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);
+                                       }
                                }
-                       } else {
-                               if (sfx_vol > 0) {
-                                       sfx_vol--;
-                                       dj_set_sfx_volume(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;
+                                       }
                                }
-                       }
+                               if (fade_flag == 0 && end_loop_flag == 1)
+                                       break;
 
-                       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 (update_count == 1) {
+                                       main_info.draw_page ^= 1;
+                                       main_info.view_page ^= 1;
+
+                                       flippage(main_info.view_page);
+       
+                                       wait_vrt(1);
                                }
-                       }
-                       if (fade_flag == 0 && end_loop_flag == 1)
-                               break;
 
-                       main_info.draw_page ^= 1;
-                       main_info.view_page ^= 1;
+                               if (fade_flag == 1)
+                                       setpalette(0, 256, cur_pal);
 
-                       outportw(0x3d4, (main_info.view_page << 23) + 0x0d);
-                       outportw(0x3d4, ((main_info.view_page << 15) & 0xff00) + 0x0c);
+                               if (update_count == 1) {
+                                       draw_begin();
 
-                       while ((inportb(0x3da) & 8) == 0)
-                               dj_mix();
-                       while ((inportb(0x3da) & 8) == 8)
-                               dj_mix();
+                                       if (flies_enabled)
+                                               redraw_flies_background(main_info.draw_page);
+
+                                       redraw_pob_backgrounds(main_info.draw_page);
+
+                                       draw_leftovers(main_info.draw_page);
+
+                                       draw_end();
+                               }
 
-                       if (fade_flag == 1) {
-                               outportb(0x3c8, 0);
-                               for (c1 = 0; c1 < 768; c1++)
-                                       outportb(0x3c9, cur_pal[c1]);
+                               update_count--;
                        }
 
-                       ptr1 = (char *) (0xa0000 + ((long) main_info.draw_page << 15) - __djgpp_base_address);
-                       for (c1 = 0; c1 < 4; c1++) {
-                               outportw(0x3c4, ((1 << c1) << 8) + 0x02);
-                               for (c2 = NUM_FLIES - 1; c2 >= 0; c2--) {
-                                       if ((flies[c2].old_x & 3) == c1 && flies[c2].back_defined[main_info.draw_page] == 1)
-                                               *(char *) (ptr1 + flies[c2].old_y * 100 + (flies[c2].old_x >> 2)) = flies[c2].back[main_info.draw_page];
-                               }
+#ifdef USE_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();
 
-                       redraw_pob_backgrounds(main_info.draw_page);
+#ifdef USE_NET
+                       if ((server_said_bye) || ((fade_flag == 0) && (end_loop_flag == 1)))
+                               break;
+#else
+                       if ((fade_flag == 0) && (end_loop_flag == 1))
+                               break;
+#endif
+               }
 
-                       draw_leftovers(main_info.draw_page);
+#ifdef USE_NET
+               if (is_server) {
+                       serverTellEveryoneGoodbye();
+                       close(sock);
+                       sock = -1;
+               } else {
+                       if (!server_said_bye) {
+                               tellServerGoodbye();
+                       }
 
+                       close(sock);
+                       sock = -1;
                }
+#endif
+               
+               main_info.view_page = 0;
+               main_info.draw_page = 1;
 
                dj_stop_sfx_channel(4);
 
                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();
 
-               outportw(0x3c4, 0x0f02);
-               memset((char *) (0xa0000 + (long) (main_info.view_page << 15) + __djgpp_conventional_base), 0, 32768);
                put_text(main_info.view_page, 100, 50, "DOTT", 2);
                put_text(main_info.view_page, 160, 50, "JIFFY", 2);
                put_text(main_info.view_page, 220, 50, "FIZZ", 2);
@@ -574,115 +1585,123 @@ char main(int argc, char *argv[])
                put_text(main_info.view_page, 40, 110, "JIFFY", 2);
                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) {
-                                       itoa(player[c1].bumped[c2], str1, 10);
+                                       sprintf(str1, "%d", player[c1].bumped[c2]);
                                        put_text(main_info.view_page, 100 + c2 * 60, 80 + c1 * 30, str1, 2);
                                } else
                                        put_text(main_info.view_page, 100 + c2 * 60, 80 + c1 * 30, "-", 2);
                        }
-                       itoa(player[c1].bumps, str1, 10);
+                       sprintf(str1, "%d", player[c1].bumps);
                        put_text(main_info.view_page, 350, 80 + c1 * 30, str1, 2);
                }
+
                put_text(main_info.view_page, 200, 230, "Press ESC to continue", 2);
 
+               draw_end();
+
+               flippage(main_info.view_page);
+
                if ((handle = dat_open("menu.pcx", datfile_name, "rb")) == 0) {
                        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);
+
+               for (c1 = 0; c1 < 16; c1++) { // fix dark font
+                       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);
 
-               outportb(0x3c8, 0);
-               for (c1 = 0; c1 < 768; c1++)
-                       outportb(0x3c9, cur_pal[c1]);
+               setpalette(0, 256, cur_pal);
 
                mod_vol = 0;
                dj_ready_mod(MOD_SCORES);
-               dj_set_mod_volume(mod_vol);
+               dj_set_mod_volume((char)mod_vol);
                dj_start_mod();
                dj_set_nosound(0);
 
                while (key_pressed(1) == 0) {
                        if (mod_vol < 35)
                                mod_vol++;
-                       dj_set_mod_volume(mod_vol);
+                       dj_set_mod_volume((char)mod_vol);
                        for (c1 = 0; c1 < 768; c1++) {
                                if (cur_pal[c1] < pal[c1])
                                        cur_pal[c1]++;
                        }
                        dj_mix();
-                       wait_vrt();
-                       outportb(0x3c8, 0);
-                       for (c1 = 0; c1 < 768; c1++)
-                               outportb(0x3c9, cur_pal[c1]);
+                       intr_sysupdate();
+                       wait_vrt(0);
+                       setpalette(0, 256, cur_pal);
+                       flippage(main_info.view_page);
                }
-               while (key_pressed(1) == 1)
+               while (key_pressed(1) == 1) {
                        dj_mix();
+                       intr_sysupdate();
+               }
 
                memset(pal, 0, 768);
 
                while (mod_vol > 0) {
                        mod_vol--;
-                       dj_set_mod_volume(mod_vol);
+                       dj_set_mod_volume((char)mod_vol);
                        for (c1 = 0; c1 < 768; c1++) {
                                if (cur_pal[c1] > pal[c1])
                                        cur_pal[c1]--;
                        }
                        dj_mix();
-                       wait_vrt();
-                       outportb(0x3c8, 0);
-                       for (c1 = 0; c1 < 768; c1++)
-                               outportb(0x3c9, cur_pal[c1]);
+                       wait_vrt(0);
+                       setpalette(0, 256, cur_pal);
+                       flippage(main_info.view_page);
                }
 
-               outportb(0x3c8, 0);
-               for (c1 = 0; c1 < 768; c1++)
-                       outportb(0x3c9, 0);
+               fillpalette(0, 0, 0);
 
                dj_set_nosound(1);
                dj_stop_mod();
 
+               if (is_net)
+                       break; /* don't go back to menu if in net game. */
        }
 
        deinit_program();
 
+       return 0;
 }
 
 
 void steer_players(void)
 {
        int c1, c2;
-       int s1, s2;
+       int s1 = 0, s2 = 0;
 
-       if (main_info.mouse_enabled == 1)
-               read_mouse();
-       if (main_info.joy_enabled == 1)
-               read_joy();
+       update_player_actions();
 
-       for (c1 = 0; c1 < 4; c1++) {
+       for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
 
                if (player[c1].enabled == 1) {
 
                        if (player[c1].dead_flag == 0) {
 
-                               if ((c1 == 0 && ((key_pressed(KEY_PL1_LEFT) == 1 && key_pressed(KEY_PL1_RIGHT) == 1))) || (c1 == 1 && ((key_pressed(KEY_PL2_LEFT) == 1 && key_pressed(KEY_PL2_RIGHT) == 1))) || (c1 == 2 && ((joy.x < -512 && joy.x > 512))) || (c1 == 3 && ((mouse.but1 == 1 && mouse.but2 == 1)))) {
+                               if (player[c1].action_left && player[c1].action_right) {
                                        if (player[c1].direction == 0) {
-                                               if ((c1 == 0 && key_pressed(KEY_PL1_RIGHT) == 1) || (c1 == 1 && key_pressed(KEY_PL2_RIGHT) == 1) || (c1 == 2 && joy.x > 512) || (c1 == 3 && mouse.but2 == 1)) {
+                                               if (player[c1].action_right) {
                                                        s1 = (player[c1].x >> 16);
                                                        s2 = (player[c1].y >> 16);
-                                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 3) {
+                                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_ICE) {
                                                                if (player[c1].x_add < 0)
                                                                        player[c1].x_add += 1024;
                                                                else
                                                                        player[c1].x_add += 768;
-                                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != 1 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 3) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == 3 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != 1)) {
+                                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != BAN_SOLID && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_ICE) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_ICE && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != BAN_SOLID)) {
                                                                if (player[c1].x_add > 0)
                                                                        player[c1].x_add += 1024;
                                                                else
@@ -690,7 +1709,7 @@ void steer_players(void)
                                                        } else {
                                                                if (player[c1].x_add < 0) {
                                                                        player[c1].x_add += 16384;
-                                                                       if (player[c1].x_add < 98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1)
+                                                                       if (player[c1].x_add < 98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID)
                                                                                add_object(OBJ_SMOKE, (player[c1].x >> 16) + 2 + rnd(9), (player[c1].y >> 16) + 13 + rnd(5), 0, -16384 - rnd(8192), OBJ_ANIM_SMOKE, 0);
                                                                } else
                                                                        player[c1].x_add += 12288;
@@ -706,15 +1725,15 @@ void steer_players(void)
                                                        }
                                                }
                                        } else {
-                                               if ((c1 == 0 && key_pressed(KEY_PL1_LEFT) == 1) || (c1 == 1 && key_pressed(KEY_PL2_LEFT) == 1) || (c1 == 2 && joy.x < -512) || (c1 == 3 && mouse.but1 == 1)) {
+                                               if (player[c1].action_left) {
                                                        s1 = (player[c1].x >> 16);
                                                        s2 = (player[c1].y >> 16);
-                                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 3) {
+                                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_ICE) {
                                                                if (player[c1].x_add > 0)
                                                                        player[c1].x_add -= 1024;
                                                                else
                                                                        player[c1].x_add -= 768;
-                                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != 1 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 3) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == 3 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != 1)) {
+                                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != BAN_SOLID && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_ICE) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_ICE && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != BAN_SOLID)) {
                                                                if (player[c1].x_add > 0)
                                                                        player[c1].x_add -= 1024;
                                                                else
@@ -722,7 +1741,7 @@ void steer_players(void)
                                                        } else {
                                                                if (player[c1].x_add > 0) {
                                                                        player[c1].x_add -= 16384;
-                                                                       if (player[c1].x_add > -98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1)
+                                                                       if (player[c1].x_add > -98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID)
                                                                                add_object(OBJ_SMOKE, (player[c1].x >> 16) + 2 + rnd(9), (player[c1].y >> 16) + 13 + rnd(5), 0, -16384 - rnd(8192), OBJ_ANIM_SMOKE, 0);
                                                                } else
                                                                        player[c1].x_add -= 12288;
@@ -738,15 +1757,15 @@ void steer_players(void)
                                                        }
                                                }
                                        }
-                               } else if ((c1 == 0 && key_pressed(KEY_PL1_LEFT) == 1) || (c1 == 1 && key_pressed(KEY_PL2_LEFT) == 1) || (c1 == 2 && joy.x < -512) || (c1 == 3 && mouse.but1 == 1)) {
+                               } else if (player[c1].action_left) {
                                        s1 = (player[c1].x >> 16);
                                        s2 = (player[c1].y >> 16);
-                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 3) {
+                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_ICE) {
                                                if (player[c1].x_add > 0)
                                                        player[c1].x_add -= 1024;
                                                else
                                                        player[c1].x_add -= 768;
-                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != 1 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 3) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == 3 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != 1)) {
+                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != BAN_SOLID && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_ICE) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_ICE && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != BAN_SOLID)) {
                                                if (player[c1].x_add > 0)
                                                        player[c1].x_add -= 1024;
                                                else
@@ -754,7 +1773,7 @@ void steer_players(void)
                                        } else {
                                                if (player[c1].x_add > 0) {
                                                        player[c1].x_add -= 16384;
-                                                       if (player[c1].x_add > -98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1)
+                                                       if (player[c1].x_add > -98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID)
                                                                add_object(OBJ_SMOKE, (player[c1].x >> 16) + 2 + rnd(9), (player[c1].y >> 16) + 13 + rnd(5), 0, -16384 - rnd(8192), OBJ_ANIM_SMOKE, 0);
                                                } else
                                                        player[c1].x_add -= 12288;
@@ -768,15 +1787,15 @@ void steer_players(void)
                                                player[c1].frame_tick = 0;
                                                player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
                                        }
-                               } else if ((c1 == 0 && key_pressed(KEY_PL1_RIGHT) == 1) || (c1 == 1 && key_pressed(KEY_PL2_RIGHT) == 1) || (c1 == 2 && joy.x > 512) || (c1 == 3 && mouse.but2 == 1)) {
+                               } else if (player[c1].action_right) {
                                        s1 = (player[c1].x >> 16);
                                        s2 = (player[c1].y >> 16);
-                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 3) {
+                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_ICE) {
                                                if (player[c1].x_add < 0)
                                                        player[c1].x_add += 1024;
                                                else
                                                        player[c1].x_add += 768;
-                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != 1 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 3) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == 3 && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != 1)) {
+                                       } else if ((ban_map[(s2 + 16) >> 4][s1 >> 4] != BAN_SOLID && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_ICE) || (ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_ICE && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != BAN_SOLID)) {
                                                if (player[c1].x_add > 0)
                                                        player[c1].x_add += 1024;
                                                else
@@ -784,7 +1803,7 @@ void steer_players(void)
                                        } else {
                                                if (player[c1].x_add < 0) {
                                                        player[c1].x_add += 16384;
-                                                       if (player[c1].x_add < 98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1)
+                                                       if (player[c1].x_add < 98304L && player[c1].in_water == 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID)
                                                                add_object(OBJ_SMOKE, (player[c1].x >> 16) + 2 + rnd(9), (player[c1].y >> 16) + 13 + rnd(5), 0, -16384 - rnd(8192), OBJ_ANIM_SMOKE, 0);
                                                } else
                                                        player[c1].x_add += 12288;
@@ -798,10 +1817,10 @@ void steer_players(void)
                                                player[c1].frame_tick = 0;
                                                player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
                                        }
-                               } else if ((c1 == 0 && ((key_pressed(KEY_PL1_LEFT) == 0 && key_pressed(KEY_PL1_RIGHT) == 0))) || (c1 == 1 && ((key_pressed(KEY_PL2_LEFT) == 0 && key_pressed(KEY_PL2_RIGHT) == 0))) || (c1 == 2 && ((joy.x >= -512 && joy.x <= 512))) || (c1 == 3 && ((mouse.but1 == 0 && mouse.but2 == 0)))) {
+                               } else if ((!player[c1].action_left) && (!player[c1].action_right)) {
                                        s1 = (player[c1].x >> 16);
                                        s2 = (player[c1].y >> 16);
-                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1 || ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 4 || (((ban_map[(s2 + 16) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 16) >> 4][s1 >> 4] == 4) && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != 3) || (ban_map[(s2 + 16) >> 4][s1 >> 4] != 3 && (ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 4)))) {
+                                       if (ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID || ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SPRING || (((ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_SPRING) && ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] != BAN_ICE) || (ban_map[(s2 + 16) >> 4][s1 >> 4] != BAN_ICE && (ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_SPRING)))) {
                                                if (player[c1].x_add < 0) {
                                                        player[c1].x_add += 16384;
                                                        if (player[c1].x_add > 0)
@@ -811,7 +1830,7 @@ void steer_players(void)
                                                        if (player[c1].x_add < 0)
                                                                player[c1].x_add = 0;
                                                }
-                                               if (player[c1].x_add != 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == 1)
+                                               if (player[c1].x_add != 0 && ban_map[(s2 + 16) >> 4][(s1 + 8) >> 4] == BAN_SOLID)
                                                        add_object(OBJ_SMOKE, (player[c1].x >> 16) + 2 + rnd(9), (player[c1].y >> 16) + 13 + rnd(5), 0, -16384 - rnd(8192), OBJ_ANIM_SMOKE, 0);
                                        }
                                        if (player[c1].anim == 1) {
@@ -822,12 +1841,12 @@ void steer_players(void)
                                        }
                                }
                                if (jetpack == 0) {
-                                       if (pogostick == 1 || (player[c1].jump_ready == 1 && ((c1 == 0 && key_pressed(KEY_PL1_JUMP) == 1) || (c1 == 1 && key_pressed(KEY_PL2_JUMP) == 1) || (c1 == 2 && joy.but1 == 1) || (c1 == 3 && ((main_info.num_mouse_buttons == 2 && mouse.but1 == 1 && mouse.but2 == 1) || (main_info.num_mouse_buttons == 3 && mouse.but3 == 1)))))) {
+                                       if (pogostick == 1 || (player[c1].jump_ready == 1 && player[c1].action_up)) {
                                                s1 = (player[c1].x >> 16);
                                                s2 = (player[c1].y >> 16);
                                                if (s2 < -16)
                                                        s2 = -16;
-                                               if (ban_map[(s2 + 16) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 16) >> 4][s1 >> 4] == 3 || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == 3) {
+                                               if (ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 16) >> 4][s1 >> 4] == BAN_ICE || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 16) >> 4][(s1 + 15) >> 4] == BAN_ICE) {
                                                        player[c1].y_add = -280000L;
                                                        player[c1].anim = 2;
                                                        player[c1].frame = 0;
@@ -836,11 +1855,11 @@ void steer_players(void)
                                                        player[c1].jump_ready = 0;
                                                        player[c1].jump_abort = 1;
                                                        if (pogostick == 0)
-                                                               dj_play_sfx(SFX_JUMP, SFX_JUMP_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_JUMP, (unsigned short)(SFX_JUMP_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                                        else
-                                                               dj_play_sfx(SFX_SPRING, SFX_SPRING_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_SPRING, (unsigned short)(SFX_SPRING_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                                }
-                                               if ((ban_map[(s2 + 7) >> 4][s1 >> 4] == 0 || ban_map[(s2 + 7) >> 4][(s1 + 15) >> 4] == 0) && (ban_map[(s2 + 8) >> 4][s1 >> 4] == 2 || ban_map[(s2 + 8) >> 4][(s1 + 15) >> 4] == 2)) {
+                                               if ((ban_map[(s2 + 7) >> 4][s1 >> 4] == BAN_VOID || ban_map[(s2 + 7) >> 4][(s1 + 15) >> 4] == BAN_VOID) && (ban_map[(s2 + 8) >> 4][s1 >> 4] == BAN_WATER || ban_map[(s2 + 8) >> 4][(s1 + 15) >> 4] == BAN_WATER)) {
                                                        player[c1].y_add = -196608L;
                                                        player[c1].in_water = 0;
                                                        player[c1].anim = 2;
@@ -850,12 +1869,12 @@ void steer_players(void)
                                                        player[c1].jump_ready = 0;
                                                        player[c1].jump_abort = 1;
                                                        if (pogostick == 0)
-                                                               dj_play_sfx(SFX_JUMP, SFX_JUMP_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_JUMP, (unsigned short)(SFX_JUMP_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                                        else
-                                                               dj_play_sfx(SFX_SPRING, SFX_SPRING_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_SPRING, (unsigned short)(SFX_SPRING_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                                }
                                        }
-                                       if (pogostick == 0 && ((c1 == 0 && key_pressed(KEY_PL1_JUMP) == 0) || (c1 == 1 && key_pressed(KEY_PL2_JUMP) == 0) || (c1 == 2 && joy.but1 == 0) || (c1 == 3 && ((main_info.num_mouse_buttons == 2 && (mouse.but1 == 0 && mouse.but2 == 0)) || (main_info.num_mouse_buttons == 3 && mouse.but3 == 0))))) {
+                                       if (pogostick == 0 && (!player[c1].action_up)) {
                                                player[c1].jump_ready = 1;
                                                if (player[c1].in_water == 0 && player[c1].y_add < 0 && player[c1].jump_abort == 1) {
                                                        if (bunnies_in_space == 0)
@@ -866,16 +1885,13 @@ void steer_players(void)
                                                                player[c1].y_add = 0;
                                                }
                                        }
-                                       if (c1 == 3 && main_info.num_mouse_buttons == 2 && (mouse.but1 == 0 || mouse.but2 == 0))
-                                               player[c1].jump_ready = 1;
-
                                } else {
 
-                                       if (((c1 == 0 && key_pressed(KEY_PL1_JUMP) == 1) || (c1 == 1 && key_pressed(KEY_PL2_JUMP) == 1) || (c1 == 2 && joy.but1 == 1) || (c1 == 3 && mouse.but3 == 1))) {
+                                       if (player[c1].action_up) {
                                                player[c1].y_add -= 16384;
                                                if (player[c1].y_add < -400000L)
                                                        player[c1].y_add = -400000L;
-                                               if ((ban_map[(s2 + 7) >> 4][s1 >> 4] == 0 || ban_map[(s2 + 7) >> 4][(s1 + 15) >> 4] == 0) && (ban_map[(s2 + 8) >> 4][s1 >> 4] == 2 || ban_map[(s2 + 8) >> 4][(s1 + 15) >> 4] == 2))
+                                               if ((ban_map[(s2 + 7) >> 4][s1 >> 4] == BAN_VOID || ban_map[(s2 + 7) >> 4][(s1 + 15) >> 4] == BAN_VOID) && (ban_map[(s2 + 8) >> 4][s1 >> 4] == BAN_WATER || ban_map[(s2 + 8) >> 4][(s1 + 15) >> 4] == BAN_WATER))
                                                        player[c1].in_water = 0;
                                                if (rnd(100) < 50)
                                                        add_object(OBJ_SMOKE, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 10 + rnd(5), 0, 16384 + rnd(8192), OBJ_ANIM_SMOKE, 0);
@@ -895,26 +1911,26 @@ void steer_players(void)
                                if (player[c1].y > 0) {
                                        s1 = (player[c1].x >> 16);
                                        s2 = (player[c1].y >> 16);
-                                       if (ban_map[s2 >> 4][s1 >> 4] == 1 || ban_map[s2 >> 4][s1 >> 4] == 3 || ban_map[s2 >> 4][s1 >> 4] == 4 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 3 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 4) {
+                                       if (ban_map[s2 >> 4][s1 >> 4] == BAN_SOLID || ban_map[s2 >> 4][s1 >> 4] == BAN_ICE || ban_map[s2 >> 4][s1 >> 4] == BAN_SPRING || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SPRING) {
                                                player[c1].x = (((s1 + 16) & 0xfff0)) << 16;
                                                player[c1].x_add = 0;
                                        }
                                        s1 = (player[c1].x >> 16);
                                        s2 = (player[c1].y >> 16);
-                                       if (ban_map[s2 >> 4][(s1 + 15) >> 4] == 1 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 3 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 4 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 3 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 4) {
+                                       if (ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SPRING || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SPRING) {
                                                player[c1].x = (((s1 + 16) & 0xfff0) - 16) << 16;
                                                player[c1].x_add = 0;
                                        }
                                } else {
                                        s1 = (player[c1].x >> 16);
                                        s2 = 0;
-                                       if (ban_map[s2 >> 4][s1 >> 4] == 1 || ban_map[s2 >> 4][s1 >> 4] == 3 || ban_map[s2 >> 4][s1 >> 4] == 4 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 3 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 4) {
+                                       if (ban_map[s2 >> 4][s1 >> 4] == BAN_SOLID || ban_map[s2 >> 4][s1 >> 4] == BAN_ICE || ban_map[s2 >> 4][s1 >> 4] == BAN_SPRING || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SPRING) {
                                                player[c1].x = (((s1 + 16) & 0xfff0)) << 16;
                                                player[c1].x_add = 0;
                                        }
                                        s1 = (player[c1].x >> 16);
                                        s2 = 0;
-                                       if (ban_map[s2 >> 4][(s1 + 15) >> 4] == 1 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 3 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 4 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 3 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 4) {
+                                       if (ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SPRING || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SPRING) {
                                                player[c1].x = (((s1 + 16) & 0xfff0) - 16) << 16;
                                                player[c1].x_add = 0;
                                        }
@@ -924,7 +1940,7 @@ void steer_players(void)
 
                                s1 = (player[c1].x >> 16);
                                s2 = (player[c1].y >> 16);
-                               if (ban_map[(s2 + 15) >> 4][(s1 + 8) >> 4] == 4 || ((ban_map[(s2 + 15) >> 4][s1 >> 4] == 4 && ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] != 1) || (ban_map[(s2 + 15) >> 4][s1 >> 4] != 1 && ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 4))) {
+                               if (ban_map[(s2 + 15) >> 4][(s1 + 8) >> 4] == BAN_SPRING || ((ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SPRING && ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] != BAN_SOLID) || (ban_map[(s2 + 15) >> 4][s1 >> 4] != BAN_SOLID && ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SPRING))) {
                                        player[c1].y = ((player[c1].y >> 16) & 0xfff0) << 16;
                                        player[c1].y_add = -400000L;
                                        player[c1].anim = 2;
@@ -933,9 +1949,9 @@ void steer_players(void)
                                        player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
                                        player[c1].jump_ready = 0;
                                        player[c1].jump_abort = 0;
-                                       for (c2 = 0; c2 < 300; c2++) {
+                                       for (c2 = 0; c2 < NUM_OBJECTS; c2++) {
                                                if (objects[c2].used == 1 && objects[c2].type == OBJ_SPRING) {
-                                                       if (ban_map[(s2 + 15) >> 4][(s1 + 8) >> 4] == 4) {
+                                                       if (ban_map[(s2 + 15) >> 4][(s1 + 8) >> 4] == BAN_SPRING) {
                                                                if ((objects[c2].x >> 20) == ((s1 + 8) >> 4) && (objects[c2].y >> 20) == ((s2 + 15) >> 4)) {
                                                                        objects[c2].frame = 0;
                                                                        objects[c2].ticks = object_anims[objects[c2].anim].frame[objects[c2].frame].ticks;
@@ -943,14 +1959,14 @@ void steer_players(void)
                                                                        break;
                                                                }
                                                        } else {
-                                                               if (ban_map[(s2 + 15) >> 4][s1 >> 4] == 4) {
+                                                               if (ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SPRING) {
                                                                        if ((objects[c2].x >> 20) == (s1 >> 4) && (objects[c2].y >> 20) == ((s2 + 15) >> 4)) {
                                                                                objects[c2].frame = 0;
                                                                                objects[c2].ticks = object_anims[objects[c2].anim].frame[objects[c2].frame].ticks;
                                                                                objects[c2].image = object_anims[objects[c2].anim].frame[objects[c2].frame].image;
                                                                                break;
                                                                        }
-                                                               } else if (ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 4) {
+                                                               } else if (ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SPRING) {
                                                                        if ((objects[c2].x >> 20) == ((s1 + 15) >> 4) && (objects[c2].y >> 20) == ((s2 + 15) >> 4)) {
                                                                                objects[c2].frame = 0;
                                                                                objects[c2].ticks = object_anims[objects[c2].anim].frame[objects[c2].frame].ticks;
@@ -961,13 +1977,13 @@ void steer_players(void)
                                                        }
                                                }
                                        }
-                                       dj_play_sfx(SFX_SPRING, SFX_SPRING_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                       dj_play_sfx(SFX_SPRING, (unsigned short)(SFX_SPRING_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                }
                                s1 = (player[c1].x >> 16);
                                s2 = (player[c1].y >> 16);
                                if (s2 < 0)
                                        s2 = 0;
-                               if (ban_map[s2 >> 4][s1 >> 4] == 1 || ban_map[s2 >> 4][s1 >> 4] == 3 || ban_map[s2 >> 4][s1 >> 4] == 4 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 1 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 3 || ban_map[s2 >> 4][(s1 + 15) >> 4] == 4) {
+                               if (ban_map[s2 >> 4][s1 >> 4] == BAN_SOLID || ban_map[s2 >> 4][s1 >> 4] == BAN_ICE || ban_map[s2 >> 4][s1 >> 4] == BAN_SPRING || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[s2 >> 4][(s1 + 15) >> 4] == BAN_SPRING) {
                                        player[c1].y = (((s2 + 16) & 0xfff0)) << 16;
                                        player[c1].y_add = 0;
                                        player[c1].anim = 0;
@@ -979,7 +1995,7 @@ void steer_players(void)
                                s2 = (player[c1].y >> 16);
                                if (s2 < 0)
                                        s2 = 0;
-                               if (ban_map[(s2 + 8) >> 4][(s1 + 8) >> 4] == 2) {
+                               if (ban_map[(s2 + 8) >> 4][(s1 + 8) >> 4] == BAN_WATER) {
                                        if (player[c1].in_water == 0) {
                                                player[c1].in_water = 1;
                                                player[c1].anim = 4;
@@ -989,9 +2005,9 @@ void steer_players(void)
                                                if (player[c1].y_add >= 32768) {
                                                        add_object(OBJ_SPLASH, (player[c1].x >> 16) + 8, ((player[c1].y >> 16) & 0xfff0) + 15, 0, 0, OBJ_ANIM_SPLASH, 0);
                                                        if (blood_is_thicker_than_water == 0)
-                                                               dj_play_sfx(SFX_SPLASH, SFX_SPLASH_FREQ + rnd(2000) - 1000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_SPLASH, (unsigned short)(SFX_SPLASH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
                                                        else
-                                                               dj_play_sfx(SFX_SPLASH, SFX_SPLASH_FREQ + rnd(2000) - 5000, 64, 0, 0, -1);
+                                                               dj_play_sfx(SFX_SPLASH, (unsigned short)(SFX_SPLASH_FREQ + rnd(2000) - 5000), 64, 0, 0, -1);
                                                }
                                        }
                                        player[c1].y_add -= 1536;
@@ -1005,11 +2021,11 @@ void steer_players(void)
                                                player[c1].y_add = -65536L;
                                        if (player[c1].y_add > 65535L)
                                                player[c1].y_add = 65535L;
-                                       if (ban_map[(s2 + 15) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 3 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 3) {
+                                       if (ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_ICE) {
                                                player[c1].y = (((s2 + 16) & 0xfff0) - 16) << 16;
                                                player[c1].y_add = 0;
                                        }
-                               } else if (ban_map[(s2 + 15) >> 4][s1 >> 4] == 1 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 3 || ban_map[(s2 + 15) >> 4][s1 >> 4] == 4 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 1 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 3 || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == 4) {
+                               } else if (ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][s1 >> 4] == BAN_SPRING || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SOLID || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_ICE || ban_map[(s2 + 15) >> 4][(s1 + 15) >> 4] == BAN_SPRING) {
                                        player[c1].in_water = 0;
                                        player[c1].y = (((s2 + 16) & 0xfff0) - 16) << 16;
                                        player[c1].y_add = 0;
@@ -1062,7 +2078,7 @@ void steer_players(void)
 }
 
 
-void position_player(short player_num)
+void position_player(int player_num)
 {
        int c1;
        int s1, s2;
@@ -1071,17 +2087,16 @@ void position_player(short player_num)
                while (1) {
                        s1 = rnd(22);
                        s2 = rnd(16);
-                       if (ban_map[s2][s1] == 0 && (ban_map[s2 + 1][s1] == 1 || ban_map[s2 + 1][s1] == 3))
+                       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;
@@ -1092,228 +2107,22 @@ void position_player(short 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;
-                       break;
-               }
-       }
-
-}
-
-
-void fireworks(void)
-{
-       FILE *handle;
-       int c1, c2;
-       int s1, s2, s3;
-       struct {
-               char used, direction, colour;
-               int x, y;
-               int x_add, y_add;
-               int timer;
-               int anim, frame, frame_tick, image;
-       } rabbits[20];
-       struct {
-               int x, y;
-               int old_x, old_y;
-               char col, back[2];
-       } stars[300];
-
-       outportw(0x3c4, 0x0f02);
-       memset((char *) (0xa0000 - __djgpp_base_address), 0, 65535);
-
-       if ((handle = dat_open("level.pcx", datfile_name, "rb")) == 0) {
-               strcpy(main_info.error_str, "Error loading 'level.pcx', aborting...\n");
-               return;
-       }
-       read_pcx(handle, mask_pic, 102400, pal);
-       fclose(handle);
-
-       memset(mask_pic, 0, 102400);
-
-       memset(ban_map, 0, sizeof(ban_map));
-
-       outportb(0x3c8, 0);
-       for (c1 = 0; c1 < 768; c1++)
-               outportb(0x3c9, 0);
-
-       for (c1 = 0; c1 < 4; c1++) {
-               outportw(0x3c4, ((1 << c1) << 8) + 0x02);
-               for (c2 = 193; c2 < 256; c2++) {
-                       memset((void *) (0xa0000 + c2 * 100 - __djgpp_base_address), (c2 - 192) >> 2, 100);
-                       memset((void *) (0xa0000 + 32768 + c2 * 100 - __djgpp_base_address), (c2 - 192) >> 2, 100);
-               }
-       }
-
-       outportb(0x3c8, 0);
-       for (c1 = 0; c1 < 768; c1++)
-               outportb(0x3c9, pal[c1]);
-
-       for (c1 = 0; c1 < 20; c1++)
-               rabbits[c1].used = 0;
-
-       rabbits[0].used = 1;
-       rabbits[0].colour = rnd(4);
-       rabbits[0].x = (int) (150 + rnd(100)) << 16;
-       rabbits[0].y = 256 << 16;
-       rabbits[0].x_add = ((int) rnd(65535) << 1) - 65536;
-       if (rabbits[0].x_add > 0)
-               rabbits[0].direction = 0;
-       else
-               rabbits[0].direction = 1;
-       rabbits[0].y_add = -262144 + (rnd(16384) * 5);
-       rabbits[0].timer = 30 + rnd(150);
-       rabbits[0].anim = 2;
-       rabbits[0].frame = 0;
-       rabbits[0].frame_tick = 0;
-       rabbits[0].image = player_anims[rabbits[0].anim].frame[rabbits[0].frame].image + rabbits[0].colour * 18 + rabbits[0].direction * 9;
-
-       for (c1 = 0; c1 < 300; c1++) {
-               s1 = rnd(400);
-               s2 = rnd(256);
-               s3 = 30 - rnd(7);
-               stars[c1].x = stars[c1].old_x = (s1 << 16);
-               stars[c1].y = stars[c1].old_y = (s2 << 16);
-               stars[c1].col = s3;
-               outportw(0x3ce, ((s1 & 3) << 8) + 0x04);
-               stars[c1].back[0] = stars[c1].back[1] = *(char *) (0xa0000 + s2 * 100 + (s1 >> 2) - __djgpp_base_address);
-       }
 
-       dj_set_nosound(0);
-
-       main_info.page_info[0].num_pobs = 0;
-       main_info.page_info[1].num_pobs = 0;
-       main_info.view_page = 0;
-       main_info.draw_page = 1;
-
-       while (key_pressed(1) == 0) {
-
-               dj_mix();
-
-               for (c1 = 0; c1 < 300; c1++) {
-                       stars[c1].old_x = stars[c1].x;
-                       stars[c1].old_y = stars[c1].y;
-                       stars[c1].y -= (int) (31 - stars[c1].col) * 16384;
-                       if ((stars[c1].y >> 16) < 0)
-                               stars[c1].y += 256 << 16;;
-                       if ((stars[c1].y >> 16) >= 256)
-                               stars[c1].y -= 256 << 16;;
-               }
-
-               for (c1 = 0, c2 = 0; c1 < 20; c1++) {
-                       if (rabbits[c1].used == 1)
-                               c2++;
-               }
-               if ((c2 == 0 && rnd(10000) < 200) || (c2 == 1 && rnd(10000) < 150) || (c2 == 2 && rnd(10000) < 100) || (c2 == 3 && rnd(10000) < 50)) {
-                       for (c1 = 0; c1 < 20; c1++) {
-                               if (rabbits[c1].used == 0) {
-                                       rabbits[c1].used = 1;
-                                       rabbits[c1].colour = rnd(4);
-                                       rabbits[c1].x = (int) (150 + rnd(100)) << 16;
-                                       rabbits[c1].y = 256 << 16;
-                                       rabbits[c1].x_add = ((int) rnd(65535) << 1) - 65536;
-                                       if (rabbits[c1].x_add > 0)
-                                               rabbits[c1].direction = 0;
-                                       else
-                                               rabbits[c1].direction = 1;
-                                       rabbits[c1].y_add = -262144 + (rnd(16384) * 5);
-                                       rabbits[c1].timer = 30 + rnd(150);
-                                       rabbits[c1].anim = 2;
-                                       rabbits[c1].frame = 0;
-                                       rabbits[c1].frame_tick = 0;
-                                       rabbits[c1].image = player_anims[rabbits[c1].anim].frame[rabbits[c1].frame].image + rabbits[c1].colour * 18 + rabbits[c1].direction * 9;
-                                       break;
-                               }
-                       }
-               }
-
-               dj_mix();
-
-               main_info.page_info[main_info.draw_page].num_pobs = 0;
-
-               for (c1 = 0; c1 < 20; c1++) {
-                       if (rabbits[c1].used == 1) {
-                               rabbits[c1].y_add += 2048;
-                               if (rabbits[c1].y_add > 36864 && rabbits[c1].anim != 3) {
-                                       rabbits[c1].anim = 3;
-                                       rabbits[c1].frame = 0;
-                                       rabbits[c1].frame_tick = 0;
-                                       rabbits[c1].image = player_anims[rabbits[c1].anim].frame[rabbits[c1].frame].image + rabbits[c1].colour * 18 + rabbits[c1].direction * 9;
-                               }
-                               rabbits[c1].x += rabbits[c1].x_add;
-                               rabbits[c1].y += rabbits[c1].y_add;
-                               if ((rabbits[c1].x >> 16) < 16 || (rabbits[c1].x >> 16) > 400 || (rabbits[c1].y >> 16) > 256) {
-                                       rabbits[c1].used = 0;
-                                       continue;
-                               }
-                               rabbits[c1].timer--;
-                               if (rabbits[c1].timer <= 0) {
-                                       rabbits[c1].used = 0;
-                                       for (c2 = 0; c2 < 6; c2++)
-                                               add_object(OBJ_FUR, (rabbits[c1].x >> 16) + 6 + rnd(5), (rabbits[c1].y >> 16) + 6 + rnd(5), rabbits[c1].x_add + (rnd(65535) - 32768) * 3, rabbits[c1].y_add + (rnd(65535) - 32768) * 3, 0, 44 + rabbits[c1].colour * 8);
-                                       for (c2 = 0; c2 < 6; c2++)
-                                               add_object(OBJ_FLESH, (rabbits[c1].x >> 16) + 6 + rnd(5), (rabbits[c1].y >> 16) + 6 + rnd(5), rabbits[c1].x_add + (rnd(65535) - 32768) * 3, rabbits[c1].y_add + (rnd(65535) - 32768) * 3, 0, 76);
-                                       for (c2 = 0; c2 < 6; c2++)
-                                               add_object(OBJ_FLESH, (rabbits[c1].x >> 16) + 6 + rnd(5), (rabbits[c1].y >> 16) + 6 + rnd(5), rabbits[c1].x_add + (rnd(65535) - 32768) * 3, rabbits[c1].y_add + (rnd(65535) - 32768) * 3, 0, 77);
-                                       for (c2 = 0; c2 < 8; c2++)
-                                               add_object(OBJ_FLESH, (rabbits[c1].x >> 16) + 6 + rnd(5), (rabbits[c1].y >> 16) + 6 + rnd(5), rabbits[c1].x_add + (rnd(65535) - 32768) * 3, rabbits[c1].y_add + (rnd(65535) - 32768) * 3, 0, 78);
-                                       for (c2 = 0; c2 < 10; c2++)
-                                               add_object(OBJ_FLESH, (rabbits[c1].x >> 16) + 6 + rnd(5), (rabbits[c1].y >> 16) + 6 + rnd(5), rabbits[c1].x_add + (rnd(65535) - 32768) * 3, rabbits[c1].y_add + (rnd(65535) - 32768) * 3, 0, 79);
-                                       dj_play_sfx(SFX_DEATH, SFX_DEATH_FREQ, 64, 0, 0, -1);
-                                       continue;
-                               }
-                               rabbits[c1].frame_tick++;
-                               if (rabbits[c1].frame_tick >= player_anims[rabbits[c1].anim].frame[rabbits[c1].frame].ticks) {
-                                       rabbits[c1].frame++;
-                                       if (rabbits[c1].frame >= player_anims[rabbits[c1].anim].num_frames)
-                                               rabbits[c1].frame = player_anims[rabbits[c1].anim].restart_frame;
-                                       rabbits[c1].frame_tick = 0;
-                               }
-                               rabbits[c1].image = player_anims[rabbits[c1].anim].frame[rabbits[c1].frame].image + rabbits[c1].colour * 18 + rabbits[c1].direction * 9;
-                               if (rabbits[c1].used == 1)
-                                       add_pob(main_info.draw_page, rabbits[c1].x >> 16, rabbits[c1].y >> 16, rabbits[c1].image, rabbit_gobs);
+                       if (is_server) {
+#ifdef USE_NET
+                               serverSendAlive(player_num);
+#endif
+                               player[player_num].dead_flag = 0;
                        }
-               }
-
-               dj_mix();
-
-               update_objects();
-
-               for (c1 = 0; c1 < 300; c1++) {
-                       outportw(0x3ce, (((stars[c1].x >> 16) & 3) << 8) + 0x04);
-                       outportw(0x3c4, ((1 << ((stars[c1].x >> 16) & 3)) << 8) + 0x02);
-                       stars[c1].back[main_info.draw_page] = *(char *) (0xa0000 + ((int) main_info.draw_page << 15) + (stars[c1].y >> 16) * 100 + (stars[c1].x >> 18) - __djgpp_base_address);
-                       *(char *) (0xa0000 + ((int) main_info.draw_page << 15) + (stars[c1].y >> 16) * 100 + (stars[c1].x >> 18) - __djgpp_base_address) = stars[c1].col;
-               }
-
-               dj_mix();
-
-               draw_pobs(main_info.draw_page);
-
-               main_info.draw_page ^= 1;
-               main_info.view_page ^= 1;
-               outportw(0x3d4, (main_info.view_page << 23) + 0x0d);
-               outportw(0x3d4, ((main_info.view_page << 15) & 0xff00) + 0x0c);
-
-               while ((inportb(0x3da) & 8) == 0)
-                       dj_mix();
-               while ((inportb(0x3da) & 8) == 8)
-                       dj_mix();
-
-               redraw_pob_backgrounds(main_info.draw_page);
 
-               dj_mix();
-
-               for (c1 = 299; c1 >= 0; c1--) {
-                       outportw(0x3c4, ((1 << ((stars[c1].old_x >> 16) & 3)) << 8) + 0x02);
-                       *(char *) (0xa0000 + ((int) main_info.draw_page << 15) + (stars[c1].old_y >> 16) * 100 + (stars[c1].old_x >> 18) - __djgpp_base_address) = stars[c1].back[main_info.draw_page];
+                       break;
                }
        }
 
-       dj_set_nosound(1);
-
 }
 
 
-void add_object(char type, short x, short y, long x_add, long y_add, short anim, short frame)
+void add_object(int type, int x, int y, int x_add, int y_add, int anim, int frame)
 {
        int c1;
 
@@ -1341,7 +2150,7 @@ void add_object(char type, short x, short y, long x_add, long y_add, short anim,
 void update_objects(void)
 {
        int c1;
-       int s1;
+       int s1 = 0;
 
        for (c1 = 0; c1 < NUM_OBJECTS; c1++) {
                if (objects[c1].used == 1) {
@@ -1359,7 +2168,7 @@ void update_objects(void)
                                        }
                                }
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
                                break;
                        case OBJ_SPLASH:
                                objects[c1].ticks--;
@@ -1373,7 +2182,7 @@ void update_objects(void)
                                        }
                                }
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
                                break;
                        case OBJ_SMOKE:
                                objects[c1].x += objects[c1].x_add;
@@ -1389,7 +2198,7 @@ void update_objects(void)
                                        }
                                }
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
                                break;
                        case OBJ_YEL_BUTFLY:
                        case OBJ_PINK_BUTFLY:
@@ -1487,7 +2296,7 @@ void update_objects(void)
                                        }
                                }
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
                                break;
                        case OBJ_FUR:
                                if (rnd(100) < 30)
@@ -1558,14 +2367,14 @@ void update_objects(void)
                                if (objects[c1].x_add > 0 && objects[c1].x_add < 16384)
                                        objects[c1].x_add = 16384;
                                if (objects[c1].used == 1) {
-                                       s1 = atan2(objects[c1].y_add, objects[c1].x_add) * 4 / M_PI;
+                                       s1 = (int)(atan2(objects[c1].y_add, objects[c1].x_add) * 4 / M_PI);
                                        if (s1 < 0)
                                                s1 += 8;
                                        if (s1 < 0)
                                                s1 = 0;
                                        if (s1 > 7)
                                                s1 = 7;
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].frame + s1, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].frame + s1, &object_gobs);
                                }
                                break;
                        case OBJ_FLESH:
@@ -1630,8 +2439,8 @@ void update_objects(void)
                                                        } else {
                                                                if (rnd(100) < 10) {
                                                                        s1 = rnd(4) - 2;
-                                                                       add_leftovers(0, objects[c1].x >> 16, (objects[c1].y >> 16) + s1, objects[c1].frame, object_gobs);
-                                                                       add_leftovers(1, objects[c1].x >> 16, (objects[c1].y >> 16) + s1, objects[c1].frame, object_gobs);
+                                                                       add_leftovers(0, objects[c1].x >> 16, (objects[c1].y >> 16) + s1, objects[c1].frame, &object_gobs);
+                                                                       add_leftovers(1, objects[c1].x >> 16, (objects[c1].y >> 16) + s1, objects[c1].frame, &object_gobs);
                                                                }
                                                                objects[c1].used = 0;
                                                        }
@@ -1649,7 +2458,7 @@ void update_objects(void)
                                if (objects[c1].x_add > 0 && objects[c1].x_add < 16384)
                                        objects[c1].x_add = 16384;
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].frame, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].frame, &object_gobs);
                                break;
                        case OBJ_FLESH_TRACE:
                                objects[c1].ticks--;
@@ -1663,7 +2472,7 @@ void update_objects(void)
                                        }
                                }
                                if (objects[c1].used == 1)
-                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, object_gobs);
+                                       add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
                                break;
                        }
                }
@@ -1672,7 +2481,7 @@ void update_objects(void)
 }
 
 
-char add_pob(char page, short x, short y, short image, char *pob_data)
+int add_pob(int page, int x, int y, int image, gob_t *pob_data)
 {
 
        if (main_info.page_info[page].num_pobs >= NUM_POBS)
@@ -1689,7 +2498,19 @@ char add_pob(char page, short x, short y, short image, char *pob_data)
 }
 
 
-void draw_pobs(char page)
+void draw_flies(int page)
+{
+       int c2;
+
+       for (c2 = 0; c2 < NUM_FLIES; c2++) {
+               flies[c2].back[main_info.draw_page] = get_pixel(main_info.draw_page, flies[c2].x, flies[c2].y);
+               flies[c2].back_defined[main_info.draw_page] = 1;
+               if (mask_pic[(flies[c2].y * JNB_WIDTH) + flies[c2].x] == 0)
+                       set_pixel(main_info.draw_page, flies[c2].x, flies[c2].y, 0);
+       }
+}
+
+void draw_pobs(int page)
 {
        int c1;
        int back_buf_ofs;
@@ -1698,25 +2519,41 @@ void draw_pobs(char 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), (char *) (main_info.pob_backbuf[page] + back_buf_ofs));
-               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);
+               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);
        }
 
 }
 
 
-void redraw_pob_backgrounds(char page)
+void redraw_flies_background(int page)
+{
+       int c2;
+
+       for (c2 = NUM_FLIES - 1; c2 >= 0; c2--) {
+               if (flies[c2].back_defined[page] == 1)
+                       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;
+       }
+}
+
+
+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), (char *) (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);
 
 }
 
 
-char add_leftovers(char page, short x, short y, short image, char *pob_data)
+int add_leftovers(int page, int x, int y, int image, gob_t *pob_data)
 {
 
        if (leftovers.page[page].num_pobs >= NUM_LEFTOVERS)
@@ -1733,10 +2570,9 @@ char add_leftovers(char page, short x, short y, short image, char *pob_data)
 }
 
 
-void draw_leftovers(char page)
+void draw_leftovers(int page)
 {
        int c1;
-       int back_buf_ofs;
 
        for (c1 = leftovers.page[page].num_pobs - 1; c1 >= 0; c1--)
                put_pob(page, leftovers.page[page].pobs[c1].x, leftovers.page[page].pobs[c1].y, leftovers.page[page].pobs[c1].image, leftovers.page[page].pobs[c1].pob_data, 1, mask_pic);
@@ -1746,50 +2582,49 @@ void draw_leftovers(char page)
 }
 
 
-char init_level(short level)
+int init_level(int level, char *pal)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
-       int l1;
        int s1, s2;
 
        if ((handle = dat_open("level.pcx", datfile_name, "rb")) == 0) {
                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);
-       memset(cur_pal, 0, 768);
+       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);
                }
        }
 
-       for (c1 = 0; c1 < 300; c1++)
+       for (c1 = 0; c1 < NUM_OBJECTS; c1++)
                objects[c1].used = 0;
 
        for (c1 = 0; c1 < 16; c1++) {
                for (c2 = 0; c2 < 22; c2++) {
-                       if (ban_map[c1][c2] == 4)
+                       if (ban_map[c1][c2] == BAN_SPRING)
                                add_object(OBJ_SPRING, c2 << 4, c1 << 4, 0, 0, OBJ_ANIM_SPRING, 5);
                }
        }
@@ -1797,7 +2632,7 @@ char init_level(short level)
        while (1) {
                s1 = rnd(22);
                s2 = rnd(16);
-               if (ban_map[s2][s1] == 0) {
+               if (ban_map[s2][s1] == BAN_VOID) {
                        add_object(OBJ_YEL_BUTFLY, (s1 << 4) + 8, (s2 << 4) + 8, (rnd(65535) - 32768) * 2, (rnd(65535) - 32768) * 2, 0, 0);
                        break;
                }
@@ -1805,7 +2640,7 @@ char init_level(short level)
        while (1) {
                s1 = rnd(22);
                s2 = rnd(16);
-               if (ban_map[s2][s1] == 0) {
+               if (ban_map[s2][s1] == BAN_VOID) {
                        add_object(OBJ_YEL_BUTFLY, (s1 << 4) + 8, (s2 << 4) + 8, (rnd(65535) - 32768) * 2, (rnd(65535) - 32768) * 2, 0, 0);
                        break;
                }
@@ -1813,7 +2648,7 @@ char init_level(short level)
        while (1) {
                s1 = rnd(22);
                s2 = rnd(16);
-               if (ban_map[s2][s1] == 0) {
+               if (ban_map[s2][s1] == BAN_VOID) {
                        add_object(OBJ_PINK_BUTFLY, (s1 << 4) + 8, (s2 << 4) + 8, (rnd(65535) - 32768) * 2, (rnd(65535) - 32768) * 2, 0, 0);
                        break;
                }
@@ -1821,7 +2656,7 @@ char init_level(short level)
        while (1) {
                s1 = rnd(22);
                s2 = rnd(16);
-               if (ban_map[s2][s1] == 0) {
+               if (ban_map[s2][s1] == BAN_VOID) {
                        add_object(OBJ_PINK_BUTFLY, (s1 << 4) + 8, (s2 << 4) + 8, (rnd(65535) - 32768) * 2, (rnd(65535) - 32768) * 2, 0, 0);
                        break;
                }
@@ -1834,22 +2669,100 @@ char init_level(short level)
 
 void deinit_level(void)
 {
-       int c1, c2;
-
        dj_set_nosound(1);
        dj_stop_mod();
+}
 
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#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: %s\n", fname, strerror(errno));
+        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);
 }
 
 
-char init_program(int argc, char *argv[])
+int init_program(int argc, char *argv[], char *pal)
 {
-       FILE *handle;
-       int c1, c2;
-       char load_flag;
-       char force2, force3;
+       char *netarg = NULL;
+       unsigned char *handle = (unsigned char *) NULL;
+       int c1 = 0, c2 = 0;
+       int load_flag = 0;
+       int force2, force3;
        sfx_data fly;
-       int player_anim_data[] = { 1, 0, 0, 0x7fff, 0, 0, 0, 0, 0, 0,
+       int player_anim_data[] = {
+               1, 0, 0, 0x7fff, 0, 0, 0, 0, 0, 0,
                4, 0, 0, 4, 1, 4, 2, 4, 3, 4,
                1, 0, 4, 0x7fff, 0, 0, 0, 0, 0, 0,
                4, 2, 5, 8, 6, 10, 7, 3, 6, 3,
@@ -1858,18 +2771,23 @@ char init_program(int argc, char *argv[])
                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;
+#endif
 
-       srandom(time(0));
+       srand(time(NULL));
 
        if (hook_keyb_handler() != 0)
                return 1;
 
        memset(&main_info, 0, sizeof(main_info));
-       main_info.joy_enabled = 1;
 
-       strcpy(datfile_name, "jumpbump.dat");
+       strcpy(datfile_name, DATA_PATH);
 
        force2 = force3 = 0;
 
@@ -1877,19 +2795,50 @@ char init_program(int argc, char *argv[])
                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)
                                main_info.fireworks = 1;
+#ifdef USE_SDL
+                       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]);
+                               }
+                       } 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];
+                               }
                        } else if (stricmp(argv[c1], "-mouse") == 0) {
                                if (c1 < (argc - 1)) {
                                        if (stricmp(argv[c1 + 1], "2") == 0)
@@ -1898,9 +2847,47 @@ char init_program(int argc, char *argv[])
                                                force3 = 1;
                                }
                        }
+                       else if (strstr(argv[1],"-v")) {
+                               printf("jumpnbump %s compiled %s at %s with",JNB_VERSION,__DATE__,__TIME__);
+#ifndef _SDLnet_h
+                               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");
+                               printf("  -port port               define listen port\n");
+                               printf("  -net player host rport   define network players\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];
@@ -1910,72 +2897,58 @@ char init_program(int argc, char *argv[])
                }
        }
 
-       if ((background_pic = malloc(102400L)) == 0)
-               return 1;
-       if ((mask_pic = malloc(102400L)) == 0)
+       if ((handle = dat_open("menu.pcx", datfile_name, "rb")) == 0) {
+               strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
                return 1;
-       memset(mask_pic, 0, 102400);
-
-       main_info.pob_backbuf[0] = malloc(65535);
-       main_info.pob_backbuf[1] = malloc(65535);
-       if (main_info.pob_backbuf[0] == 0 || main_info.pob_backbuf[1] == 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;
+       }
 
        if ((handle = dat_open("rabbit.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'rabbit.gob', aborting...\n");
                return 1;
        }
-       if ((rabbit_gobs = malloc(dat_filelen("rabbit.gob", datfile_name))) == 0) {
-               strcpy(main_info.error_str, "Not enough memory, aborting...\n");
-               fclose(handle);
+       if (register_gob(handle, &rabbit_gobs, dat_filelen("rabbit.gob", datfile_name))) {
+               /* error */
                return 1;
        }
-       fread(rabbit_gobs, 1, dat_filelen("rabbit.gob", datfile_name), handle);
-       fclose(handle);
 
        if ((handle = dat_open("objects.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'objects.gob', aborting...\n");
                return 1;
        }
-       if ((object_gobs = malloc(dat_filelen("objects.gob", datfile_name))) == 0) {
-               strcpy(main_info.error_str, "Not enough memory, aborting...\n");
-               fclose(handle);
+       if (register_gob(handle, &object_gobs, dat_filelen("objects.gob", datfile_name))) {
+               /* error */
                return 1;
        }
-       fread(object_gobs, 1, dat_filelen("objects.gob", datfile_name), handle);
-       fclose(handle);
 
        if ((handle = dat_open("font.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'font.gob', aborting...\n");
                return 1;
        }
-       if ((font_gobs = malloc(dat_filelen("font.gob", datfile_name))) == 0) {
-               strcpy(main_info.error_str, "Not enough memory, aborting...\n");
-               fclose(handle);
+       if (register_gob(handle, &font_gobs, dat_filelen("font.gob", datfile_name))) {
+               /* error */
                return 1;
        }
-       fread(font_gobs, 1, dat_filelen("font.gob", datfile_name), handle);
-       fclose(handle);
 
        if ((handle = dat_open("numbers.gob", datfile_name, "rb")) == 0) {
                strcpy(main_info.error_str, "Error loading 'numbers.gob', aborting...\n");
                return 1;
        }
-       if ((number_gobs = malloc(dat_filelen("numbers.gob", datfile_name))) == 0) {
-               strcpy(main_info.error_str, "Not enough memory, aborting...\n");
-               fclose(handle);
+       if (register_gob(handle, &number_gobs, dat_filelen("numbers.gob", datfile_name))) {
+               /* error */
                return 1;
        }
-       fread(number_gobs, 1, dat_filelen("numbers.gob", datfile_name), handle);
-       fclose(handle);
 
        if (read_level() != 0) {
                strcpy(main_info.error_str, "Error loading 'levelmap.txt', aborting...\n");
-               fclose(handle);
                return 1;
        }
 
        dj_init();
+
        if (main_info.no_sound == 0) {
                dj_autodetect_sd();
                dj_set_mixing_freq(20000);
@@ -1995,7 +2968,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2005,7 +2977,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2015,7 +2986,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2025,7 +2995,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2035,7 +3004,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2045,7 +3013,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2055,7 +3022,6 @@ char init_program(int argc, char *argv[])
                        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");
@@ -2065,7 +3031,6 @@ char init_program(int argc, char *argv[])
                        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;
@@ -2076,123 +3041,109 @@ char init_program(int argc, char *argv[])
                dj_set_sfx_settings(SFX_FLY, &fly);
        }
 
-       open_screen();
-
-       if ((handle = dat_open("menu.pcx", datfile_name, "rb")) == 0) {
-               strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
+       if ((background_pic = malloc(JNB_WIDTH*JNB_HEIGHT)) == NULL)
                return 1;
-       }
-       if (read_pcx(handle, background_pic, 102400L, pal) != 0) {
-               strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
+       if ((mask_pic = malloc(JNB_WIDTH*JNB_HEIGHT)) == NULL)
                return 1;
+       memset(mask_pic, 0, JNB_WIDTH*JNB_HEIGHT);
+       register_mask(mask_pic);
+
+       for (c1 = 0; c1 < 16; c1++) { // fix dark font
+               pal[(240 + c1) * 3 + 0] = c1 << 2;
+               pal[(240 + c1) * 3 + 1] = c1 << 2;
+               pal[(240 + c1) * 3 + 2] = c1 << 2;
        }
-       fclose(handle);
 
-       outportb(0x3c8, 0);
-       for (c1 = 0; c1 < 768; c1++)
-               outportb(0x3c9, pal[c1]);
+       setpalette(0, 256, pal);
+
+       init_inputs();
+
+       recalculate_gob(&font_gobs, pal);
 
        if (main_info.joy_enabled == 1 && main_info.fireworks == 0) {
-               c1 = 0;
-               outportb(0x201, 0);
-               while (c1 < 0x7fff) {
-                       if ((inportb(0x201) & 1) == 0)
-                               break;
-                       c1++;
-               }
-               if (c1 != 0x7fff) {
-                       main_info.joy_enabled = 1;
-                       load_flag = 0;
-                       put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
-                       put_text(0, 200, 100, "Move the joystick to the", 2);
-                       put_text(0, 200, 115, "UPPER LEFT", 2);
-                       put_text(0, 200, 130, "and press button A", 2);
-                       put_text(0, 200, 200, "Or press ESC to use", 2);
-                       put_text(0, 200, 215, "previous settings", 2);
-                       if (calib_joy(0) != 0)
+               load_flag = 0;
+               put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
+               put_text(0, 200, 100, "Move the joystick to the", 2);
+               put_text(0, 200, 115, "UPPER LEFT", 2);
+               put_text(0, 200, 130, "and press button A", 2);
+               put_text(0, 200, 200, "Or press ESC to use", 2);
+               put_text(0, 200, 215, "previous settings", 2);
+               if (calib_joy(0) != 0)
+                       load_flag = 1;
+               else {
+                       register_background(NULL, NULL);
+
+                       main_info.view_page = 1;
+                       flippage(1);
+
+                       wait_vrt(0);
+
+                       put_text(1, 200, 40, "JOYSTICK CALIBRATION", 2);
+                       put_text(1, 200, 100, "Move the joystick to the", 2);
+                       put_text(1, 200, 115, "LOWER RIGHT", 2);
+                       put_text(1, 200, 130, "and press button A", 2);
+                       put_text(1, 200, 200, "Or press ESC to use", 2);
+                       put_text(1, 200, 215, "previous settings", 2);
+                       if (calib_joy(1) != 0)
                                load_flag = 1;
                        else {
-                               outportw(0x3c4, 0x0f02);
-                               memset((char *) (0xa0000 + 32768 + __djgpp_conventional_base), 0, 32768);
-                               main_info.view_page = 1;
-                               outportw(0x3d4, (1 << 23) + 0x0d);
-                               outportw(0x3d4, ((1 << 15) & 0xff00) + 0x0c);
-                               wait_vrt();
-
-                               put_text(1, 200, 40, "JOYSTICK CALIBRATION", 2);
-                               put_text(1, 200, 100, "Move the joystick to the", 2);
-                               put_text(1, 200, 115, "LOWER RIGHT", 2);
-                               put_text(1, 200, 130, "and press button A", 2);
-                               put_text(1, 200, 200, "Or press ESC to use", 2);
-                               put_text(1, 200, 215, "previous settings", 2);
-                               if (calib_joy(1) != 0)
+                               register_background(NULL, NULL);
+                               flippage(0);
+
+                               wait_vrt(0);
+
+                               put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
+                               put_text(0, 200, 100, "Move the joystick to the", 2);
+                               put_text(0, 200, 115, "CENTER", 2);
+                               put_text(0, 200, 130, "and press button A", 2);
+                               put_text(0, 200, 200, "Or press ESC to use", 2);
+                               put_text(0, 200, 215, "previous settings", 2);
+                               if (calib_joy(2) != 0)
                                        load_flag = 1;
                                else {
-                                       outportw(0x3c4, 0x0f02);
-                                       memset((char *) (0xa0000 + __djgpp_conventional_base), 0, 32768);
-                                       outportw(0x3d4, (0 << 23) + 0x0d);
-                                       outportw(0x3d4, ((0 << 15) & 0xff00) + 0x0c);
-                                       wait_vrt();
-
-                                       put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
-                                       put_text(0, 200, 100, "Move the joystick to the", 2);
-                                       put_text(0, 200, 115, "CENTER", 2);
-                                       put_text(0, 200, 130, "and press button A", 2);
-                                       put_text(0, 200, 200, "Or press ESC to use", 2);
-                                       put_text(0, 200, 215, "previous settings", 2);
-                                       if (calib_joy(2) != 0)
-                                               load_flag = 1;
-                                       else {
-                                               if (joy.calib_data.x1 == joy.calib_data.x2)
-                                                       joy.calib_data.x1 -= 10;
-                                               if (joy.calib_data.x3 == joy.calib_data.x2)
-                                                       joy.calib_data.x3 += 10;
-                                               if (joy.calib_data.y1 == joy.calib_data.y2)
-                                                       joy.calib_data.y1 -= 10;
-                                               if (joy.calib_data.y3 == joy.calib_data.y2)
-                                                       joy.calib_data.y3 += 10;
-                                               write_calib_data();
-                                       }
+                                       if (joy.calib_data.x1 == joy.calib_data.x2)
+                                               joy.calib_data.x1 -= 10;
+                                       if (joy.calib_data.x3 == joy.calib_data.x2)
+                                               joy.calib_data.x3 += 10;
+                                       if (joy.calib_data.y1 == joy.calib_data.y2)
+                                               joy.calib_data.y1 -= 10;
+                                       if (joy.calib_data.y3 == joy.calib_data.y2)
+                                               joy.calib_data.y3 += 10;
+                                       write_calib_data();
                                }
                        }
-                       if (load_flag == 1) {
-                               if ((handle = dat_open("calib.dat", datfile_name, "rb")) == 0) {
-                                       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);
+               }
+               if (load_flag == 1) {
+                       if ((handle = dat_open("calib.dat", datfile_name, "rb")) == 0) {
+                               strcpy(main_info.error_str, "Error loading 'calib.dat', aborting...\n");
+                               return 1;
                        }
-               } else
-                       main_info.joy_enabled = 0;
-
+                       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;
+               }
        }
 
-       regs.x.ax = 0;
-       __dpmi_int(0x33, &regs);
-       if (regs.x.ax == 0xffff) {
-               main_info.mouse_enabled = 1;
-               main_info.num_mouse_buttons = regs.x.bx;
-               if (force2 == 1)
-                       main_info.num_mouse_buttons = 2;
-               if (force3 == 1)
-                       main_info.num_mouse_buttons = 3;
-       } else
-               main_info.mouse_enabled = 0;
+#ifdef USE_NET
+       if (is_server) {
+               init_server(netarg);
+       } else {
+               connect_to_server(netarg);
+       }
+#endif
 
        return 0;
 
 }
 
-
 void deinit_program(void)
 {
+#ifdef DOS
        __dpmi_regs regs;
+#endif
 
        dj_stop();
        dj_free_mod(MOD_MENU);
@@ -2202,18 +3153,6 @@ void deinit_program(void)
        dj_free_sfx(SFX_SPLASH);
        dj_deinit();
 
-       if (rabbit_gobs != 0)
-               free(rabbit_gobs);
-       if (object_gobs != 0)
-               free(object_gobs);
-       if (number_gobs != 0)
-               free(number_gobs);
-
-       if (main_info.pob_backbuf[0] != 0)
-               free(main_info.pob_backbuf[0]);
-       if (main_info.pob_backbuf[1] != 0)
-               free(main_info.pob_backbuf[1]);
-
        if (background_pic != 0)
                free(background_pic);
        if (mask_pic != 0)
@@ -2221,11 +3160,16 @@ void deinit_program(void)
 
        remove_keyb_handler();
 
+#ifdef DOS
        regs.x.ax = 0x3;
        __dpmi_int(0x10, &regs);
+#endif
 
        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);
@@ -2233,200 +3177,15 @@ void deinit_program(void)
 }
 
 
-void read_joy(void)
-{
-       int c1;
-       int x, y;
-       int s1;
-       char flag;
-
-       c1 = x = y = flag = 0;
-       outportb(0x201, 0);
-
-       while (1) {
-
-               s1 = inportb(0x201);
-
-               if (x == 0) {
-                       if ((s1 & 1) == 0)
-                               x = c1;
-               }
-               if (y == 0) {
-                       if ((s1 & 2) == 0)
-                               y = c1;
-               }
-               if (x != 0 && y != 0)
-                       break;
-
-               c1++;
-               if (c1 == 0x7fff) {
-                       flag = 1;
-                       break;
-               }
-
-       }
-
-       if (flag == 0) {
-               joy.raw_x = x;
-               joy.raw_y = y;
-
-               if (joy.raw_x < joy.calib_data.x2)
-                       joy.x = ((long) (joy.raw_x - joy.calib_data.x2) << 10) / (joy.calib_data.x2 - joy.calib_data.x1);
-               else
-                       joy.x = ((long) (joy.raw_x - joy.calib_data.x2) << 10) / (joy.calib_data.x3 - joy.calib_data.x2);
-               if (joy.raw_y < joy.calib_data.y2)
-                       joy.y = ((long) (joy.raw_y - joy.calib_data.y2) << 10) / (joy.calib_data.y2 - joy.calib_data.y1);
-               else
-                       joy.y = ((long) (joy.raw_y - joy.calib_data.y2) << 10) / (joy.calib_data.y3 - joy.calib_data.y2);
-
-               if (joy.x < -1024)
-                       joy.x = -1024;
-               if (joy.x > 1024)
-                       joy.x = 1024;
-               if (joy.y < -1024)
-                       joy.y = -1024;
-               if (joy.y > 1024)
-                       joy.y = 1024;
-
-               s1 = inportb(0x201);
-               joy.but1 = (((s1 >> 4) & 1) ^ 1);
-               joy.but2 = (((s1 >> 5) & 1) ^ 1);
-       } else {
-               joy.raw_x = joy.calib_data.x2;
-               joy.raw_y = joy.calib_data.y2;
-
-               joy.x = joy.y = 0;
-
-               joy.but1 = joy.but2 = 0;
-       }
-
-}
-
-
-char calib_joy(char type)
-{
-       int c1;
-       int x, y;
-       int s1;
-       int num_times;
-       char flag;
-
-       while (joy.but1 == 1) {
-               s1 = inportb(0x201);
-               joy.but1 = (((s1 >> 4) & 1) ^ 1);
-               if (key_pressed(1) == 1) {
-                       while (key_pressed(1) == 1);
-                       return 1;
-               }
-       }
-
-       num_times = 0;
-
-       while (joy.but1 == 0) {
-
-               c1 = x = y = flag = 0;
-               outportb(0x201, 0);
-
-               while (1) {
-
-                       s1 = inportb(0x201);
-
-                       if (x == 0) {
-                               if ((s1 & 1) == 0)
-                                       x = c1;
-                       }
-                       if (y == 0) {
-                               if ((s1 & 2) == 0)
-                                       y = c1;
-                       }
-                       if (x != 0 && y != 0)
-                               break;
-
-                       c1++;
-                       if (c1 == 0x7fff) {
-                               flag = 1;
-                               break;
-                       }
-
-               }
-
-               joy.raw_x = x;
-               joy.raw_y = y;
-
-               s1 = inportb(0x201);
-               joy.but1 = (((s1 >> 4) & 1) ^ 1);
-
-               if (num_times < 0x7fffffff)
-                       num_times++;
-
-               if (flag == 1)
-                       break;
-
-               if (key_pressed(1) == 1) {
-                       while (key_pressed(1) == 1);
-                       return 1;
-               }
-
-       }
-
-       if (num_times < 16)
-               return 1;
-
-       if (flag == 0) {
-
-               switch (type) {
-               case 0:
-                       joy.calib_data.x1 = joy.raw_x;
-                       joy.calib_data.y1 = joy.raw_y;
-                       break;
-               case 1:
-                       joy.calib_data.x3 = joy.raw_x;
-                       joy.calib_data.y3 = joy.raw_y;
-                       break;
-               case 2:
-                       joy.calib_data.x2 = joy.raw_x;
-                       joy.calib_data.y2 = joy.raw_y;
-                       break;
-               }
-
-               while (joy.but1 == 1) {
-                       s1 = inportb(0x201);
-                       joy.but1 = (((s1 >> 4) & 1) ^ 1);
-               }
-
-       }
-
-       return 0;
-
-}
-
-
-void read_mouse(void)
-{
-
-       regs.x.ax = 3;
-       __dpmi_int(0x33, &regs);
-       mouse.but1 = regs.x.bx & 1;
-       mouse.but2 = (regs.x.bx & 2) >> 1;
-       mouse.but3 = (regs.x.bx & 4) >> 2;
-
-}
-
-
 unsigned short rnd(unsigned short max)
 {
-       int l1;
-
-       l1 = ((random() >> 16) * max) / 0x7fff;
-       if (l1 > max - 1)
-               l1 = max - 1;
-       return l1;
+       return (rand() % max);
 }
 
 
-char read_level(void)
+int read_level(void)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
        int chr;
 
@@ -2438,47 +3197,59 @@ char 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] = 1;
+               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;
 
-       if ((handle = fopen(dat_name, mode)) == NULL)
+       if (datafile_buffer == NULL)
                return 0;
 
-       num = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
+       memset(name, 0, sizeof(name));
+
+       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++) {
-               fread(name, 1, 12, handle);
+
+               memcpy(name, ptr, 12);
+               ptr += 12;
+
                if (strnicmp(name, file_name, strlen(file_name)) == 0) {
-                       ofs = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (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;
        }
 
        return 0;
@@ -2487,29 +3258,43 @@ FILE *dat_open(char *file_name, char *dat_name, char *mode)
 
 int dat_filelen(char *file_name, char *dat_name)
 {
-       FILE *handle;
+       unsigned char *ptr;
        int num;
        int c1;
        char name[21];
        int len;
 
-       if ((handle = fopen(dat_name, "rb")) == NULL)
-               return 0;
+       memset(name, 0, sizeof(name));
+       
+       num = ( (datafile_buffer[0] <<  0) +
+               (datafile_buffer[1] <<  8) +
+               (datafile_buffer[2] << 16) +
+               (datafile_buffer[3] << 24) );
+
+       ptr = datafile_buffer + 4;
 
-       num = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
        for (c1 = 0; c1 < num; c1++) {
-               fread(name, 1, 12, handle);
+
+               memcpy(name, ptr, 12);
+               ptr += 12;
+
                if (strnicmp(name, file_name, strlen(file_name)) == 0) {
-                       fseek(handle, 4, SEEK_CUR);
-                       len = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
+
+                       ptr += 4;
+                       len = ( (ptr[0] <<  0) +
+                               (ptr[1] <<  8) +
+                               (ptr[2] << 16) +
+                               (ptr[3] << 24) );
+
                        return len;
                }
-               fseek(handle, 8, SEEK_CUR);
+               ptr += 8;
        }
 
        return 0;
 }
 
+
 void write_calib_data(void)
 {
        FILE *handle;