no message
[crow/jumpnbump.git] / main.c
diff --git a/main.c b/main.c
index ae36572..91b1b00 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,19 +1,60 @@
-#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
+ */
 
+#include "globals.h"
+#include <fcntl.h>
 
-#ifdef DOS
-__dpmi_regs regs;
-#endif
+#ifdef USE_NET
+#include "SDL_net.h"
+#endif /* USE_NET */
 
 #ifndef M_PI
 #define M_PI           3.14159265358979323846
 #endif
 
-char *object_gobs;
-char *number_gobs;
+gob_t rabbit_gobs = { 0 };
+gob_t font_gobs = { 0 };
+gob_t object_gobs = { 0 };
+gob_t number_gobs = { 0 };
 
-char pal[768];
-char cur_pal[768];
+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},
@@ -158,10 +199,14 @@ struct {
        }
 };
 
+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 {
@@ -170,27 +215,770 @@ 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;
+
+
+#ifndef _MSC_VER
+int filelength(int handle)
+{
+       struct stat buf;
+
+       if (fstat(handle, &buf) == -1) {
+               perror("filelength");
+               exit(EXIT_FAILURE);
+       }
+
+       return buf.st_size;
+}
+#endif
+
+
+/* networking shite. */
+
+int client_player_num = -1;
+int is_server = 1;
+int is_net = 0;
+
+#ifdef USE_NET
+TCPsocket sock = NULL;
+SDLNet_SocketSet socketset = NULL;
+
+typedef struct
+{
+       TCPsocket sock;
+       IPaddress addr;
+       SDLNet_SocketSet socketset;
+} NetInfo;
+
+NetInfo net_info[JNB_MAX_PLAYERS];
+#endif
+
+typedef struct
+{
+       unsigned long cmd;
+       long arg;
+       long arg2;
+       long arg3;
+       long arg4;
+} NetPacket;
+
+#define NETPKTBUFSIZE (4 + 4 + 4 + 4 + 4)
+
+#define NETCMD_NACK         (0xF00DF00D + 0)
+#define NETCMD_ACK          (0xF00DF00D + 1)
+#define NETCMD_HELLO        (0xF00DF00D + 2)
+#define NETCMD_GREENLIGHT   (0xF00DF00D + 3)
+#define NETCMD_MOVE         (0xF00DF00D + 4)
+#define NETCMD_BYE          (0xF00DF00D + 5)
+#define NETCMD_POSITION     (0xF00DF00D + 6)
+#define NETCMD_ALIVE        (0xF00DF00D + 7)
+#define NETCMD_KILL         (0xF00DF00D + 8)
+
+
+#ifdef USE_NET
+void bufToPacket(const char *buf, NetPacket *pkt)
+{
+       SDLNet_Write32(*((unsigned long *) (buf +  0)), &pkt->cmd);
+       SDLNet_Write32(*((unsigned long *) (buf +  4)), &pkt->arg);
+       SDLNet_Write32(*((unsigned long *) (buf +  8)), &pkt->arg2);
+       SDLNet_Write32(*((unsigned long *) (buf + 12)), &pkt->arg3);
+       SDLNet_Write32(*((unsigned long *) (buf + 16)), &pkt->arg4);
+/*
+       pkt->cmd               =        ntohl(*((unsigned long *) (buf +  0)));
+       pkt->arg               = (long) ntohl(*((unsigned long *) (buf +  4)));
+       pkt->arg2              = (long) ntohl(*((unsigned long *) (buf +  8)));
+       pkt->arg3              = (long) ntohl(*((unsigned long *) (buf + 12)));
+       pkt->arg4              = (long) ntohl(*((unsigned long *) (buf + 16)));
+*/
+}
+
+
+void packetToBuf(const NetPacket *pkt, char *buf)
+{
+       *((unsigned long *) (buf +  0)) = SDLNet_Read32(&pkt->cmd);
+       *((unsigned long *) (buf +  4)) = SDLNet_Read32(&pkt->arg);
+       *((unsigned long *) (buf +  8)) = SDLNet_Read32(&pkt->arg2);
+       *((unsigned long *) (buf + 12)) = SDLNet_Read32(&pkt->arg3);
+       *((unsigned long *) (buf + 16)) = SDLNet_Read32(&pkt->arg4);
+/*
+       *((unsigned long *) (buf +  0)) = htonl(pkt->cmd);
+       *((unsigned long *) (buf +  4)) = htonl((unsigned long) pkt->arg);
+       *((unsigned long *) (buf +  8)) = htonl((unsigned long) pkt->arg2);
+       *((unsigned long *) (buf + 12)) = htonl((unsigned long) pkt->arg3);
+       *((unsigned long *) (buf + 16)) = htonl((unsigned long) pkt->arg4);
+*/
+}
+
+
+void sendPacketToSock(TCPsocket s, NetPacket *pkt)
+{
+       int bytes_left = NETPKTBUFSIZE;
+       int bw;
+       char buf[NETPKTBUFSIZE];
+       char *ptr = buf;
+
+       packetToBuf(pkt, buf);
+       while (bytes_left > 0) {
+               bw = SDLNet_TCP_Send(s, ptr, bytes_left);
+               if (bw < 0) {
+                       fprintf(stderr, "SERVER: SDLNet_TCP_Send(): %s\n", SDLNet_GetError());
+                       SDLNet_TCP_Close(s);
+                       exit(42);
+               } else if (bw == 0) {
+                       SDL_Delay(1);
+               } else {
+                       bytes_left -= bw;
+                       ptr += bw;
+               }
+       }
+}
+
+
+void sendPacket(int playerid, NetPacket *pkt)
+{
+       if ( playerid < JNB_MAX_PLAYERS ) {
+               if ((player[playerid].enabled) && (playerid != client_player_num)) {
+                       sendPacketToSock(net_info[playerid].sock, pkt);
+               }
+       }
+}
+
+
+void sendPacketToAll(NetPacket *pkt)
+{
+       int i;
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               sendPacket(i, pkt);
+       }
+}
+
+
+int grabPacket(TCPsocket s, SDLNet_SocketSet ss, NetPacket *pkt)
+{
+       static char buf[NETPKTBUFSIZE];
+       static int buf_count = 0;
+       int rc;
+       int retval = 0;
+
+       if (SDLNet_CheckSockets(ss, 0) > 0) {
+               rc = SDLNet_TCP_Recv(s, &buf[buf_count], NETPKTBUFSIZE - buf_count);
+               if (rc <= 0) {  /* closed connection? */
+                       retval = -1;
+               } else if (rc != NETPKTBUFSIZE) {
+                       buf_count = rc;
+               } else {
+                       buf_count = 0;
+                       bufToPacket(buf, pkt);
+                       retval = 1;
+               }
+       }
+
+       return(retval);
+}
+
+
+int serverRecvPacket(NetPacket *pkt)
+{
+       int rc;
+       int i;
+
+       assert(is_server);
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               TCPsocket s = net_info[i].sock;
+
+               if ((i == client_player_num) || (!player[i].enabled))
+                       continue;
+
+               rc = grabPacket(s, net_info[i].socketset, pkt);
+               if (rc < 0) {
+                       NetPacket pkt;
+
+                       player[i].enabled = 0;
+                       SDLNet_TCP_Close(s);
+                       pkt.cmd = NETCMD_BYE;
+                       pkt.arg = i;
+                       pkt.arg2 = 0;
+                       pkt.arg3 = 0;
+                       pkt.arg4 = 0;
+                       sendPacketToAll(&pkt);
+               } else if (rc > 0) {
+                       return(i);  /* it's all good. */
+               }
+       }
+
+       return(-1);  /* no packets available currently. */
+}
+
+
+void wait_for_greenlight(void)
+{
+       NetPacket pkt;
+       int i;
+
+       printf("CLIENT: Waiting for greenlight...\n");
+
+       do {
+               int rc;
+               while ((rc = grabPacket(sock, socketset, &pkt)) == 0) {
+                       SDL_Delay(100);  /* nap and then try again. */
+               }
+
+               if (rc < 0) {
+                       printf("CLIENT: Lost connection.\n");
+                       SDLNet_TCP_Close(sock);
+                       exit(42);
+               }
+       } while (pkt.cmd != NETCMD_GREENLIGHT);
+
+       printf("CLIENT: Got greenlight.\n");
+
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               if (pkt.arg & (1 << i)) {
+                       printf("CLIENT: There is a player #%d.\n", i);
+                       player[i].enabled = 1;
+               }
+       }
+}
+
+
+static int buggered_off = 0;
+
+
+void tellServerGoodbye(void)
+{
+       NetPacket pkt;
+
+       if (!buggered_off) {
+               buggered_off = 1;
+               pkt.cmd = NETCMD_BYE;
+               pkt.arg = client_player_num;
+               pkt.arg2 = 0;
+               pkt.arg3 = 0;
+               pkt.arg4 = 0;
+               sendPacketToSock(sock, &pkt);
+       }
+}
+#endif /* USE_NET */
+
+
+void processMovePacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+       int movetype = ((pkt->arg2 >> 16) & 0xFF);
+       int newval   = ((pkt->arg2 >>  0) & 0xFF);
+
+       if (movetype == MOVEMENT_LEFT) {
+               player[playerid].action_left = newval;
+       } else if (movetype == MOVEMENT_RIGHT) {
+               player[playerid].action_right = newval;
+       } else if (movetype == MOVEMENT_UP) {
+               player[playerid].action_up = newval;
+       } else {
+               printf("bogus MOVE packet!\n");
+       }
+
+       player[playerid].x = pkt->arg3;
+       player[playerid].y = pkt->arg4;
+}
+
+
+void tellServerPlayerMoved(int playerid, int movement_type, int newval)
+{
+       NetPacket pkt;
+
+       pkt.cmd = NETCMD_MOVE;
+       pkt.arg = playerid;
+       pkt.arg2 = ( ((movement_type & 0xFF) << 16) | ((newval & 0xFF) << 0) );
+       pkt.arg3 = player[playerid].x;
+       pkt.arg4 = player[playerid].y;
+
+       if (is_server) {
+               processMovePacket(&pkt);
+#ifdef USE_NET
+               if (is_net)
+                       sendPacketToAll(&pkt);
+       } else {
+               sendPacketToSock(sock, &pkt);
+#endif
+       }
+}
+
+
+#ifdef USE_NET
+void tellServerNewPosition(void)
+{
+       NetPacket pkt;
+       pkt.cmd = NETCMD_POSITION;
+       pkt.arg = client_player_num;
+       pkt.arg2 = player[client_player_num].x;
+       pkt.arg3 = player[client_player_num].y;
+
+       if (is_server) {
+               sendPacketToAll(&pkt);
+       } else {
+               sendPacketToSock(sock, &pkt);
+       }
+}
+#endif /* USE_NET */
+
+
+void processKillPacket(NetPacket *pkt)
+{
+       int c1 = pkt->arg;
+       int c2 = pkt->arg2;
+       int x = pkt->arg3;
+       int y = pkt->arg4;
+       int c4 = 0;
+       int s1 = 0;
+
+       player[c1].y_add = -player[c1].y_add;
+       if (player[c1].y_add > -262144L)
+               player[c1].y_add = -262144L;
+       player[c1].jump_abort = 1;
+       player[c2].dead_flag = 1;
+       if (player[c2].anim != 6) {
+               player[c2].anim = 6;
+               player[c2].frame = 0;
+               player[c2].frame_tick = 0;
+               player[c2].image = player_anims[player[c2].anim].frame[player[c2].frame].image + player[c2].direction * 9;
+               if (main_info.no_gore == 0) {
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FUR, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 44 + c2 * 8);
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 76);
+                       for (c4 = 0; c4 < 6; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 77);
+                       for (c4 = 0; c4 < 8; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 78);
+                       for (c4 = 0; c4 < 10; c4++)
+                               add_object(OBJ_FLESH, (x >> 16) + 6 + rnd(5), (y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 79);
+               }
+               dj_play_sfx(SFX_DEATH, (unsigned short)(SFX_DEATH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
+               player[c1].bumps++;
+               player[c1].bumped[c2]++;
+               s1 = player[c1].bumps % 100;
+               add_leftovers(0, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
+               add_leftovers(1, 360, 34 + c1 * 64, s1 / 10, &number_gobs);
+               add_leftovers(0, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+               add_leftovers(1, 376, 34 + c1 * 64, s1 - (s1 / 10) * 10, &number_gobs);
+       }
+}
+
+
+#ifdef USE_NET
+void processPositionPacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+
+       player[playerid].x = pkt->arg2;
+       player[playerid].y = pkt->arg3;
+}
+
+
+void processAlivePacket(NetPacket *pkt)
+{
+       int playerid = pkt->arg;
+
+       player[playerid].dead_flag = 0;
+       player[playerid].x = pkt->arg2;
+       player[playerid].y = pkt->arg3;
+}
+
+
+void serverTellEveryoneGoodbye(void)
+{
+       int i;
+
+       if (!buggered_off) {
+               buggered_off = 1;
+               for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+                       if (player[i].enabled) {
+                               NetPacket pkt;
+
+                               pkt.cmd = NETCMD_BYE;
+                               pkt.arg = i;
+                               pkt.arg2 = 0;
+                               pkt.arg3 = 0;
+                               pkt.arg4 = 0;
+                               sendPacketToAll(&pkt);
+                       }
+               }
+       }
+}
+
+
+int server_said_bye = 0;
+
+
+int update_players_from_server(void)
+{
+       NetPacket pkt;
+       int rc;
+
+       assert(!is_server);
+
+       while ((rc = grabPacket(sock, socketset, &pkt)) != 0) {
+               if (rc < 0) {
+                       printf("CLIENT: Lost connection.\n");
+                       pkt.cmd = NETCMD_BYE;
+                       pkt.arg = client_player_num;
+               }
+
+               if (pkt.cmd == NETCMD_BYE) {
+                       if (pkt.arg == client_player_num) {
+                               SDLNet_FreeSocketSet(socketset);
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                               server_said_bye = 1;
+                               return(0);
+                       } else {
+                               player[pkt.arg].enabled = 0;
+                       }
+               } else if (pkt.cmd == NETCMD_MOVE) {
+                       processMovePacket(&pkt);
+               } else if (pkt.cmd == NETCMD_ALIVE) {
+                       processAlivePacket(&pkt);
+               } else if (pkt.cmd == NETCMD_POSITION) {
+                       processPositionPacket(&pkt);
+               } else if (pkt.cmd == NETCMD_KILL) {
+                       processKillPacket(&pkt);
+               } else {
+                       printf("CLIENT: Got an unknown packet: 0x%lX.\n", pkt.cmd);
+               }
+       }
+
+       return(1);
+}
+
+
+void serverSendAlive(int playerid)
+{
+       NetPacket pkt;
+
+       assert(is_server);
+       pkt.cmd = NETCMD_ALIVE;
+       pkt.arg = playerid;
+       pkt.arg2 = player[playerid].x;
+       pkt.arg3 = player[playerid].y;
+       sendPacketToAll(&pkt);
+}
+#endif /* USE_NET */
+
+
+void serverSendKillPacket(int killer, int victim)
+{
+       NetPacket pkt;
+
+       assert(is_server);
+       pkt.cmd = NETCMD_KILL;
+       pkt.arg = killer;
+       pkt.arg2 = victim;
+       pkt.arg3 = player[victim].x;
+       pkt.arg4 = player[victim].y;
+       processKillPacket(&pkt);
+#ifdef USE_NET
+       if (is_net)
+               sendPacketToAll(&pkt);
+#endif
+}
+
+
+#ifdef USE_NET
+void update_players_from_clients(void)
+{
+       int i;
+       NetPacket pkt;
+       int playerid;
+
+       assert(is_server);
+
+       while ((playerid = serverRecvPacket(&pkt)) >= 0) {
+               if (pkt.cmd == NETCMD_BYE) {
+                       pkt.arg = playerid;  /* just in case. */
+                       sendPacketToAll(&pkt);
+                       player[playerid].enabled = 0;
+                       SDLNet_FreeSocketSet(net_info[playerid].socketset);
+                       SDLNet_TCP_Close(net_info[playerid].sock);
+               } else if (pkt.cmd == NETCMD_POSITION) {
+                       pkt.arg = playerid;  /* just in case. */
+                       processPositionPacket(&pkt);
+                       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+                               if (i != playerid) {
+                                       sendPacket(i, &pkt);
+                               }
+                       }
+               } else if (pkt.cmd == NETCMD_MOVE) {
+                       pkt.arg = playerid;  /* just in case. */
+                       /*
+                       pkt.arg3 = player[playerid].x;
+                       pkt.arg4 = player[playerid].y;
+                       */
+                       processMovePacket(&pkt);
+                       sendPacketToAll(&pkt);
+               } else {
+                       printf("SERVER: Got unknown packet (0x%lX).\n", pkt.cmd);
+               }
+       }
+}
+
+
+void init_server(const char *netarg)
+{
+       NetPacket pkt;
+       IPaddress addr;
+       int i;
+       int wait_for_clients = ((netarg == NULL) ? 0 : atoi(netarg));
+       char *ipstr;
+
+       if ((wait_for_clients > (JNB_MAX_PLAYERS - 1)) || (wait_for_clients < 0)) {
+               printf("SERVER: Waiting for bogus client count (%d).\n", wait_for_clients);
+               exit(42);
+       }
+
+       if (SDLNet_Init() < 0) {
+               exit(42);
+       }
+       atexit(SDLNet_Quit);
+       
+       SDLNet_ResolveHost(&addr, NULL, JNB_INETPORT);
+       ipstr = SDLNet_ResolveIP(&addr);
+       SDLNet_ResolveHost(&addr, ipstr, JNB_INETPORT);
+       printf("SERVER: we are %s (%i.%i.%i.%i:%i).\n", ipstr, (addr.host >> 0) & 0xff, (addr.host >> 8) & 0xff, (addr.host >> 16) & 0xff, (addr.host >> 24) & 0xff, addr.port);
+       net_info[client_player_num].addr = addr;
+
+       addr.host = INADDR_ANY;
+       sock = SDLNet_TCP_Open(&addr);
+       if (sock == NULL) {
+               fprintf(stderr, "SERVER: SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       player[client_player_num].enabled = 1;
+
+       printf("SERVER: waiting for (%d) clients...\n", wait_for_clients);
+
+       socketset = SDLNet_AllocSocketSet(JNB_MAX_PLAYERS + 1);
+       SDLNet_TCP_AddSocket(socketset, sock);
+
+       while (wait_for_clients > 0)
+       {
+               char buf[NETPKTBUFSIZE];
+               IPaddress *from;
+               int negatory = 1;
+               int br;
+               TCPsocket s;
+
+               /* Wait for events */
+               SDLNet_CheckSockets(socketset, ~0);
+               if ( SDLNet_SocketReady(sock) ) {
+                       s = SDLNet_TCP_Accept(sock);
+
+                       if (s == NULL)
+                       {
+                               fprintf(stderr, "SERVER: SDLNet_TCP_Accept(): %s", SDLNet_GetError());
+                               SDLNet_TCP_Close(sock);
+                               exit(42);
+                       }
+               } else
+                       continue;
+
+               br = SDLNet_TCP_Recv(s, buf, NETPKTBUFSIZE);
+               if (br < 0) {
+                       fprintf(stderr, "SERVER: SDLNet_TCP_Recv(): %s\n", SDLNet_GetError());
+                       SDLNet_TCP_Close(s);
+                       SDLNet_TCP_Close(sock);
+                       exit(42);
+               }
+
+               from = SDLNet_TCP_GetPeerAddress(s);
+               ipstr = SDLNet_ResolveIP(from);
+               printf("SERVER: Got data from %s (%i.%i.%i.%i:%i).\n", ipstr, (from->host >> 0) & 0xff, (from->host >> 8) & 0xff, (from->host >> 16) & 0xff, (from->host >> 24) & 0xff, from->port);
+
+               if (br != NETPKTBUFSIZE) {
+                       printf("SERVER: Bogus packet.\n");
+                       continue;
+               }
+
+               bufToPacket(buf, &pkt);
+               if (pkt.cmd != NETCMD_HELLO) {
+                       printf("SERVER: Bogus packet.\n");
+                       continue;
+               }
+
+               printf("SERVER: Client claims to be player #%ld.\n", pkt.arg);
+
+               if (pkt.arg > JNB_MAX_PLAYERS) {
+                       printf("SERVER:  (that's an invalid player number.)\n");
+               } else {
+                       if (player[pkt.arg].enabled) {
+                               printf("SERVER:  (that player number is already taken.)\n");
+                       } else {
+                               negatory = 0;
+                       }
+               }
+
+               if (negatory) {
+                       printf("SERVER: Forbidding connection.\n");
+                       pkt.cmd = NETCMD_NACK;
+                       sendPacketToSock(s, &pkt);
+                       SDLNet_TCP_Close(s);
+               } else {
+                       player[pkt.arg].enabled = 1;
+                       net_info[pkt.arg].sock = s;
+                       net_info[pkt.arg].addr = *from;
+                       net_info[pkt.arg].socketset = SDLNet_AllocSocketSet(1);
+                       SDLNet_TCP_AddSocket(net_info[pkt.arg].socketset, net_info[pkt.arg].sock);
+                       wait_for_clients--;
+                       printf("SERVER: Granting connection. (%d) to go.\n", wait_for_clients);
+                       pkt.cmd = NETCMD_ACK;
+                       sendPacket(pkt.arg, &pkt);
+               }
+       }
+
+       SDLNet_TCP_Close(sock);  /* done with the listen socket. */
+       SDLNet_FreeSocketSet(socketset);
+       sock = NULL;
+       socketset = NULL;
+
+       printf("SERVER: Got all our connections. Greenlighting clients...\n");
+
+       pkt.cmd = NETCMD_GREENLIGHT;
+       pkt.arg = 0;
+       for (i = 0; i < JNB_MAX_PLAYERS; i++) {
+               if (player[i].enabled) {
+                       pkt.arg |= (1 << i);
+               }
+       }
+       sendPacketToAll(&pkt);
+}
+
+
+void connect_to_server(char *netarg)
+{
+       NetPacket pkt;
+       char buf[NETPKTBUFSIZE];
+       char *ipstr;
+       IPaddress hent;
+       IPaddress addr;
+       int br;
+
+       if (netarg == NULL) {
+               printf("CLIENT: Need to specify host to connect to.\n");
+               exit(42);
+       }
+
+       if (SDLNet_Init() < 0) {
+               exit(42);
+       }
+       atexit(SDLNet_Quit);
+       
+       player[client_player_num].enabled = 1;
+
+       SDLNet_ResolveHost(&addr, NULL, JNB_INETPORT);
+       ipstr = SDLNet_ResolveIP(&addr);
+       SDLNet_ResolveHost(&addr, ipstr, JNB_INETPORT);
+       printf("CLIENT: we are %s (%i.%i.%i.%i:%i).\n", ipstr, (addr.host >> 0) & 0xff, (addr.host >> 8) & 0xff, (addr.host >> 16) & 0xff, (addr.host >> 24) & 0xff, addr.port);
+       net_info[client_player_num].addr = addr;
+
+       if (SDLNet_ResolveHost(&hent, netarg, JNB_INETPORT) < 0) {
+               fprintf(stderr, "CLIENT: couldn't find host: %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       sock = SDLNet_TCP_Open(&hent);
+       if (sock == NULL) {
+               fprintf(stderr, "CLIENT: SDLNet_TCP_Open(): %s\n", SDLNet_GetError());
+               exit(42);
+       }
+
+       socketset = SDLNet_AllocSocketSet(1);
+       SDLNet_TCP_AddSocket(socketset, sock);
+
+       printf("CLIENT: connected to %s...\n", SDLNet_ResolveIP(&hent));
+
+       printf("CLIENT: Sending HELLO packet...\n");
+       pkt.cmd = NETCMD_HELLO;
+       pkt.arg = client_player_num;
+       sendPacketToSock(sock, &pkt);
+
+       printf("CLIENT: Waiting for ACK from server...\n");
+
+       br = SDLNet_TCP_Recv(sock, buf, NETPKTBUFSIZE);
+       if (br < 0) {
+               fprintf(stderr, "CLIENT: recv(): %s\n", SDLNet_GetError());
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       if (br != NETPKTBUFSIZE) {
+               printf("CLIENT: Bogus packet size (%d of %d). FIXME.\n", br, NETPKTBUFSIZE);
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       bufToPacket(buf, &pkt);
+
+       if (pkt.cmd == NETCMD_NACK) {
+               printf("CLIENT: Server forbid us from playing.\n");
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       if (pkt.cmd != NETCMD_ACK) {
+               printf("CLIENT: Unexpected packet (cmd=0x%lX).\n", pkt.cmd);
+               SDLNet_FreeSocketSet(socketset);
+               SDLNet_TCP_Close(sock);
+               exit(42);
+       }
+
+       printf("CLIENT: Server accepted our connection.\n");
+
+       wait_for_greenlight();
+}
+#endif /* USE_NET */
+
+
+static void flip_pixels(unsigned char *pixels)
+{
+       int x,y;
+       unsigned char temp;
+
+       assert(pixels);
+       for (y = 0; y < JNB_HEIGHT; y++) {
+               for (x = 0; x < (352/2); x++) {
+                       temp = pixels[y*JNB_WIDTH+x];
+                       pixels[y*JNB_WIDTH+x] = pixels[y*JNB_WIDTH+(352-x)-1];
+                       pixels[y*JNB_WIDTH+(352-x)-1] = temp;
+               }
+       }
+}
 
 
 int main(int argc, char *argv[])
 {
-       FILE *handle;
-       int c1, c2 = 0, c3, c4;
+       unsigned char *handle;
+       int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
        int l1;
        int s1, s2, s3, s4;
-       int closest_player = 0, dist, cur_dist;
-       char end_loop_flag, fade_flag;
-       char mod_vol, sfx_vol, mod_fade_direction;
-       char *ptr1 = (char *) NULL;
+       int closest_player = 0, dist, cur_dist = 0;
+       int end_loop_flag = 0, fade_flag = 0;
+       int mod_vol, sfx_vol, mod_fade_direction;
        char str1[100];
+       char pal[768];
+       char cur_pal[768];
+       int update_count;
 
-       if (init_program(argc, argv) != 0)
+       if (init_program(argc, argv, pal) != 0)
                deinit_program();
 
        if (main_info.fireworks == 1) {
@@ -200,44 +988,55 @@ int main(int argc, char *argv[])
 
        while (1) {
 
-               if (menu() != 0)
-                       deinit_program();
+               if (!is_net)
+                       if (menu() != 0)
+                               deinit_program();
 
                if (key_pressed(1) == 1) {
                        break;
                }
-               if (init_level(0) != 0) {
+               if (init_level(0, pal) != 0) {
                        deinit_level();
                        deinit_program();
                }
 
+               memset(cur_pal, 0, 768);
                setpalette(0, 256, cur_pal);
 
+               recalculate_gob(&rabbit_gobs, pal);
+               recalculate_gob(&object_gobs, pal);
+               recalculate_gob(&number_gobs, pal);
+
                flippage(1);
-               put_block(1, 0, 0, 400, 256, background_pic);
-               put_block(0, 0, 0, 400, 256, background_pic);
+               register_background(background_pic, pal);
                flippage(0);
 
-               s1 = rnd(250) + 50;
-               s2 = rnd(150) + 50;
-               for (c1 = 0; c1 < NUM_FLIES; c1++) {
-                       while (1) {
-                               flies[c1].x = s1 + rnd(101) - 50;
-                               flies[c1].y = s2 + rnd(101) - 50;
-                               if (ban_map[flies[c1].y >> 4][flies[c1].x >> 4] == 0)
-                                       break;
+               if (flies_enabled) {
+                       s1 = rnd(250) + 50;
+                       s2 = rnd(150) + 50;
+
+                       for (c1 = 0; c1 < NUM_FLIES; c1++) {
+                               while (1) {
+                                       flies[c1].x = s1 + rnd(101) - 50;
+                                       flies[c1].y = s2 + rnd(101) - 50;
+                                       if (ban_map[flies[c1].y >> 4][flies[c1].x >> 4] == BAN_VOID)
+                                               break;
+                               }
+                               flies[c1].back_defined[0] = 0;
+                               flies[c1].back_defined[1] = 0;
                        }
-                       flies[c1].back_defined[0] = 0;
-                       flies[c1].back_defined[1] = 0;
                }
 
                mod_vol = sfx_vol = 10;
                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;
@@ -247,464 +1046,453 @@ int main(int argc, char *argv[])
                main_info.view_page = 0;
                main_info.draw_page = 1;
 
+               update_count = 1;
                while (1) {
+                       while (update_count) {
 
-                       if (key_pressed(1) == 1) {
-                               end_loop_flag = 1;
-                               memset(pal, 0, 768);
-                               mod_fade_direction = 0;
-                       }
+                               if (key_pressed(1) == 1) {
+#ifdef USE_NET
+                                       if (is_net) {
+                                               if (is_server) {
+                                                       serverTellEveryoneGoodbye();
+                                               } else {
+                                                       tellServerGoodbye();
+                                               }
+                                       }
+#endif
+                                       end_loop_flag = 1;
+                                       memset(pal, 0, 768);
+                                       mod_fade_direction = 0;
+                               }
 
-                       if (strncmp(last_keys, "kcitsogop", strlen("kcitsogop")) == 0) {
-                               pogostick ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "ecapsniseinnub", strlen("ecapsniseinnub")) == 0) {
-                               bunnies_in_space ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "kcaptej", strlen("kcaptej")) == 0) {
-                               jetpack ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "seilfehtfodrol", strlen("seilfehtfodrol")) == 0) {
-                               lord_of_the_flies ^= 1;
-                               last_keys[0] = 0;
-                       }
-                       if (strncmp(last_keys, "retawnahtrekcihtsidoolb", strlen("retawnahtrekcihtsidoolb")) == 0) {
-                               blood_is_thicker_than_water ^= 1;
-                               if (blood_is_thicker_than_water == 1) {
-                                       pal[432] = 63;
-                                       pal[433] = 32;
-                                       pal[434] = 32;
-                                       pal[435] = 53;
-                                       pal[436] = 17;
-                                       pal[437] = 17;
-                                       pal[438] = 42;
-                                       pal[439] = 7;
-                                       pal[440] = 7;
-                                       pal[441] = 28;
-                                       pal[442] = 0;
-                                       pal[443] = 0;
-                                       pal[444] = 24;
-                                       pal[445] = 0;
-                                       pal[446] = 0;
-                                       pal[447] = 19;
-                                       pal[448] = 0;
-                                       pal[449] = 0;
-                                       pal[450] = 12;
-                                       pal[451] = 0;
-                                       pal[452] = 0;
-                                       pal[453] = 7;
-                                       pal[454] = 0;
-                                       pal[455] = 0;
-                               } else {
-                                       pal[432] = 63;
-                                       pal[433] = 63;
-                                       pal[434] = 63;
-                                       pal[435] = 40;
-                                       pal[436] = 53;
-                                       pal[437] = 62;
-                                       pal[438] = 19;
-                                       pal[439] = 42;
-                                       pal[440] = 60;
-                                       pal[441] = 0;
-                                       pal[442] = 33;
-                                       pal[443] = 60;
-                                       pal[444] = 3;
-                                       pal[445] = 32;
-                                       pal[446] = 46;
-                                       pal[447] = 3;
-                                       pal[448] = 26;
-                                       pal[449] = 33;
-                                       pal[450] = 3;
-                                       pal[451] = 19;
-                                       pal[452] = 21;
-                                       pal[453] = 1;
-                                       pal[454] = 8;
-                                       pal[455] = 8;
+                               if (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;
                                }
-                               last_keys[0] = 0;
-                       }
 
-                       steer_players();
+#ifdef USE_NET
+                               if (is_net) {
+                                       if (is_server) {
+                                               update_players_from_clients();
+                                       } else {
+                                               if (!update_players_from_server()) {
+                                                       break;  /* got a BYE packet */
+                                               }
+                                       }
+                               }
+#endif
 
-                       dj_mix();
+                               steer_players();
 
-                       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);
+                               dj_mix();
+
+                               for (c3 = 0; c3 < 6; c3++) {
+                                       if (c3 == 0) {
+                                               c1 = 0;
+                                               c2 = 1;
+                                       } else if (c3 == 1) {
+                                               c1 = 0;
+                                               c2 = 2;
+                                       } else if (c3 == 2) {
+                                               c1 = 0;
+                                               c2 = 3;
+                                       } else if (c3 == 3) {
+                                               c1 = 1;
+                                               c2 = 2;
+                                       } else if (c3 == 4) {
+                                               c1 = 1;
+                                               c2 = 3;
+                                       } else if (c3 == 5) {
+                                               c1 = 2;
+                                               c2 = 3;
+                                       }
+                                       if (player[c1].enabled == 1 && player[c2].enabled == 1) {
+                                               if (labs(player[c1].x - player[c2].x) < (12L << 16) && labs(player[c1].y - player[c2].y) < (12L << 16)) {
+                                                       if ((labs(player[c1].y - player[c2].y) >> 16) > 5) {
+                                                               if (player[c1].y < player[c2].y) {
+                                                                       if (player[c1].y_add >= 0) {
+                                                                               if (is_server)
+                                                                                       serverSendKillPacket(c1, c2);
+                                                                       } else {
+                                                                               if (player[c2].y_add < 0)
+                                                                                       player[c2].y_add = 0;
                                                                        }
                                                                } else {
-                                                                       if (player[c2].y_add < 0)
-                                                                               player[c2].y_add = 0;
+                                                                       if (player[c2].y_add >= 0) {
+                                                                               if (is_server)
+                                                                                       serverSendKillPacket(c2, c1);
+                                                                       } else {
+                                                                               if (player[c1].y_add < 0)
+                                                                                       player[c1].y_add = 0;
+                                                                       }
                                                                }
                                                        } else {
-                                                               if (player[c2].y_add >= 0) {
-                                                                       player[c2].y_add = -player[c2].y_add;
-                                                                       if (player[c2].y_add > -262144L)
-                                                                               player[c2].y_add = -262144L;
-                                                                       player[c2].jump_abort = 1;
-                                                                       player[c1].dead_flag = 1;
-                                                                       if (player[c1].anim != 6) {
-                                                                               player[c1].anim = 6;
-                                                                               player[c1].frame = 0;
-                                                                               player[c1].frame_tick = 0;
-                                                                               player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
-                                                                               if (main_info.no_gore == 0) {
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FUR, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 44 + c1 * 8);
-                                                                                       for (c4 = 0; c4 < 6; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 76);
-                                                                                       for (c4 = 0; c4 < 7; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 77);
-                                                                                       for (c4 = 0; c4 < 8; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 78);
-                                                                                       for (c4 = 0; c4 < 10; c4++)
-                                                                                               add_object(OBJ_FLESH, (player[c1].x >> 16) + 6 + rnd(5), (player[c1].y >> 16) + 6 + rnd(5), (rnd(65535) - 32768) * 3, (rnd(65535) - 32768) * 3, 0, 79);
-                                                                               }
-                                                                               dj_play_sfx(SFX_DEATH, 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);
 
-#ifdef DOS
-                       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;
-                                       }
-                               }
-                       }
-#else
-                       ptr1 = (char *) get_vgaptr(main_info.draw_page, 0, 0);
-                       for (c2 = 0; c2 < NUM_FLIES; c2++) {
-                               flies[c2].back[main_info.draw_page] = *(char *) (ptr1 + flies[c2].y * JNB_WIDTH + (flies[c2].x));
-                               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 * JNB_WIDTH + (flies[c2].x)) = 0;
-                       }
-#endif
+                                       dj_mix();
+
+                                       if (flies_enabled)
+                                               draw_flies(main_info.draw_page);
 
-                       if (mod_fade_direction == 1) {
-                               if (mod_vol < 30) {
-                                       mod_vol++;
-                                       dj_set_mod_volume(mod_vol);
+                                       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);
 
-                       flippage(main_info.view_page);
+                               if (update_count == 1) {
+                                       draw_begin();
 
-#ifdef DOS
-                       while ((inportb(0x3da) & 8) == 0)
-                               dj_mix();
-                       while ((inportb(0x3da) & 8) == 8)
-                               dj_mix();
-#endif
+                                       if (flies_enabled)
+                                               redraw_flies_background(main_info.draw_page);
 
-                       if (fade_flag == 1)
-                               setpalette(0, 256, cur_pal);
+                                       redraw_pob_backgrounds(main_info.draw_page);
 
-#ifdef DOS
-                       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];
+                                       draw_leftovers(main_info.draw_page);
+
+                                       draw_end();
                                }
+
+                               update_count--;
                        }
-#else
-                       ptr1 = (char *) get_vgaptr(main_info.draw_page, 0, 0);
-                       for (c2 = NUM_FLIES - 1; c2 >= 0; c2--) {
-                               if (flies[c2].back_defined[main_info.draw_page] == 1)
-                                       *(char *) (ptr1 + flies[c2].old_y * JNB_WIDTH + (flies[c2].old_x)) = flies[c2].back[main_info.draw_page];
+
+#ifdef USE_NET
+                       if (is_net) {
+                               if ( (player[client_player_num].dead_flag == 0) &&
+                                       (
+                                        (player[client_player_num].action_left) ||
+                                        (player[client_player_num].action_right) ||
+                                        (player[client_player_num].action_up) ||
+                                        (player[client_player_num].jump_ready == 0)
+                                       )
+                                  ) {
+                                       tellServerNewPosition();
+                               }
                        }
 #endif
 
-                       redraw_pob_backgrounds(main_info.draw_page);
+                       update_count = intr_sysupdate();
 
-                       draw_leftovers(main_info.draw_page);
+#ifdef USE_NET
+                       if (is_net) {
+                               if ((server_said_bye) || ((fade_flag == 0) && (end_loop_flag == 1)))
+                                       break;
+                       } else
+#endif
+                       if ((fade_flag == 0) && (end_loop_flag == 1))
+                               break;
+               }
 
-                       intr_sysupdate();
+#ifdef USE_NET
+               if (is_net) {
+                       if (is_server) {
+                               serverTellEveryoneGoodbye();
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                       } else {
+                               if (!server_said_bye) {
+                                       tellServerGoodbye();
+                               }
 
+                               SDLNet_TCP_Close(sock);
+                               sock = NULL;
+                       }
                }
-
-#ifndef DOS
+#endif
+               
                main_info.view_page = 0;
                main_info.draw_page = 1;
-#endif
 
                dj_stop_sfx_channel(4);
 
                deinit_level();
 
-               memset(mask_pic, 0, 102400L);
+               memset(mask_pic, 0, JNB_WIDTH*JNB_HEIGHT);
+               register_mask(mask_pic);
+
+               register_background(NULL, NULL);
+
+               draw_begin();
 
-#ifdef DOS
-               outportw(0x3c4, 0x0f02);
-               memset((char *) (0xa0000 + (long) (main_info.view_page << 15) + __djgpp_conventional_base), 0, 32768);
-#else
-               memset((void *) get_vgaptr(main_info.view_page, 0, 0), 0, JNB_WIDTH * JNB_HEIGHT);
-#endif
                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);
@@ -714,8 +1502,8 @@ int main(int argc, char *argv[])
                put_text(main_info.view_page, 40, 140, "FIZZ", 2);
                put_text(main_info.view_page, 40, 170, "MIJJI", 2);
 
-               for (c1 = 0; c1 < 4; c1++) {
-                       for (c2 = 0; c2 < 4; c2++) {
+               for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
+                       for (c2 = 0; c2 < JNB_MAX_PLAYERS; c2++) {
                                if (c2 != c1) {
                                        sprintf(str1, "%d", player[c1].bumped[c2]);
                                        put_text(main_info.view_page, 100 + c2 * 60, 80 + c1 * 30, str1, 2);
@@ -728,19 +1516,25 @@ int main(int argc, char *argv[])
 
                put_text(main_info.view_page, 200, 230, "Press ESC to continue", 2);
 
-#ifndef DOS
+               draw_end();
+
                flippage(main_info.view_page);
-#endif
 
                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);
+
+               /* fix dark font */
+               for (c1 = 0; c1 < 16; c1++) {
+                       pal[(240 + c1) * 3 + 0] = c1 << 2;
+                       pal[(240 + c1) * 3 + 1] = c1 << 2;
+                       pal[(240 + c1) * 3 + 2] = c1 << 2;
+               }
 
                memset(cur_pal, 0, 768);
 
@@ -748,22 +1542,23 @@ int main(int argc, char *argv[])
 
                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();
                        intr_sysupdate();
-                       wait_vrt();
+                       wait_vrt(0);
                        setpalette(0, 256, cur_pal);
+                       flippage(main_info.view_page);
                }
                while (key_pressed(1) == 1) {
                        dj_mix();
@@ -774,14 +1569,15 @@ int main(int argc, char *argv[])
 
                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();
+                       wait_vrt(0);
                        setpalette(0, 256, cur_pal);
+                       flippage(main_info.view_page);
                }
 
                fillpalette(0, 0, 0);
@@ -789,6 +1585,8 @@ int main(int argc, char *argv[])
                dj_set_nosound(1);
                dj_stop_mod();
 
+               if (is_net)
+                       break; /* don't go back to menu if in net game. */
        }
 
        deinit_program();
@@ -802,28 +1600,25 @@ void steer_players(void)
        int c1, c2;
        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 && ((key_pressed(KEY_PL3_LEFT) == 1 && key_pressed(KEY_PL3_RIGHT) == 1))) || (c1 == 3 && ((key_pressed(KEY_PL4_LEFT) == 1 && key_pressed(KEY_PL4_RIGHT) == 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 && key_pressed(KEY_PL3_RIGHT) == 1) || (c1 == 3 && key_pressed(KEY_PL4_RIGHT) == 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
@@ -831,7 +1626,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;
@@ -847,15 +1642,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 && key_pressed(KEY_PL3_LEFT) == 1) || (c1 == 3 && key_pressed(KEY_PL4_LEFT) == 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
@@ -863,7 +1658,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;
@@ -879,15 +1674,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 && key_pressed(KEY_PL3_LEFT) == 1) || (c1 == 3 && key_pressed(KEY_PL4_LEFT) == 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
@@ -895,7 +1690,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;
@@ -909,15 +1704,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 && key_pressed(KEY_PL3_RIGHT)) || (c1 == 3 && key_pressed(KEY_PL4_RIGHT))) {
+                               } 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
@@ -925,7 +1720,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;
@@ -939,10 +1734,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 && ((key_pressed(KEY_PL3_LEFT) == 0 && key_pressed(KEY_PL3_RIGHT) == 0))) || (c1 == 3 && ((key_pressed(KEY_PL4_LEFT) == 0 && key_pressed(KEY_PL4_RIGHT) == 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)
@@ -952,7 +1747,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) {
@@ -963,12 +1758,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 && key_pressed(KEY_PL3_JUMP) == 1) || (c1 == 3 && key_pressed(KEY_PL4_JUMP) == 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;
@@ -977,11 +1772,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;
@@ -991,12 +1786,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 && key_pressed(KEY_PL3_JUMP) == 0) || (c1 == 3 && key_pressed(KEY_PL4_JUMP) == 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)
@@ -1007,16 +1802,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 && key_pressed(KEY_PL3_JUMP) == 1) || (c1 == 3 && key_pressed(KEY_PL4_JUMP) == 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);
@@ -1036,26 +1828,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;
                                        }
@@ -1065,7 +1857,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;
@@ -1074,9 +1866,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;
@@ -1084,14 +1876,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;
@@ -1102,13 +1894,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;
@@ -1120,7 +1912,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;
@@ -1130,9 +1922,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;
@@ -1146,11 +1938,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;
@@ -1200,289 +1992,55 @@ void steer_players(void)
 
        }
 
-}
-
-
-void position_player(short player_num)
-{
-       int c1;
-       int s1, s2;
-
-       while (1) {
-               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))
-                               break;
-               }
-               for (c1 = 0; c1 < 4; 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;
-                       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;
-                       player[player_num].direction = 0;
-                       player[player_num].jump_ready = 1;
-                       player[player_num].in_water = 0;
-                       player[player_num].anim = 0;
-                       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];
-
-#ifdef DOS
-       outportw(0x3c4, 0x0f02);
-       memset((char *) (0xa0000 - __djgpp_base_address), 0, 65535);
-#else
-       memset((char *) get_vgaptr(0, 0, 0), 0, JNB_WIDTH * JNB_HEIGHT);
-#endif
-
-       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));
-
-       fillpalette(0, 0, 0);
-
-#ifdef DOS
-       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);
-               }
-       }
-#else
-       for (c2 = 193; c2 < 256; c2++) {
-               memset((void *) get_vgaptr(0, 0, c2), (c2 - 192) >> 2, 400);
-       }
-#endif
-
-       setpalette(0, 256, pal);
-
-       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;
-#ifdef DOS
-               outportw(0x3ce, ((s1 & 3) << 8) + 0x04);
-               stars[c1].back[0] = stars[c1].back[1] = *(char *) (0xa0000 + s2 * 100 + (s1 >> 2) - __djgpp_base_address);
-#else
-               stars[c1].back[0] = stars[c1].back[1] = *(char *) get_vgaptr(0, s1, s2);
-#endif
-       }
-
-       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();
-               intr_sysupdate();
-
-               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);
-                       }
-               }
-
-               dj_mix();
-
-               update_objects();
-
-               for (c1 = 0; c1 < 300; c1++) {
-#ifdef DOS
-                       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;
-#else
-                       stars[c1].back[main_info.draw_page] = *(char *) get_vgaptr(main_info.draw_page, stars[c1].x >> 16, stars[c1].y >> 16);
-                       *(char *) get_vgaptr(main_info.draw_page, stars[c1].x >> 16, stars[c1].y >> 16) = stars[c1].col;
-#endif
-               }
-
-               dj_mix();
-
-               draw_pobs(main_info.draw_page);
-
-               main_info.draw_page ^= 1;
-               main_info.view_page ^= 1;
-#ifdef DOS
-               outportw(0x3d4, (main_info.view_page << 23) + 0x0d);
-               outportw(0x3d4, ((main_info.view_page << 15) & 0xff00) + 0x0c);
-#else
-               flippage(main_info.view_page);
-#endif
+}
 
-#ifdef DOS
-               while ((inportb(0x3da) & 8) == 0)
-                       dj_mix();
-               while ((inportb(0x3da) & 8) == 8)
-                       dj_mix();
-#endif
 
-               redraw_pob_backgrounds(main_info.draw_page);
+void position_player(int player_num)
+{
+       int c1;
+       int s1, s2;
 
-               dj_mix();
-               intr_sysupdate();
+       while (1) {
+               while (1) {
+                       s1 = rnd(22);
+                       s2 = rnd(16);
+                       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 < 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 == 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;
+                       player[player_num].direction = 0;
+                       player[player_num].jump_ready = 1;
+                       player[player_num].in_water = 0;
+                       player[player_num].anim = 0;
+                       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;
 
-               for (c1 = 299; c1 >= 0; c1--) {
-#ifdef DOS
-                       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];
-#else
-                       *(char *) get_vgaptr(main_info.draw_page, stars[c1].old_x >> 16, stars[c1].old_y >> 16) = stars[c1].back[main_info.draw_page];
+                       if (is_server) {
+#ifdef USE_NET
+                               if (is_net)
+                                       serverSendAlive(player_num);
 #endif
-               }
+                               player[player_num].dead_flag = 0;
+                       }
 
+                       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;
 
@@ -1528,7 +2086,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--;
@@ -1542,7 +2100,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;
@@ -1558,7 +2116,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:
@@ -1656,7 +2214,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)
@@ -1727,14 +2285,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:
@@ -1799,8 +2357,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;
                                                        }
@@ -1818,7 +2376,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--;
@@ -1832,7 +2390,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;
                        }
                }
@@ -1841,7 +2399,7 @@ void update_objects(void)
 }
 
 
-char add_pob(int 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)
@@ -1858,6 +2416,18 @@ char add_pob(int page, short x, short y, short image, char *pob_data)
 }
 
 
+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;
@@ -1867,25 +2437,41 @@ void draw_pobs(int page)
 
        for (c1 = main_info.page_info[page].num_pobs - 1; c1 >= 0; c1--) {
                main_info.page_info[page].pobs[c1].back_buf_ofs = back_buf_ofs;
-               get_block(page, main_info.page_info[page].pobs[c1].x - pob_hs_x(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), main_info.page_info[page].pobs[c1].y - pob_hs_y(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_width(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), pob_height(main_info.page_info[page].pobs[c1].image, main_info.page_info[page].pobs[c1].pob_data), (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_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(int 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)
@@ -1914,9 +2500,9 @@ void draw_leftovers(int page)
 }
 
 
-char init_level(short level)
+int init_level(int level, char *pal)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
        int s1, s2;
 
@@ -1924,39 +2510,39 @@ char init_level(short level)
                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);
                }
        }
@@ -1964,7 +2550,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;
                }
@@ -1972,7 +2558,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;
                }
@@ -1980,7 +2566,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;
                }
@@ -1988,7 +2574,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;
                }
@@ -2006,12 +2592,96 @@ void deinit_level(void)
 }
 
 
-char init_program(int argc, char *argv[])
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+unsigned char *datafile_buffer = NULL;
+
+static void preread_datafile(const char *fname)
+{
+    int fd = 0;
+    int len;
+
+#ifdef ZLIB_SUPPORT
+    char *gzfilename = alloca(strlen(fname) + 4);
+    int bufsize = 0;
+    int bufpos = 0;
+    gzFile gzf;
+
+    strcpy(gzfilename, fname);
+    strcat(gzfilename, ".gz");
+
+    gzf = gzopen(gzfilename, "rb");
+    if (gzf != NULL) {
+        unsigned char *ptr;
+        do {
+            int br;
+            if (bufpos >= bufsize) {
+                bufsize += 1024 * 1024;
+                datafile_buffer = (unsigned char *) realloc(datafile_buffer, bufsize);
+                if (datafile_buffer == NULL) {
+                    perror("realloc()");
+                    exit(42);
+                }
+            }
+
+            br = gzread(gzf, datafile_buffer + bufpos, bufsize - bufpos);
+            if (br == -1) {
+                fprintf(stderr, "gzread failed.\n");
+                exit(42);
+            }
+
+            bufpos += br;
+        } while (!gzeof(gzf));
+
+        /* try to shrink buffer... */
+        ptr = (unsigned char *) realloc(datafile_buffer, bufpos);
+        if (ptr != NULL)
+            datafile_buffer = ptr;
+
+        gzclose(gzf);
+        return;
+    }
+
+    /* drop through and try for an uncompressed datafile... */
+#endif
+
+    fd = open(fname, O_RDONLY | O_BINARY);
+    if (fd == -1) {
+        fprintf(stderr, "can't open %s:", fname);
+       perror("");
+        exit(42);
+    }
+
+    len = filelength(fd);
+    datafile_buffer = (unsigned char *) malloc(len);
+    if (datafile_buffer == NULL) {
+        perror("malloc()");
+        close(fd);
+        exit(42);
+    }
+
+    if (read(fd, datafile_buffer, len) != len) {
+        perror("read()");
+        close(fd);
+        exit(42);
+    }
+
+    close(fd);
+}
+
+
+int init_program(int argc, char *argv[], char *pal)
 {
-       FILE *handle = (FILE *) NULL;
+       char *netarg = NULL;
+       unsigned char *handle = (unsigned char *) NULL;
        int c1 = 0, c2 = 0;
-       char load_flag = 0;
-       char force2, force3;
+       int load_flag = 0;
+       int force2, force3;
        sfx_data fly;
        int player_anim_data[] = {
                1, 0, 0, 0x7fff, 0, 0, 0, 0, 0, 0,
@@ -2023,6 +2693,10 @@ 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;
@@ -2034,9 +2708,8 @@ char init_program(int argc, char *argv[])
                return 1;
 
        memset(&main_info, 0, sizeof(main_info));
-       main_info.joy_enabled = 0;      /* CHANGE THIS FOR JOY */
 
-       strcpy(datfile_name, "data/jumpbump.dat");
+       strcpy(datfile_name, DATA_PATH);
 
        force2 = force3 = 0;
 
@@ -2044,8 +2717,12 @@ 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)
@@ -2054,13 +2731,38 @@ char init_program(int argc, char *argv[])
                        else if (stricmp(argv[c1], "-fullscreen") == 0)
                                fs_toggle();
 #endif
+                       else if (stricmp(argv[c1], "-scaleup") == 0)
+                               set_scaling(1);
+                       else if (stricmp(argv[c1], "-mirror") == 0)
+                               flip = 1;
                        else if (stricmp(argv[c1], "-dat") == 0) {
                                if (c1 < (argc - 1)) {
-                                       if ((handle = fopen(argv[c1 + 1], "rb")) != NULL) {
-                                               fclose(handle);
+                                       FILE *f;
+
+                                       if ((f = fopen(argv[c1 + 1], "rb")) != NULL) {
+                                               fclose(f);
                                                strcpy(datfile_name, argv[c1 + 1]);
                                        }
                                }
+                       } else if (stricmp(argv[c1], "-player") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       if (client_player_num < 0)
+                                               client_player_num = atoi(argv[c1 + 1]);
+                               }
+#ifdef USE_NET
+                       } else if (stricmp(argv[c1], "-server") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       is_server = 1;
+                                       is_net = 1;
+                                       netarg = argv[c1 + 1];
+                               }
+                       } else if (stricmp(argv[c1], "-connect") == 0) {
+                               if (c1 < (argc - 1)) {
+                                       is_server = 0;
+                                       is_net = 1;
+                                       netarg = argv[c1 + 1];
+                               }
+#endif
                        } else if (stricmp(argv[c1], "-mouse") == 0) {
                                if (c1 < (argc - 1)) {
                                        if (stricmp(argv[c1 + 1], "2") == 0)
@@ -2069,9 +2771,50 @@ 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 USE_NET
+                               printf("out");
+#endif
+                               printf(" network support.\n");
+                               return 1;
+                       }
+                       else if (strstr(argv[1],"-h")) {
+                               printf("Usage: jumpnbump [OPTION]...\n");
+                               printf("\n");
+                               printf("  -h                       this help\n");
+                               printf("  -v                       print version\n");
+                               printf("  -dat level.dat           play a different level\n");
+#ifdef USE_NET
+                               printf("  -server playercount      start as server waiting for players\n");
+                               printf("  -connect host            connect to server\n");
+#endif
+                               printf("  -player num              set main player to num (0-3). Needed for networking\n");
+                               printf("  -fireworks               screensaver mode\n");
+                               printf("  -fullscreen              run in fullscreen mode\n");
+                               printf("  -nosound                 play without sound\n");
+                               printf("  -nogore                  play without blood\n");
+                               printf("  -noflies                 disable flies\n");
+                               printf("  -mirror                  play with mirrored level\n");
+                               printf("  -scaleup                 play with doubled resolution (800x512)\n");
+                               printf("  -musicnosound            play with music but without sound\n");
+                               printf("\n");
+                               return 1;
+                       }
                }
        }
 
+       preread_datafile(datfile_name);
+
+       if (is_net) {
+               if (client_player_num < 0)
+                       client_player_num = 0;
+               player[client_player_num].enabled = 1;
+       }
+
+       main_info.pob_backbuf[0] = malloc(screen_pitch*screen_height*bytes_per_pixel);
+       main_info.pob_backbuf[1] = malloc(screen_pitch*screen_height*bytes_per_pixel);
+
        for (c1 = 0; c1 < 7; c1++) {
                player_anims[c1].num_frames = player_anim_data[c1 * 10];
                player_anims[c1].restart_frame = player_anim_data[c1 * 10 + 1];
@@ -2081,72 +2824,58 @@ char init_program(int argc, char *argv[])
                }
        }
 
-       if ((background_pic = malloc(102400)) == NULL)
-               return 1;
-       if ((mask_pic = malloc(102400)) == NULL)
+       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);
@@ -2166,7 +2895,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");
@@ -2176,7 +2904,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");
@@ -2186,7 +2913,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");
@@ -2196,7 +2922,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");
@@ -2206,7 +2931,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");
@@ -2216,7 +2940,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");
@@ -2226,7 +2949,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");
@@ -2236,7 +2958,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;
@@ -2247,132 +2968,107 @@ 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);
+
+       /* fix dark font */
+       for (c1 = 0; c1 < 16; c1++) {
+               pal[(240 + c1) * 3 + 0] = c1 << 2;
+               pal[(240 + c1) * 3 + 1] = c1 << 2;
+               pal[(240 + c1) * 3 + 2] = c1 << 2;
        }
-       fclose(handle);
 
        setpalette(0, 256, pal);
 
+       init_inputs();
+
+       recalculate_gob(&font_gobs, pal);
+
        if (main_info.joy_enabled == 1 && main_info.fireworks == 0) {
-               c1 = 0;
-#ifdef DOS
-               outportb(0x201, 0);
-               while (c1 < 0x7fff) {
-                       if ((inportb(0x201) & 1) == 0)
-                               break;
-                       c1++;
-               }
-#endif
-               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 {
-#ifdef DOS
-                               outportw(0x3c4, 0x0f02);
-                               memset((char *) (0xa0000 + 32768 + __djgpp_conventional_base), 0, 32768);
-#else
-                               memset((char *) get_vgaptr(1, 0, 0), 0, JNB_WIDTH * JNB_HEIGHT);
-#endif
-
-                               main_info.view_page = 1;
-#ifdef DOS
-                               outportw(0x3d4, (1 << 23) + 0x0d);
-                               outportw(0x3d4, ((1 << 15) & 0xff00) + 0x0c);
-#else
-                               flippage(main_info.view_page);
-#endif
-                               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 {
-#ifdef DOS
-                                       outportw(0x3c4, 0x0f02);
-                                       memset((char *) (0xa0000 + __djgpp_conventional_base), 0, 32768);
-                                       outportw(0x3d4, (0 << 23) + 0x0d);
-                                       outportw(0x3d4, ((0 << 15) & 0xff00) + 0x0c);
-#endif
-                                       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;
+               }
+       }
 
+#ifdef USE_NET
+       if (is_net) {
+               if (is_server) {
+                       init_server(netarg);
+               } else {
+                       connect_to_server(netarg);
+               }
        }
-#ifdef DOS
-       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
 #endif
-               main_info.mouse_enabled = 0;
 
        return 0;
 
 }
 
-
 void deinit_program(void)
 {
 #ifdef DOS
@@ -2387,18 +3083,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)
@@ -2413,6 +3097,9 @@ void deinit_program(void)
 
        if (main_info.error_str[0] != 0) {
                printf(main_info.error_str);
+#ifdef _MSC_VER
+               MessageBox(0, main_info.error_str, "Jump'n'Bump", 0);
+#endif
                exit(1);
        } else
                exit(0);
@@ -2420,213 +3107,21 @@ void deinit_program(void)
 }
 
 
-void read_joy(void)
-{
-       int c1;
-       int x, y;
-       int s1 = 0;
-       char flag;
-
-       c1 = x = y = flag = 0;
-#ifdef DOS
-       outportb(0x201, 0);
-#endif
-
-       while (1) {
-
-#ifdef DOS
-               s1 = inportb(0x201);
-#endif
-
-               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;
-
-#ifdef DOS
-               s1 = inportb(0x201);
-#endif
-               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 = 0;
-       int num_times;
-       char flag = 0;
-
-       while (joy.but1 == 1) {
-#ifdef DOS
-               s1 = inportb(0x201);
-#endif
-               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;
-#ifdef DOS
-               outportb(0x201, 0);
-#endif
-
-               while (1) {
-
-#ifdef DOS
-                       s1 = inportb(0x201);
-#endif
-
-                       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;
-
-#ifdef DOS
-               s1 = inportb(0x201);
-#endif
-               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) {
-#ifdef DOS
-                       s1 = inportb(0x201);
-#endif
-                       joy.but1 = (((s1 >> 4) & 1) ^ 1);
-               }
-
-       }
-
-       return 0;
-
-}
-
-
-void read_mouse(void)
-{
-
-#ifdef DOS
-       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;
-#endif
-
-}
-
-
 unsigned short rnd(unsigned short max)
 {
-       return (rand() % max);
+#if (RAND_MAX < 0x7fff)
+#error "rand returns too small values"
+#elif (RAND_MAX == 0x7fff)
+       return (unsigned short)((rand()*2) % (int)max);
+#else
+       return (unsigned short)(rand() % (int)max);
+#endif
 }
 
 
-char read_level(void)
+int read_level(void)
 {
-       FILE *handle;
+       unsigned char *handle;
        int c1, c2;
        int chr;
 
@@ -2638,47 +3133,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;
@@ -2687,33 +3194,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) );
 
-       num = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 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) {
-                       fseek(handle, 4, SEEK_CUR);
-                       len = fgetc(handle) + (fgetc(handle) << 8) + (fgetc(handle) << 16) + (fgetc(handle) << 24);
 
-                       fclose(handle);
+                       ptr += 4;
+                       len = ( (ptr[0] <<  0) +
+                               (ptr[1] <<  8) +
+                               (ptr[2] << 16) +
+                               (ptr[3] << 24) );
+
                        return len;
                }
-               fseek(handle, 8, SEEK_CUR);
+               ptr += 8;
        }
 
-       fclose(handle);
        return 0;
 }
 
+
 void write_calib_data(void)
 {
        FILE *handle;