kolibrios-fun/contrib/other/jumpnbump/main.c

3591 lines
95 KiB
C
Raw Normal View History

/*
* 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>
*
* 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>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#ifdef BZLIB_SUPPORT
#include "bzlib.h"
#endif
#ifdef ZLIB_SUPPORT
#include "zlib.h"
#endif
#ifdef USE_NET
#include "SDL_net.h"
#endif /* USE_NET */
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
gob_t rabbit_gobs = { 0 };
gob_t font_gobs = { 0 };
gob_t object_gobs = { 0 };
gob_t number_gobs = { 0 };
main_info_t main_info;
player_t player[JNB_MAX_PLAYERS];
player_anim_t player_anims[7];
object_t objects[NUM_OBJECTS];
joy_t joy;
mouse_t mouse;
char datfile_name[2048];
char *background_pic;
char *mask_pic;
int flip = 0;
char pal[768];
char cur_pal[768];
int ai[JNB_MAX_PLAYERS];
unsigned int ban_map[17][22] = {
{1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0},
{1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1},
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1},
{1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1},
{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
{1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
{2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 0, 0, 0, 0, 0, 1, 3, 3, 3, 1, 1, 1},
{2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
};
#define GET_BAN_MAP_XY(x,y) ban_map[(y) >> 4][(x) >> 4]
struct {
int num_frames;
int restart_frame;
struct {
int image;
int ticks;
} frame[10];
} object_anims[8] = {
{
6, 0, {
{
0, 3}, {
1, 3}, {
2, 3}, {
3, 3}, {
4, 3}, {
5, 3}, {
0, 0}, {
0, 0}, {
0, 0}, {
0, 0}
}
}, {
9, 0, {
{
6, 2}, {
7, 2}, {
8, 2}, {
9, 2}, {
10, 2}, {
11, 2}, {
12, 2}, {
13, 2}, {
14, 2}, {
0, 0}
}
}, {
5, 0, {
{
15, 3}, {
16, 3}, {
16, 3}, {
17, 3}, {
18, 3}, {
19, 3}, {
0, 0}, {
0, 0}, {
0, 0}, {
0, 0}
}
}, {
10, 0, {
{
20, 2}, {
21, 2}, {
22, 2}, {
23, 2}, {
24, 2}, {
25, 2}, {
24, 2}, {
23, 2}, {
22, 2}, {
21, 2}
}
}, {
10, 0, {
{
26, 2}, {
27, 2}, {
28, 2}, {
29, 2}, {
30, 2}, {
31, 2}, {
30, 2}, {
29, 2}, {
28, 2}, {
27, 2}
}
}, {
10, 0, {
{
32, 2}, {
33, 2}, {
34, 2}, {
35, 2}, {
36, 2}, {
37, 2}, {
36, 2}, {
35, 2}, {
34, 2}, {
33, 2}
}
}, {
10, 0, {
{
38, 2}, {
39, 2}, {
40, 2}, {
41, 2}, {
42, 2}, {
43, 2}, {
42, 2}, {
41, 2}, {
40, 2}, {
39, 2}
}
}, {
4, 0, {
{
76, 4}, {
77, 4}, {
78, 4}, {
79, 4}, {
0, 0}, {
0, 0}, {
0, 0}, {
0, 0}, {
0, 0}, {
0, 0}
}
}
};
int flies_enabled = 1;
struct {
int x, y;
int old_x, old_y;
int old_draw_x, old_draw_y;
int back[2];
int back_defined[2];
} flies[NUM_FLIES];
struct {
struct {
short num_pobs;
struct {
int x, y;
int image;
gob_t *pob_data;
} pobs[NUM_LEFTOVERS];
} page[2];
} leftovers;
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(*((Uint32*) (buf + 0)), &pkt->cmd);
SDLNet_Write32(*((Uint32*) (buf + 4)), &pkt->arg);
SDLNet_Write32(*((Uint32*) (buf + 8)), &pkt->arg2);
SDLNet_Write32(*((Uint32*) (buf + 12)), &pkt->arg3);
SDLNet_Write32(*((Uint32*) (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)
{
*((Uint32*) (buf + 0)) = SDLNet_Read32(&pkt->cmd);
*((Uint32*) (buf + 4)) = SDLNet_Read32(&pkt->arg);
*((Uint32*) (buf + 8)) = SDLNet_Read32(&pkt->arg2);
*((Uint32*) (buf + 12)) = SDLNet_Read32(&pkt->arg3);
*((Uint32*) (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) && (playerid >= 0)) {
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);
}
}
/** read a packet from the given TCPsocket
Returns -1 if some error occured, 0 if there was no data available and 1 if a
packet was successfully read.
Note: the socket has to be in the supplied socketset.
TODO: this function will bomb if a packet arrives in pieces, there is no
inherent guarantee that the next call will be made on the same socket. */
int grabPacket(TCPsocket s, SDLNet_SocketSet ss, NetPacket *pkt)
{
static char buf[NETPKTBUFSIZE];
static int buf_count = 0;
int rc;
if (SDLNet_CheckSockets(ss, 0) <= 0)
return 0;
if(!SDLNet_SocketReady(s))
return 0;
rc = SDLNet_TCP_Recv(s, &buf[buf_count], NETPKTBUFSIZE - buf_count);
if (rc <= 0) {
/* closed connection? */
return -1;
} else if (rc != NETPKTBUFSIZE) {
/* we got a partial packet. Store what we got in the static buffer and
return so that the next call can read the rest. Hopefully. */
buf_count = rc;
return 0;
} else {
buf_count = 0;
bufToPacket(buf, pkt);
return 1;
}
}
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;
/** assign player number zero as default for the server */
if(-1 == client_player_num)
client_player_num = 0;
if ((wait_for_clients >= JNB_MAX_PLAYERS) || (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 (-1 == pkt.arg) {
int i;
for(i=0; i!=JNB_MAX_PLAYERS; ++i) {
if(!player[i].enabled) {
printf("SERVER: assigning %d as player number\n", i);
pkt.arg = i;
break;
}
}
}
if ((pkt.arg>=JNB_MAX_PLAYERS)||(pkt.arg<0)) {
printf("SERVER: (that's an invalid player number.)\n");
} else if (player[pkt.arg].enabled) {
printf("SERVER: (that player number is already taken.)\n");
} else {
negatory = 0;
}
if (negatory) {
printf("SERVER: Forbidding connection.\n");
pkt.cmd = NETCMD_NACK;
sendPacketToSock(s, &pkt);
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);
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);
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);
}
client_player_num = pkt.arg;
player[client_player_num].enabled = 1;
net_info[client_player_num].addr = addr;
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;
}
}
}
void get_closest_player_to_point(int x,int y,int *dist,int *closest_player)
{
int c1;
int cur_dist = 0;
*dist = 0x7fff;
for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
if (player[c1].enabled == 1) {
cur_dist = (int)sqrt((x - ((player[c1].x >> 16) + 8)) * (x - ((player[c1].x >> 16) + 8)) + (y - ((player[c1].y >> 16) + 8)) * (y - ((player[c1].y >> 16) + 8)));
if (cur_dist < *dist) {
*closest_player = c1;
*dist = cur_dist;
}
}
}
}
static void update_flies(int update_count)
{
int c1;
int closest_player = 0, dist;
int s1, s2, s3, s4;
/* get center of fly swarm */
s1 = s2 = 0;
for (c1 = 0; c1 < NUM_FLIES; c1++) {
s1 += flies[c1].x;
s2 += flies[c1].y;
}
s1 /= NUM_FLIES;
s2 /= NUM_FLIES;
if (update_count == 1) {
/* get closest player to fly swarm */
get_closest_player_to_point(s1, s2, &dist, &closest_player);
/* update fly swarm sound */
s3 = 32 - dist / 3;
if (s3 < 0)
s3 = 0;
dj_set_sfx_channel_volume(4, (char)(s3));
}
for (c1 = 0; c1 < NUM_FLIES; c1++) {
/* get closest player to fly */
get_closest_player_to_point(flies[c1].x, flies[c1].y, &dist, &closest_player);
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)
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 (GET_BAN_MAP_XY(flies[c1].x + s4, flies[c1].y) != BAN_VOID)
s4 = 0;
flies[c1].x += s4;
s3 = 0;
if ((s2 - flies[c1].y) > 30)
s3 += 1;
else if ((s2 - flies[c1].y) < -30)
s3 -= 1;
if (dist < 30) {
if (((player[closest_player].y >> 16) + 8) > flies[c1].y) {
if (lord_of_the_flies == 0)
s3 -= 1;
else
s3 += 1;
} else {
if (lord_of_the_flies == 0)
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 (GET_BAN_MAP_XY(flies[c1].x, flies[c1].y + s4) != BAN_VOID)
s4 = 0;
flies[c1].y += s4;
}
}
static void player_kill(int c1, int c2)
{
if (player[c1].y_add >= 0) {
if (is_server)
serverSendKillPacket(c1, c2);
} else {
if (player[c2].y_add < 0)
player[c2].y_add = 0;
}
}
static void check_cheats(void)
{
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) {
char blood[32] = {
63,32,32,53,17,17,42, 7,
7,28, 0, 0,24, 0, 0,19,
0, 0,12, 0, 0, 7, 0, 0
};
char water[32] = {
63,63,63,40,53,62,19,42,
60, 0,33,60, 3,32,46, 3,
26,33, 3,19,21, 1, 8, 8
};
int i;
blood_is_thicker_than_water ^= 1;
if (blood_is_thicker_than_water == 1) {
for (i=0; i<32; i++)
pal[432+i] = blood[i];
} else {
for (i=0; i<32; i++)
pal[432+i] = water[i];
}
register_background(background_pic, pal);
recalculate_gob(&object_gobs, pal);
last_keys[0] = 0;
}
}
static void collision_check(void)
{
int c1 = 0, c2 = 0, c3 = 0;
int l1;
/* collision check */
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) {
player_kill(c1,c2);
} else {
player_kill(c2,c1);
}
} 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;
}
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;
}
}
}
}
}
}
static void game_loop(void) {
int mod_vol, sfx_vol;
int update_count = 1;
int end_loop_flag = 0;
int fade_flag = 0;
int update_palette = 0;
int mod_fade_direction;
int i;
mod_vol = sfx_vol = 0;
mod_fade_direction = 1;
dj_ready_mod(MOD_GAME);
dj_set_mod_volume((char)mod_vol);
dj_set_sfx_volume((char)mod_vol);
dj_start_mod();
intr_sysupdate();
while (1) {
while (update_count) {
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;
}
check_cheats();
#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
steer_players();
dj_mix();
collision_check();
dj_mix();
main_info.page_info[main_info.draw_page].num_pobs = 0;
for (i = 0; i < JNB_MAX_PLAYERS; i++) {
if (player[i].enabled == 1)
main_info.page_info[main_info.draw_page].num_pobs++;
}
update_objects();
dj_mix();
if (flies_enabled) {
update_flies(update_count);
}
dj_mix();
if (update_count == 1) {
int c2;
for (i = 0, c2 = 0; i < JNB_MAX_PLAYERS; i++) {
if (player[i].enabled == 1) {
main_info.page_info[main_info.draw_page].pobs[c2].x = player[i].x >> 16;
main_info.page_info[main_info.draw_page].pobs[c2].y = player[i].y >> 16;
main_info.page_info[main_info.draw_page].pobs[c2].image = player[i].image + i * 18;
main_info.page_info[main_info.draw_page].pobs[c2].pob_data = &rabbit_gobs;
c2++;
}
}
draw_begin();
draw_pobs(main_info.draw_page);
dj_mix();
if (flies_enabled)
draw_flies(main_info.draw_page);
draw_end();
}
if (mod_fade_direction == 1) {
if (mod_vol < 30) {
mod_vol++;
dj_set_mod_volume((char)mod_vol);
}
if (sfx_vol < 64) {
sfx_vol++;
dj_set_sfx_volume((char)sfx_vol);
}
} else {
if (mod_vol > 0) {
mod_vol--;
dj_set_mod_volume((char)mod_vol);
}
if (sfx_vol > 0) {
sfx_vol--;
dj_set_sfx_volume((char)sfx_vol);
}
}
fade_flag = 0;
for (i = 0; i < 768; i++) {
if (cur_pal[i] < pal[i]) {
cur_pal[i]++;
fade_flag = 1;
} else if (cur_pal[i] > pal[i]) {
cur_pal[i]--;
fade_flag = 1;
}
}
if (fade_flag == 1)
update_palette = 1;
if (fade_flag == 0 && end_loop_flag == 1)
break;
if (update_count == 1) {
if (update_palette == 1) {
setpalette(0, 256, cur_pal);
update_palette = 0;
}
main_info.draw_page ^= 1;
main_info.view_page ^= 1;
flippage(main_info.view_page);
wait_vrt(1);
draw_begin();
if (flies_enabled)
redraw_flies_background(main_info.draw_page);
redraw_pob_backgrounds(main_info.draw_page);
draw_leftovers(main_info.draw_page);
draw_end();
}
update_count--;
}
#ifdef USE_NET
if (is_net) {
if ( (player[client_player_num].dead_flag == 0) &&
(
(player[client_player_num].action_left) ||
(player[client_player_num].action_right) ||
(player[client_player_num].action_up) ||
(player[client_player_num].jump_ready == 0)
)
) {
tellServerNewPosition();
}
}
#endif
update_count = intr_sysupdate();
#ifdef USE_NET
if (is_net) {
if ((server_said_bye) || ((fade_flag == 0) && (end_loop_flag == 1)))
break;
} else
#endif
if ((fade_flag == 0) && (end_loop_flag == 1))
break;
}
}
static int menu_loop(void)
{
unsigned char *handle;
int mod_vol;
int c1, c2;
int s1, s2;
for(c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) // reset player values
{
ai[c1] = 0;
}
while (1) {
if (!is_net)
if (menu() != 0)
deinit_program();
if (key_pressed(1) == 1) {
return 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);
register_background(background_pic, pal);
flippage(0);
if (flies_enabled) {
s1 = rnd(250) + 50;
s2 = rnd(150) + 50;
for (c1 = 0; c1 < NUM_FLIES; c1++) {
while (1) {
flies[c1].x = s1 + rnd(101) - 50;
flies[c1].y = s2 + rnd(101) - 50;
if (GET_BAN_MAP_XY(flies[c1].x, flies[c1].y) == BAN_VOID)
break;
}
flies[c1].back_defined[0] = 0;
flies[c1].back_defined[1] = 0;
}
}
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;
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;
game_loop();
#ifdef USE_NET
if (is_net) {
if (is_server) {
serverTellEveryoneGoodbye();
SDLNet_TCP_Close(sock);
sock = NULL;
} else {
if (!server_said_bye) {
tellServerGoodbye();
}
SDLNet_TCP_Close(sock);
sock = NULL;
}
}
#endif
main_info.view_page = 0;
main_info.draw_page = 1;
dj_stop_sfx_channel(4);
deinit_level();
memset(mask_pic, 0, JNB_WIDTH*JNB_HEIGHT);
register_mask(mask_pic);
register_background(NULL, NULL);
draw_begin();
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);
put_text(main_info.view_page, 280, 50, "MIJJI", 2);
put_text(main_info.view_page, 40, 80, "DOTT", 2);
put_text(main_info.view_page, 40, 110, "JIFFY", 2);
put_text(main_info.view_page, 40, 140, "FIZZ", 2);
put_text(main_info.view_page, 40, 170, "MIJJI", 2);
for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
char str1[100];
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);
} else
put_text(main_info.view_page, 100 + c2 * 60, 80 + c1 * 30, "-", 2);
}
sprintf(str1, "%d", player[c1].bumps);
put_text(main_info.view_page, 350, 80 + c1 * 30, str1, 2);
}
put_text(main_info.view_page, 200, 230, "Press ESC to continue", 2);
draw_end();
flippage(main_info.view_page);
if ((handle = dat_open("menu.pcx")) == 0) {
strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
return 1;
}
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;
}
/* 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);
setpalette(0, 256, cur_pal);
mod_vol = 0;
dj_ready_mod(MOD_SCORES);
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((char)mod_vol);
for (c1 = 0; c1 < 768; c1++) {
if (cur_pal[c1] < pal[c1])
cur_pal[c1]++;
}
dj_mix();
intr_sysupdate();
wait_vrt(0);
setpalette(0, 256, cur_pal);
flippage(main_info.view_page);
}
while (key_pressed(1) == 1) {
dj_mix();
intr_sysupdate();
}
memset(pal, 0, 768);
while (mod_vol > 0) {
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(0);
setpalette(0, 256, cur_pal);
flippage(main_info.view_page);
}
fillpalette(0, 0, 0);
dj_set_nosound(1);
dj_stop_mod();
if (is_net)
return 0; /* don't go back to menu if in net game. */
}
}
int main(int argc, char *argv[])
{
int result;
if (init_program(argc, argv, pal) != 0)
deinit_program();
if (main_info.fireworks == 1) {
fireworks();
deinit_program();
}
result = menu_loop();
deinit_program();
return result;
}
static void player_action_left(int c1)
{
int s1 = 0, s2 = 0;
int below_left, below, below_right;
s1 = (player[c1].x >> 16);
s2 = (player[c1].y >> 16);
below_left = GET_BAN_MAP_XY(s1, s2 + 16);
below = GET_BAN_MAP_XY(s1 + 8, s2 + 16);
below_right = GET_BAN_MAP_XY(s1 + 15, s2 + 16);
if (below == BAN_ICE) {
if (player[c1].x_add > 0)
player[c1].x_add -= 1024;
else
player[c1].x_add -= 768;
} else if ((below_left != BAN_SOLID && below_right == BAN_ICE) || (below_left == BAN_ICE && below_right != BAN_SOLID)) {
if (player[c1].x_add > 0)
player[c1].x_add -= 1024;
else
player[c1].x_add -= 768;
} else {
if (player[c1].x_add > 0) {
player[c1].x_add -= 16384;
if (player[c1].x_add > -98304L && player[c1].in_water == 0 && below == 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;
}
if (player[c1].x_add < -98304L)
player[c1].x_add = -98304L;
player[c1].direction = 1;
if (player[c1].anim == 0) {
player[c1].anim = 1;
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;
}
}
static void player_action_right(int c1)
{
int s1 = 0, s2 = 0;
int below_left, below, below_right;
s1 = (player[c1].x >> 16);
s2 = (player[c1].y >> 16);
below_left = GET_BAN_MAP_XY(s1, s2 + 16);
below = GET_BAN_MAP_XY(s1 + 8, s2 + 16);
below_right = GET_BAN_MAP_XY(s1 + 15, s2 + 16);
if (below == BAN_ICE) {
if (player[c1].x_add < 0)
player[c1].x_add += 1024;
else
player[c1].x_add += 768;
} else if ((below_left != BAN_SOLID && below_right == BAN_ICE) || (below_left == BAN_ICE && below_right != BAN_SOLID)) {
if (player[c1].x_add > 0)
player[c1].x_add += 1024;
else
player[c1].x_add += 768;
} else {
if (player[c1].x_add < 0) {
player[c1].x_add += 16384;
if (player[c1].x_add < 98304L && player[c1].in_water == 0 && below == 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;
}
if (player[c1].x_add > 98304L)
player[c1].x_add = 98304L;
player[c1].direction = 0;
if (player[c1].anim == 0) {
player[c1].anim = 1;
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;
}
}
int map_tile(int pos_x, int pos_y)
{
int tile;
pos_x = pos_x >> 4;
pos_y = pos_y >> 4;
if(pos_x < 0 || pos_x >= 17 || pos_y < 0 || pos_y >= 22)
return BAN_VOID;
tile = ban_map[pos_y][pos_x];
return tile;
}
void cpu_move(void)
{
int lm, rm, jm;
int i, j;
int cur_posx, cur_posy, tar_posx, tar_posy;
int players_distance;
player_t* target = NULL;
int nearest_distance = -1;
for (i = 0; i < JNB_MAX_PLAYERS; i++)
{
nearest_distance = -1;
if(ai[i] && player[i].enabled) // this player is a computer
{ // get nearest target
for (j = 0; j < JNB_MAX_PLAYERS; j++)
{
int deltax, deltay;
if(i == j || !player[j].enabled)
continue;
deltax = player[j].x - player[i].x;
deltay = player[j].y - player[i].y;
players_distance = deltax*deltax + deltay*deltay;
if (players_distance < nearest_distance || nearest_distance == -1)
{
target = &player[j];
nearest_distance = players_distance;
}
}
if(target == NULL)
continue;
cur_posx = player[i].x >> 16;
cur_posy = player[i].y >> 16;
tar_posx = target->x >> 16;
tar_posy = target->y >> 16;
/** nearest player found, get him */
/* here goes the artificial intelligence code */
/* X-axis movement */
if(tar_posx > cur_posx) // if true target is on the right side
{ // go after him
lm=0;
rm=1;
}
else // target on the left side
{
lm=1;
rm=0;
}
if(cur_posy - tar_posy < 32 && cur_posy - tar_posy > 0 &&
tar_posx - cur_posx < 32+8 && tar_posx - cur_posx > -32)
{
lm = !lm;
rm = !rm;
}
else if(tar_posx - cur_posx < 4+8 && tar_posx - cur_posx > -4)
{ // makes the bunnies less "nervous"
lm=0;
lm=0;
}
/* Y-axis movement */
if(map_tile(cur_posx, cur_posy+16) != BAN_VOID &&
((i == 0 && key_pressed(KEY_PL1_JUMP)) ||
(i == 1 && key_pressed(KEY_PL2_JUMP)) ||
(i == 2 && key_pressed(KEY_PL3_JUMP)) ||
(i == 3 && key_pressed(KEY_PL4_JUMP))))
jm=0; // if we are on ground and jump key is being pressed,
//first we have to release it or else we won't be able to jump more than once
else if(map_tile(cur_posx, cur_posy-8) != BAN_VOID &&
map_tile(cur_posx, cur_posy-8) != BAN_WATER)
jm=0; // don't jump if there is something over it
else if(map_tile(cur_posx-(lm*8)+(rm*16), cur_posy) != BAN_VOID &&
map_tile(cur_posx-(lm*8)+(rm*16), cur_posy) != BAN_WATER &&
cur_posx > 16 && cur_posx < 352-16-8) // obstacle, jump
jm=1; // if there is something on the way, jump over it
else if(((i == 0 && key_pressed(KEY_PL1_JUMP)) ||
(i == 1 && key_pressed(KEY_PL2_JUMP)) ||
(i == 2 && key_pressed(KEY_PL3_JUMP)) ||
(i == 3 && key_pressed(KEY_PL4_JUMP))) &&
(map_tile(cur_posx-(lm*8)+(rm*16), cur_posy+8) != BAN_VOID &&
map_tile(cur_posx-(lm*8)+(rm*16), cur_posy+8) != BAN_WATER))
jm=1; // this makes it possible to jump over 2 tiles
else if(cur_posy - tar_posy < 32 && cur_posy - tar_posy > 0 &&
tar_posx - cur_posx < 32+8 && tar_posx - cur_posx > -32) // don't jump - running away
jm=0;
else if(tar_posy <= cur_posy) // target on the upper side
jm=1;
else // target below
jm=0;
/** Artificial intelligence done, now apply movements */
if(lm)
{
SDLKey key;
if(i == 0)
key = KEY_PL1_LEFT;
else if(i == 1)
key = KEY_PL2_LEFT;
else if(i == 2)
key = KEY_PL3_LEFT;
else
key = KEY_PL4_LEFT;
key &= 0x7f;
addkey(key);
}
else
{
SDLKey key;
if(i == 0)
key = KEY_PL1_LEFT;
else if(i == 1)
key = KEY_PL2_LEFT;
else if(i == 2)
key = KEY_PL3_LEFT;
else
key = KEY_PL4_LEFT;
key &= 0x7f;
addkey(key | 0x8000);
}
if(rm)
{
SDLKey key;
if(i == 0)
key = KEY_PL1_RIGHT;
else if(i == 1)
key = KEY_PL2_RIGHT;
else if(i == 2)
key = KEY_PL3_RIGHT;
else
key = KEY_PL4_RIGHT;
key &= 0x7f;
addkey(key);
}
else
{
SDLKey key;
if(i == 0)
key = KEY_PL1_RIGHT;
else if(i == 1)
key = KEY_PL2_RIGHT;
else if(i == 2)
key = KEY_PL3_RIGHT;
else
key = KEY_PL4_RIGHT;
key &= 0x7f;
addkey(key | 0x8000);
}
if(jm)
{
SDLKey key;
if(i == 0)
key = KEY_PL1_JUMP;
else if(i == 1)
key = KEY_PL2_JUMP;
else if(i == 2)
key = KEY_PL3_JUMP;
else
key = KEY_PL4_JUMP;
key &= 0x7f;
addkey(key);
}
else
{
SDLKey key;
if(i == 0)
key = KEY_PL1_JUMP;
else if(i == 1)
key = KEY_PL2_JUMP;
else if(i == 2)
key = KEY_PL3_JUMP;
else
key = KEY_PL4_JUMP;
key &= 0x7f;
addkey(key | 0x8000);
}
}
}
}
#define GET_BAN_MAP_IN_WATER(s1, s2) (GET_BAN_MAP_XY((s1), ((s2) + 7)) == BAN_VOID || GET_BAN_MAP_XY(((s1) + 15), ((s2) + 7)) == BAN_VOID) && (GET_BAN_MAP_XY((s1), ((s2) + 8)) == BAN_WATER || GET_BAN_MAP_XY(((s1) + 15), ((s2) + 8)) == BAN_WATER)
void steer_players(void)
{
int c1, c2;
int s1 = 0, s2 = 0;
cpu_move();
update_player_actions();
for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
if (player[c1].enabled == 1) {
if (player[c1].dead_flag == 0) {
if (player[c1].action_left && player[c1].action_right) {
if (player[c1].direction == 0) {
if (player[c1].action_right) {
player_action_right(c1);
}
} else {
if (player[c1].action_left) {
player_action_left(c1);
}
}
} else if (player[c1].action_left) {
player_action_left(c1);
} else if (player[c1].action_right) {
player_action_right(c1);
} else if ((!player[c1].action_left) && (!player[c1].action_right)) {
int below_left, below, below_right;
s1 = (player[c1].x >> 16);
s2 = (player[c1].y >> 16);
below_left = GET_BAN_MAP_XY(s1, s2 + 16);
below = GET_BAN_MAP_XY(s1 + 8, s2 + 16);
below_right = GET_BAN_MAP_XY(s1 + 15, s2 + 16);
if (below == BAN_SOLID || below == BAN_SPRING || (((below_left == BAN_SOLID || below_left == BAN_SPRING) && below_right != BAN_ICE) || (below_left != BAN_ICE && (below_right == BAN_SOLID || below_right == BAN_SPRING)))) {
if (player[c1].x_add < 0) {
player[c1].x_add += 16384;
if (player[c1].x_add > 0)
player[c1].x_add = 0;
} else {
player[c1].x_add -= 16384;
if (player[c1].x_add < 0)
player[c1].x_add = 0;
}
if (player[c1].x_add != 0 && GET_BAN_MAP_XY((s1 + 8), (s2 + 16)) == 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) {
player[c1].anim = 0;
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 (jetpack == 0) {
/* no jetpack */
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;
/* jump */
if (GET_BAN_MAP_XY(s1, (s2 + 16)) == BAN_SOLID || GET_BAN_MAP_XY(s1, (s2 + 16)) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), (s2 + 16)) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), (s2 + 16)) == BAN_ICE) {
player[c1].y_add = -280000L;
player[c1].anim = 2;
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;
player[c1].jump_ready = 0;
player[c1].jump_abort = 1;
if (pogostick == 0)
dj_play_sfx(SFX_JUMP, (unsigned short)(SFX_JUMP_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
else
dj_play_sfx(SFX_SPRING, (unsigned short)(SFX_SPRING_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
}
/* jump out of water */
if (GET_BAN_MAP_IN_WATER(s1, s2)) {
player[c1].y_add = -196608L;
player[c1].in_water = 0;
player[c1].anim = 2;
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;
player[c1].jump_ready = 0;
player[c1].jump_abort = 1;
if (pogostick == 0)
dj_play_sfx(SFX_JUMP, (unsigned short)(SFX_JUMP_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
else
dj_play_sfx(SFX_SPRING, (unsigned short)(SFX_SPRING_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
}
}
/* fall down by gravity */
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)
/* normal gravity */
player[c1].y_add += 32768;
else
/* light gravity */
player[c1].y_add += 16384;
if (player[c1].y_add > 0)
player[c1].y_add = 0;
}
}
} else {
/* with jetpack */
if (player[c1].action_up) {
player[c1].y_add -= 16384;
if (player[c1].y_add < -400000L)
player[c1].y_add = -400000L;
if (GET_BAN_MAP_IN_WATER(s1, s2))
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);
}
}
player[c1].x += player[c1].x_add;
if ((player[c1].x >> 16) < 0) {
player[c1].x = 0;
player[c1].x_add = 0;
}
if ((player[c1].x >> 16) + 15 > 351) {
player[c1].x = 336L << 16;
player[c1].x_add = 0;
}
{
if (player[c1].y > 0) {
s2 = (player[c1].y >> 16);
} else {
/* check top line only */
s2 = 0;
}
s1 = (player[c1].x >> 16);
if (GET_BAN_MAP_XY(s1, s2) == BAN_SOLID || GET_BAN_MAP_XY(s1, s2) == BAN_ICE || GET_BAN_MAP_XY(s1, s2) == BAN_SPRING || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_ICE || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SPRING) {
player[c1].x = (((s1 + 16) & 0xfff0)) << 16;
player[c1].x_add = 0;
}
s1 = (player[c1].x >> 16);
if (GET_BAN_MAP_XY((s1 + 15), s2) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), s2) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), s2) == BAN_SPRING || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SPRING) {
player[c1].x = (((s1 + 16) & 0xfff0) - 16) << 16;
player[c1].x_add = 0;
}
}
player[c1].y += player[c1].y_add;
s1 = (player[c1].x >> 16);
s2 = (player[c1].y >> 16);
if (GET_BAN_MAP_XY((s1 + 8), (s2 + 15)) == BAN_SPRING || ((GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SPRING && GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) != BAN_SOLID) || (GET_BAN_MAP_XY(s1, (s2 + 15)) != BAN_SOLID && GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SPRING))) {
player[c1].y = ((player[c1].y >> 16) & 0xfff0) << 16;
player[c1].y_add = -400000L;
player[c1].anim = 2;
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;
player[c1].jump_ready = 0;
player[c1].jump_abort = 0;
for (c2 = 0; c2 < NUM_OBJECTS; c2++) {
if (objects[c2].used == 1 && objects[c2].type == OBJ_SPRING) {
if (GET_BAN_MAP_XY((s1 + 8), (s2 + 15)) == 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;
objects[c2].image = object_anims[objects[c2].anim].frame[objects[c2].frame].image;
break;
}
} else {
if (GET_BAN_MAP_XY(s1, (s2 + 15)) == 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 (GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == 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;
objects[c2].image = object_anims[objects[c2].anim].frame[objects[c2].frame].image;
break;
}
}
}
}
}
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 (GET_BAN_MAP_XY(s1, s2) == BAN_SOLID || GET_BAN_MAP_XY(s1, s2) == BAN_ICE || GET_BAN_MAP_XY(s1, s2) == BAN_SPRING || GET_BAN_MAP_XY((s1 + 15), s2) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), s2) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), s2) == BAN_SPRING) {
player[c1].y = (((s2 + 16) & 0xfff0)) << 16;
player[c1].y_add = 0;
player[c1].anim = 0;
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;
}
s1 = (player[c1].x >> 16);
s2 = (player[c1].y >> 16);
if (s2 < 0)
s2 = 0;
if (GET_BAN_MAP_XY((s1 + 8), (s2 + 8)) == BAN_WATER) {
if (player[c1].in_water == 0) {
/* falling into water */
player[c1].in_water = 1;
player[c1].anim = 4;
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 (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, (unsigned short)(SFX_SPLASH_FREQ + rnd(2000) - 1000), 64, 0, 0, -1);
else
dj_play_sfx(SFX_SPLASH, (unsigned short)(SFX_SPLASH_FREQ + rnd(2000) - 5000), 64, 0, 0, -1);
}
}
/* slowly move up to water surface */
player[c1].y_add -= 1536;
if (player[c1].y_add < 0 && player[c1].anim != 5) {
player[c1].anim = 5;
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 (player[c1].y_add < -65536L)
player[c1].y_add = -65536L;
if (player[c1].y_add > 65535L)
player[c1].y_add = 65535L;
if (GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_ICE) {
player[c1].y = (((s2 + 16) & 0xfff0) - 16) << 16;
player[c1].y_add = 0;
}
} else if (GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_ICE || GET_BAN_MAP_XY(s1, (s2 + 15)) == BAN_SPRING || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SOLID || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_ICE || GET_BAN_MAP_XY((s1 + 15), (s2 + 15)) == BAN_SPRING) {
player[c1].in_water = 0;
player[c1].y = (((s2 + 16) & 0xfff0) - 16) << 16;
player[c1].y_add = 0;
if (player[c1].anim != 0 && player[c1].anim != 1) {
player[c1].anim = 0;
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;
}
} else {
if (player[c1].in_water == 0) {
if (bunnies_in_space == 0)
player[c1].y_add += 12288;
else
player[c1].y_add += 6144;
if (player[c1].y_add > 327680L)
player[c1].y_add = 327680L;
} else {
player[c1].y = (player[c1].y & 0xffff0000) + 0x10000;
player[c1].y_add = 0;
}
player[c1].in_water = 0;
}
if (player[c1].y_add > 36864 && player[c1].anim != 3 && player[c1].in_water == 0) {
player[c1].anim = 3;
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;
}
}
player[c1].frame_tick++;
if (player[c1].frame_tick >= player_anims[player[c1].anim].frame[player[c1].frame].ticks) {
player[c1].frame++;
if (player[c1].frame >= player_anims[player[c1].anim].num_frames) {
if (player[c1].anim != 6)
player[c1].frame = player_anims[player[c1].anim].restart_frame;
else
position_player(c1);
}
player[c1].frame_tick = 0;
}
player[c1].image = player_anims[player[c1].anim].frame[player[c1].frame].image + player[c1].direction * 9;
}
}
}
void position_player(int player_num)
{
int c1;
int s1, s2;
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;
if (is_server) {
#ifdef USE_NET
if (is_net)
serverSendAlive(player_num);
#endif
player[player_num].dead_flag = 0;
}
break;
}
}
}
void add_object(int type, int x, int y, int x_add, int y_add, int anim, int frame)
{
int c1;
for (c1 = 0; c1 < NUM_OBJECTS; c1++) {
if (objects[c1].used == 0) {
objects[c1].used = 1;
objects[c1].type = type;
objects[c1].x = (long) x << 16;
objects[c1].y = (long) y << 16;
objects[c1].x_add = x_add;
objects[c1].y_add = y_add;
objects[c1].x_acc = 0;
objects[c1].y_acc = 0;
objects[c1].anim = anim;
objects[c1].frame = frame;
objects[c1].ticks = object_anims[anim].frame[frame].ticks;
objects[c1].image = object_anims[anim].frame[frame].image;
break;
}
}
}
void update_objects(void)
{
int c1;
int s1 = 0;
for (c1 = 0; c1 < NUM_OBJECTS; c1++) {
if (objects[c1].used == 1) {
switch (objects[c1].type) {
case OBJ_SPRING:
objects[c1].ticks--;
if (objects[c1].ticks <= 0) {
objects[c1].frame++;
if (objects[c1].frame >= object_anims[objects[c1].anim].num_frames) {
objects[c1].frame--;
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
} else {
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
if (objects[c1].used == 1)
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--;
if (objects[c1].ticks <= 0) {
objects[c1].frame++;
if (objects[c1].frame >= object_anims[objects[c1].anim].num_frames)
objects[c1].used = 0;
else {
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
if (objects[c1].used == 1)
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;
objects[c1].y += objects[c1].y_add;
objects[c1].ticks--;
if (objects[c1].ticks <= 0) {
objects[c1].frame++;
if (objects[c1].frame >= object_anims[objects[c1].anim].num_frames)
objects[c1].used = 0;
else {
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
if (objects[c1].used == 1)
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:
objects[c1].x_acc += rnd(128) - 64;
if (objects[c1].x_acc < -1024)
objects[c1].x_acc = -1024;
if (objects[c1].x_acc > 1024)
objects[c1].x_acc = 1024;
objects[c1].x_add += objects[c1].x_acc;
if (objects[c1].x_add < -32768)
objects[c1].x_add = -32768;
if (objects[c1].x_add > 32768)
objects[c1].x_add = 32768;
objects[c1].x += objects[c1].x_add;
if ((objects[c1].x >> 16) < 16) {
objects[c1].x = 16 << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
objects[c1].x_acc = 0;
} else if ((objects[c1].x >> 16) > 350) {
objects[c1].x = 350 << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
objects[c1].x_acc = 0;
}
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 0) {
if (objects[c1].x_add < 0) {
objects[c1].x = (((objects[c1].x >> 16) + 16) & 0xfff0) << 16;
} else {
objects[c1].x = ((((objects[c1].x >> 16) - 16) & 0xfff0) + 15) << 16;
}
objects[c1].x_add = -objects[c1].x_add >> 2;
objects[c1].x_acc = 0;
}
objects[c1].y_acc += rnd(64) - 32;
if (objects[c1].y_acc < -1024)
objects[c1].y_acc = -1024;
if (objects[c1].y_acc > 1024)
objects[c1].y_acc = 1024;
objects[c1].y_add += objects[c1].y_acc;
if (objects[c1].y_add < -32768)
objects[c1].y_add = -32768;
if (objects[c1].y_add > 32768)
objects[c1].y_add = 32768;
objects[c1].y += objects[c1].y_add;
if ((objects[c1].y >> 16) < 0) {
objects[c1].y = 0;
objects[c1].y_add = -objects[c1].y_add >> 2;
objects[c1].y_acc = 0;
} else if ((objects[c1].y >> 16) > 255) {
objects[c1].y = 255 << 16;
objects[c1].y_add = -objects[c1].y_add >> 2;
objects[c1].y_acc = 0;
}
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 0) {
if (objects[c1].y_add < 0) {
objects[c1].y = (((objects[c1].y >> 16) + 16) & 0xfff0) << 16;
} else {
objects[c1].y = ((((objects[c1].y >> 16) - 16) & 0xfff0) + 15) << 16;
}
objects[c1].y_add = -objects[c1].y_add >> 2;
objects[c1].y_acc = 0;
}
if (objects[c1].type == OBJ_YEL_BUTFLY) {
if (objects[c1].x_add < 0 && objects[c1].anim != OBJ_ANIM_YEL_BUTFLY_LEFT) {
objects[c1].anim = OBJ_ANIM_YEL_BUTFLY_LEFT;
objects[c1].frame = 0;
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
} else if (objects[c1].x_add > 0 && objects[c1].anim != OBJ_ANIM_YEL_BUTFLY_RIGHT) {
objects[c1].anim = OBJ_ANIM_YEL_BUTFLY_RIGHT;
objects[c1].frame = 0;
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
} else {
if (objects[c1].x_add < 0 && objects[c1].anim != OBJ_ANIM_PINK_BUTFLY_LEFT) {
objects[c1].anim = OBJ_ANIM_PINK_BUTFLY_LEFT;
objects[c1].frame = 0;
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
} else if (objects[c1].x_add > 0 && objects[c1].anim != OBJ_ANIM_PINK_BUTFLY_RIGHT) {
objects[c1].anim = OBJ_ANIM_PINK_BUTFLY_RIGHT;
objects[c1].frame = 0;
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
objects[c1].ticks--;
if (objects[c1].ticks <= 0) {
objects[c1].frame++;
if (objects[c1].frame >= object_anims[objects[c1].anim].num_frames)
objects[c1].frame = object_anims[objects[c1].anim].restart_frame;
else {
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
if (objects[c1].used == 1)
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)
add_object(OBJ_FLESH_TRACE, objects[c1].x >> 16, objects[c1].y >> 16, 0, 0, OBJ_ANIM_FLESH_TRACE, 0);
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 0) {
objects[c1].y_add += 3072;
if (objects[c1].y_add > 196608L)
objects[c1].y_add = 196608L;
} else if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 2) {
if (objects[c1].x_add < 0) {
if (objects[c1].x_add < -65536L)
objects[c1].x_add = -65536L;
objects[c1].x_add += 1024;
if (objects[c1].x_add > 0)
objects[c1].x_add = 0;
} else {
if (objects[c1].x_add > 65536L)
objects[c1].x_add = 65536L;
objects[c1].x_add -= 1024;
if (objects[c1].x_add < 0)
objects[c1].x_add = 0;
}
objects[c1].y_add += 1024;
if (objects[c1].y_add < -65536L)
objects[c1].y_add = -65536L;
if (objects[c1].y_add > 65536L)
objects[c1].y_add = 65536L;
}
objects[c1].x += objects[c1].x_add;
if ((objects[c1].y >> 16) > 0 && (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 1 || ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 3)) {
if (objects[c1].x_add < 0) {
objects[c1].x = (((objects[c1].x >> 16) + 16) & 0xfff0) << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
} else {
objects[c1].x = ((((objects[c1].x >> 16) - 16) & 0xfff0) + 15) << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
}
}
objects[c1].y += objects[c1].y_add;
if ((objects[c1].x >> 16) < -5 || (objects[c1].x >> 16) > 405 || (objects[c1].y >> 16) > 260)
objects[c1].used = 0;
if ((objects[c1].y >> 16) > 0 && (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 0)) {
if (objects[c1].y_add < 0) {
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 2) {
objects[c1].y = (((objects[c1].y >> 16) + 16) & 0xfff0) << 16;
objects[c1].x_add >>= 2;
objects[c1].y_add = -objects[c1].y_add >> 2;
}
} else {
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 1) {
if (objects[c1].y_add > 131072L) {
objects[c1].y = ((((objects[c1].y >> 16) - 16) & 0xfff0) + 15) << 16;
objects[c1].x_add >>= 2;
objects[c1].y_add = -objects[c1].y_add >> 2;
} else
objects[c1].used = 0;
} else if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 3) {
objects[c1].y = ((((objects[c1].y >> 16) - 16) & 0xfff0) + 15) << 16;
if (objects[c1].y_add > 131072L)
objects[c1].y_add = -objects[c1].y_add >> 2;
else
objects[c1].y_add = 0;
}
}
}
if (objects[c1].x_add < 0 && objects[c1].x_add > -16384)
objects[c1].x_add = -16384;
if (objects[c1].x_add > 0 && objects[c1].x_add < 16384)
objects[c1].x_add = 16384;
if (objects[c1].used == 1) {
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);
}
break;
case OBJ_FLESH:
if (rnd(100) < 30) {
if (objects[c1].frame == 76)
add_object(OBJ_FLESH_TRACE, objects[c1].x >> 16, objects[c1].y >> 16, 0, 0, OBJ_ANIM_FLESH_TRACE, 1);
else if (objects[c1].frame == 77)
add_object(OBJ_FLESH_TRACE, objects[c1].x >> 16, objects[c1].y >> 16, 0, 0, OBJ_ANIM_FLESH_TRACE, 2);
else if (objects[c1].frame == 78)
add_object(OBJ_FLESH_TRACE, objects[c1].x >> 16, objects[c1].y >> 16, 0, 0, OBJ_ANIM_FLESH_TRACE, 3);
}
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 0) {
objects[c1].y_add += 3072;
if (objects[c1].y_add > 196608L)
objects[c1].y_add = 196608L;
} else if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 2) {
if (objects[c1].x_add < 0) {
if (objects[c1].x_add < -65536L)
objects[c1].x_add = -65536L;
objects[c1].x_add += 1024;
if (objects[c1].x_add > 0)
objects[c1].x_add = 0;
} else {
if (objects[c1].x_add > 65536L)
objects[c1].x_add = 65536L;
objects[c1].x_add -= 1024;
if (objects[c1].x_add < 0)
objects[c1].x_add = 0;
}
objects[c1].y_add += 1024;
if (objects[c1].y_add < -65536L)
objects[c1].y_add = -65536L;
if (objects[c1].y_add > 65536L)
objects[c1].y_add = 65536L;
}
objects[c1].x += objects[c1].x_add;
if ((objects[c1].y >> 16) > 0 && (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 1 || ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 3)) {
if (objects[c1].x_add < 0) {
objects[c1].x = (((objects[c1].x >> 16) + 16) & 0xfff0) << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
} else {
objects[c1].x = ((((objects[c1].x >> 16) - 16) & 0xfff0) + 15) << 16;
objects[c1].x_add = -objects[c1].x_add >> 2;
}
}
objects[c1].y += objects[c1].y_add;
if ((objects[c1].x >> 16) < -5 || (objects[c1].x >> 16) > 405 || (objects[c1].y >> 16) > 260)
objects[c1].used = 0;
if ((objects[c1].y >> 16) > 0 && (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 0)) {
if (objects[c1].y_add < 0) {
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] != 2) {
objects[c1].y = (((objects[c1].y >> 16) + 16) & 0xfff0) << 16;
objects[c1].x_add >>= 2;
objects[c1].y_add = -objects[c1].y_add >> 2;
}
} else {
if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 1) {
if (objects[c1].y_add > 131072L) {
objects[c1].y = ((((objects[c1].y >> 16) - 16) & 0xfff0) + 15) << 16;
objects[c1].x_add >>= 2;
objects[c1].y_add = -objects[c1].y_add >> 2;
} 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);
}
objects[c1].used = 0;
}
} else if (ban_map[objects[c1].y >> 20][objects[c1].x >> 20] == 3) {
objects[c1].y = ((((objects[c1].y >> 16) - 16) & 0xfff0) + 15) << 16;
if (objects[c1].y_add > 131072L)
objects[c1].y_add = -objects[c1].y_add >> 2;
else
objects[c1].y_add = 0;
}
}
}
if (objects[c1].x_add < 0 && objects[c1].x_add > -16384)
objects[c1].x_add = -16384;
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);
break;
case OBJ_FLESH_TRACE:
objects[c1].ticks--;
if (objects[c1].ticks <= 0) {
objects[c1].frame++;
if (objects[c1].frame >= object_anims[objects[c1].anim].num_frames)
objects[c1].used = 0;
else {
objects[c1].ticks = object_anims[objects[c1].anim].frame[objects[c1].frame].ticks;
objects[c1].image = object_anims[objects[c1].anim].frame[objects[c1].frame].image;
}
}
if (objects[c1].used == 1)
add_pob(main_info.draw_page, objects[c1].x >> 16, objects[c1].y >> 16, objects[c1].image, &object_gobs);
break;
}
}
}
}
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)
return 1;
main_info.page_info[page].pobs[main_info.page_info[page].num_pobs].x = x;
main_info.page_info[page].pobs[main_info.page_info[page].num_pobs].y = y;
main_info.page_info[page].pobs[main_info.page_info[page].num_pobs].image = image;
main_info.page_info[page].pobs[main_info.page_info[page].num_pobs].pob_data = pob_data;
main_info.page_info[page].num_pobs++;
return 0;
}
void draw_flies(int page)
{
int c2;
for (c2 = 0; c2 < NUM_FLIES; c2++) {
flies[c2].back[main_info.draw_page] = get_pixel(main_info.draw_page, flies[c2].x, flies[c2].y);
flies[c2].back_defined[main_info.draw_page] = 1;
if (mask_pic[(flies[c2].y * JNB_WIDTH) + flies[c2].x] == 0)
set_pixel(main_info.draw_page, flies[c2].x, flies[c2].y, 0);
}
}
void draw_pobs(int page)
{
int c1;
int back_buf_ofs;
back_buf_ofs = 0;
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), (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;
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);
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), (unsigned char *)main_info.pob_backbuf[page] + main_info.page_info[page].pobs[c1].back_buf_ofs);
}
int add_leftovers(int page, int x, int y, int image, gob_t *pob_data)
{
if (leftovers.page[page].num_pobs >= NUM_LEFTOVERS)
return 1;
leftovers.page[page].pobs[leftovers.page[page].num_pobs].x = x;
leftovers.page[page].pobs[leftovers.page[page].num_pobs].y = y;
leftovers.page[page].pobs[leftovers.page[page].num_pobs].image = image;
leftovers.page[page].pobs[leftovers.page[page].num_pobs].pob_data = pob_data;
leftovers.page[page].num_pobs++;
return 0;
}
void draw_leftovers(int page)
{
int c1;
for (c1 = leftovers.page[page].num_pobs - 1; c1 >= 0; c1--)
put_pob(page, leftovers.page[page].pobs[c1].x, leftovers.page[page].pobs[c1].y, leftovers.page[page].pobs[c1].image, leftovers.page[page].pobs[c1].pob_data, 1, mask_pic);
leftovers.page[page].num_pobs = 0;
}
int init_level(int level, char *pal)
{
unsigned char *handle;
int c1, c2;
int s1, s2;
if ((handle = dat_open("level.pcx")) == 0) {
strcpy(main_info.error_str, "Error loading 'level.pcx', aborting...\n");
return 1;
}
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;
}
if (flip)
flip_pixels(background_pic);
if ((handle = dat_open("mask.pcx")) == 0) {
strcpy(main_info.error_str, "Error loading 'mask.pcx', aborting...\n");
return 1;
}
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;
}
if (flip)
flip_pixels(mask_pic);
register_mask(mask_pic);
for (c1 = 0; c1 < JNB_MAX_PLAYERS; c1++) {
if (player[c1].enabled == 1) {
player[c1].bumps = 0;
for (c2 = 0; c2 < JNB_MAX_PLAYERS; c2++)
player[c1].bumped[c2] = 0;
position_player(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] == BAN_SPRING)
add_object(OBJ_SPRING, c2 << 4, c1 << 4, 0, 0, OBJ_ANIM_SPRING, 5);
}
}
while (1) {
s1 = rnd(22);
s2 = rnd(16);
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;
}
}
while (1) {
s1 = rnd(22);
s2 = rnd(16);
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;
}
}
while (1) {
s1 = rnd(22);
s2 = rnd(16);
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;
}
}
while (1) {
s1 = rnd(22);
s2 = rnd(16);
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;
}
}
return 0;
}
void deinit_level(void)
{
dj_set_nosound(1);
dj_stop_mod();
}
#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;
gzFile gzf;
#endif
#ifdef BZLIB_SUPPORT
char *bzfilename;
BZFILE *bzf;
#endif
#ifdef BZLIB_SUPPORT
bzfilename = malloc(strlen(fname) + 5);
strcpy(bzfilename, fname);
strcat(bzfilename, ".bz2");
bzf = BZ2_bzopen(bzfilename, "rb");
free(bzfilename);
bzfilename = NULL;
if (bzf != NULL) {
int bufsize = 0;
int bufpos = 0;
int br;
unsigned char *ptr;
do {
if (bufpos >= bufsize) {
bufsize += 1024 * 1024;
datafile_buffer = (unsigned char *) realloc(datafile_buffer, bufsize);
if (datafile_buffer == NULL) {
perror("realloc()");
exit(42);
}
}
br = BZ2_bzread(bzf, datafile_buffer + bufpos, bufsize - bufpos);
if (br == -1) {
fprintf(stderr, "gzread failed.\n");
exit(42);
}
bufpos += br;
} while (br>0);
/* try to shrink buffer... */
ptr = (unsigned char *) realloc(datafile_buffer, bufpos);
if (ptr != NULL)
datafile_buffer = ptr;
BZ2_bzclose(bzf);
return;
}
/* drop through and try for an gzip compressed or uncompressed datafile... */
#endif
#ifdef ZLIB_SUPPORT
gzfilename = malloc(strlen(fname) + 4);
strcpy(gzfilename, fname);
strcat(gzfilename, ".gz");
gzf = gzopen(gzfilename, "rb");
free(gzfilename);
gzfilename = NULL;
if (gzf != NULL) {
int bufsize = 0;
int bufpos = 0;
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)
{
char *netarg = NULL;
unsigned char *handle = (unsigned char *) NULL;
int c1 = 0, c2 = 0;
int load_flag = 0;
int force2, force3;
sfx_data fly;
int player_anim_data[] = {
1, 0, 0, 0x7fff, 0, 0, 0, 0, 0, 0,
4, 0, 0, 4, 1, 4, 2, 4, 3, 4,
1, 0, 4, 0x7fff, 0, 0, 0, 0, 0, 0,
4, 2, 5, 8, 6, 10, 7, 3, 6, 3,
1, 0, 6, 0x7fff, 0, 0, 0, 0, 0, 0,
2, 1, 5, 8, 4, 0x7fff, 0, 0, 0, 0,
1, 0, 8, 5, 0, 0, 0, 0, 0, 0
};
#ifdef USE_NET
memset(&net_info, 0, sizeof(net_info));
#endif
#ifdef DOS
if (__djgpp_nearptr_enable() == 0)
return 1;
#endif
srand(time(NULL));
if (hook_keyb_handler() != 0)
return 1;
memset(&main_info, 0, sizeof(main_info));
strcpy(datfile_name, DATA_PATH);
force2 = force3 = 0;
if (argc > 1) {
for (c1 = 1; c1 < argc; c1++) {
if (stricmp(argv[c1], "-nosound") == 0)
main_info.no_sound = 1;
else if (stricmp(argv[c1], "-musicnosound") == 0)
main_info.music_no_sound = 1;
else if (stricmp(argv[c1], "-nogore") == 0)
main_info.no_gore = 1;
else if (stricmp(argv[c1], "-noflies") == 0)
flies_enabled = 0;
else if (stricmp(argv[c1], "-nojoy") == 0)
main_info.joy_enabled = 0;
else if (stricmp(argv[c1], "-fireworks") == 0)
main_info.fireworks = 1;
#ifdef USE_SDL
else if (stricmp(argv[c1], "-fullscreen") == 0)
fs_toggle();
#endif
else if (stricmp(argv[c1], "-scaleup") == 0)
set_scaling(1);
else if (stricmp(argv[c1], "-mirror") == 0)
flip = 1;
else if (stricmp(argv[c1], "-dat") == 0) {
if (c1 < (argc - 1)) {
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)
force2 = 1;
if (stricmp(argv[c1 + 1], "3") == 0)
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 0
/** It should not be necessary to assign a default player number here. The
server assigns one in init_server, the client gets one assigned by the server,
all provided the user didn't choose one on the commandline. */
if (is_net) {
if (client_player_num < 0)
client_player_num = 0;
player[client_player_num].enabled = 1;
}
#endif
main_info.pob_backbuf[0] = malloc(screen_pitch*screen_height);
main_info.pob_backbuf[1] = malloc(screen_pitch*screen_height);
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];
for (c2 = 0; c2 < 4; c2++) {
player_anims[c1].frame[c2].image = player_anim_data[c1 * 10 + c2 * 2 + 2];
player_anims[c1].frame[c2].ticks = player_anim_data[c1 * 10 + c2 * 2 + 3];
}
}
if ((handle = dat_open("menu.pcx")) == 0) {
strcpy(main_info.error_str, "Error loading 'menu.pcx', aborting...\n");
return 1;
}
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")) == 0) {
strcpy(main_info.error_str, "Error loading 'rabbit.gob', aborting...\n");
return 1;
}
if (register_gob(handle, &rabbit_gobs, dat_filelen("rabbit.gob"))) {
/* error */
return 1;
}
if ((handle = dat_open("objects.gob")) == 0) {
strcpy(main_info.error_str, "Error loading 'objects.gob', aborting...\n");
return 1;
}
if (register_gob(handle, &object_gobs, dat_filelen("objects.gob"))) {
/* error */
return 1;
}
if ((handle = dat_open("font.gob")) == 0) {
strcpy(main_info.error_str, "Error loading 'font.gob', aborting...\n");
return 1;
}
if (register_gob(handle, &font_gobs, dat_filelen("font.gob"))) {
/* error */
return 1;
}
if ((handle = dat_open("numbers.gob")) == 0) {
strcpy(main_info.error_str, "Error loading 'numbers.gob', aborting...\n");
return 1;
}
if (register_gob(handle, &number_gobs, dat_filelen("numbers.gob"))) {
/* error */
return 1;
}
if (read_level() != 0) {
strcpy(main_info.error_str, "Error loading 'levelmap.txt', aborting...\n");
return 1;
}
dj_init();
if (main_info.no_sound == 0) {
dj_autodetect_sd();
dj_set_mixing_freq(20000);
dj_set_stereo(0);
dj_set_auto_mix(0);
dj_set_dma_time(8);
dj_set_num_sfx_channels(5);
dj_set_sfx_volume(64);
dj_set_nosound(1);
dj_start();
if ((handle = dat_open("jump.mod")) == 0) {
strcpy(main_info.error_str, "Error loading 'jump.mod', aborting...\n");
return 1;
}
if (dj_load_mod(handle, 0, MOD_MENU) != 0) {
strcpy(main_info.error_str, "Error loading 'jump.mod', aborting...\n");
return 1;
}
if ((handle = dat_open("bump.mod")) == 0) {
strcpy(main_info.error_str, "Error loading 'bump.mod', aborting...\n");
return 1;
}
if (dj_load_mod(handle, 0, MOD_GAME) != 0) {
strcpy(main_info.error_str, "Error loading 'bump.mod', aborting...\n");
return 1;
}
if ((handle = dat_open("scores.mod")) == 0) {
strcpy(main_info.error_str, "Error loading 'scores.mod', aborting...\n");
return 1;
}
if (dj_load_mod(handle, 0, MOD_SCORES) != 0) {
strcpy(main_info.error_str, "Error loading 'scores.mod', aborting...\n");
return 1;
}
if ((handle = dat_open("jump.smp")) == 0) {
strcpy(main_info.error_str, "Error loading 'jump.smp', aborting...\n");
return 1;
}
if (dj_load_sfx(handle, 0, dat_filelen("jump.smp"), DJ_SFX_TYPE_SMP, SFX_JUMP) != 0) {
strcpy(main_info.error_str, "Error loading 'jump.smp', aborting...\n");
return 1;
}
if ((handle = dat_open("death.smp")) == 0) {
strcpy(main_info.error_str, "Error loading 'death.smp', aborting...\n");
return 1;
}
if (dj_load_sfx(handle, 0, dat_filelen("death.smp"), DJ_SFX_TYPE_SMP, SFX_DEATH) != 0) {
strcpy(main_info.error_str, "Error loading 'death.smp', aborting...\n");
return 1;
}
if ((handle = dat_open("spring.smp")) == 0) {
strcpy(main_info.error_str, "Error loading 'spring.smp', aborting...\n");
return 1;
}
if (dj_load_sfx(handle, 0, dat_filelen("spring.smp"), DJ_SFX_TYPE_SMP, SFX_SPRING) != 0) {
strcpy(main_info.error_str, "Error loading 'spring.smp', aborting...\n");
return 1;
}
if ((handle = dat_open("splash.smp")) == 0) {
strcpy(main_info.error_str, "Error loading 'splash.smp', aborting...\n");
return 1;
}
if (dj_load_sfx(handle, 0, dat_filelen("splash.smp"), DJ_SFX_TYPE_SMP, SFX_SPLASH) != 0) {
strcpy(main_info.error_str, "Error loading 'splash.smp', aborting...\n");
return 1;
}
if ((handle = dat_open("fly.smp")) == 0) {
strcpy(main_info.error_str, "Error loading 'fly.smp', aborting...\n");
return 1;
}
if (dj_load_sfx(handle, 0, dat_filelen("fly.smp"), DJ_SFX_TYPE_SMP, SFX_FLY) != 0) {
strcpy(main_info.error_str, "Error loading 'fly.smp', aborting...\n");
return 1;
}
dj_get_sfx_settings(SFX_FLY, &fly);
fly.priority = 10;
fly.default_freq = SFX_FLY_FREQ;
fly.loop = 1;
fly.loop_start = 0;
fly.loop_length = fly.length;
dj_set_sfx_settings(SFX_FLY, &fly);
}
if ((background_pic = malloc(JNB_WIDTH*JNB_HEIGHT)) == NULL)
return 1;
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;
}
setpalette(0, 256, pal);
init_inputs();
recalculate_gob(&font_gobs, pal);
if (main_info.joy_enabled == 1 && main_info.fireworks == 0) {
load_flag = 0;
put_text(0, 200, 40, "JOYSTICK CALIBRATION", 2);
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 {
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 {
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")) == 0) {
strcpy(main_info.error_str, "Error loading 'calib.dat', aborting...\n");
return 1;
}
joy.calib_data.x1 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
joy.calib_data.x2 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
joy.calib_data.x3 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
joy.calib_data.y1 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
joy.calib_data.y2 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
joy.calib_data.y3 = (handle[0]) + (handle[1] << 8) + (handle[2] << 16) + (handle[3] << 24); handle += 4;
}
}
#ifdef USE_NET
if (is_net) {
if (is_server) {
init_server(netarg);
} else {
connect_to_server(netarg);
}
}
#endif
return 0;
}
void deinit_program(void)
{
#ifdef DOS
__dpmi_regs regs;
#endif
dj_stop();
dj_free_mod(MOD_MENU);
dj_free_mod(MOD_GAME);
dj_free_sfx(SFX_DEATH);
dj_free_sfx(SFX_SPRING);
dj_free_sfx(SFX_SPLASH);
dj_deinit();
if (background_pic != 0)
free(background_pic);
if (mask_pic != 0)
free(mask_pic);
remove_keyb_handler();
#ifdef DOS
regs.x.ax = 0x3;
__dpmi_int(0x10, &regs);
#endif
if (main_info.error_str[0] != 0) {
printf(main_info.error_str);
#ifdef _MSC_VER
MessageBox(0, main_info.error_str, "Jump'n'Bump", 0);
#endif
exit(1);
} else
exit(0);
}
unsigned short rnd(unsigned short max)
{
#if (RAND_MAX < 0x7fff)
#error "rand returns too small values"
#elif (RAND_MAX == 0x7fff)
return (unsigned short)((rand()*2) % (int)max);
#else
return (unsigned short)(rand() % (int)max);
#endif
}
int read_level(void)
{
unsigned char *handle;
int c1, c2;
int chr;
if ((handle = dat_open("levelmap.txt")) == 0) {
strcpy(main_info.error_str, "Error loading 'levelmap.txt', aborting...\n");
return 1;
}
for (c1 = 0; c1 < 16; c1++) {
for (c2 = 0; c2 < 22; c2++) {
while (1) {
chr = (int) *(handle++);
if (chr >= '0' && chr <= '4')
break;
}
if (flip)
ban_map[c1][21-c2] = chr - '0';
else
ban_map[c1][c2] = chr - '0';
}
}
for (c2 = 0; c2 < 22; c2++)
ban_map[16][c2] = BAN_SOLID;
return 0;
}
unsigned char *dat_open(char *file_name)
{
int num;
int c1;
char name[21];
int ofs;
unsigned char *ptr;
if (datafile_buffer == NULL)
return 0;
memset(name, 0, sizeof(name));
num = ( (datafile_buffer[0] << 0) +
(datafile_buffer[1] << 8) +
(datafile_buffer[2] << 16) +
(datafile_buffer[3] << 24) );
ptr = datafile_buffer + 4;
for (c1 = 0; c1 < num; c1++) {
memcpy(name, ptr, 12);
ptr += 12;
if (strnicmp(name, file_name, strlen(file_name)) == 0) {
ofs = ( (ptr[0] << 0) +
(ptr[1] << 8) +
(ptr[2] << 16) +
(ptr[3] << 24) );
return (datafile_buffer + ofs);
}
ptr += 8;
}
return 0;
}
int dat_filelen(char *file_name)
{
unsigned char *ptr;
int num;
int c1;
char name[21];
int len;
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++) {
memcpy(name, ptr, 12);
ptr += 12;
if (strnicmp(name, file_name, strlen(file_name)) == 0) {
ptr += 4;
len = ( (ptr[0] << 0) +
(ptr[1] << 8) +
(ptr[2] << 16) +
(ptr[3] << 24) );
return len;
}
ptr += 8;
}
return 0;
}
void write_calib_data(void)
{
FILE *handle;
int c1;
int len, num;
char *mem;
int ofs;
if ((handle = fopen(datfile_name, "rb")) == NULL)
return;
len = filelength(fileno(handle));
if ((mem = malloc(len)) == NULL)
return;
fread(mem, 1, len, handle);
fclose(handle);
ofs = 4;
num = *(int *) (&mem[0]);
for (c1 = 0; c1 < num; c1++) {
if (strnicmp(&mem[ofs], "calib.dat", strlen("calib.dat")) == 0) {
ofs = *(int *) (&mem[ofs + 12]);
break;
}
ofs += 20;
}
mem[ofs] = joy.calib_data.x1 & 0xff;
mem[ofs + 1] = (joy.calib_data.x1 >> 8) & 0xff;
mem[ofs + 2] = (joy.calib_data.x1 >> 16) & 0xff;
mem[ofs + 3] = (joy.calib_data.x1 >> 24) & 0xff;
mem[ofs + 4] = joy.calib_data.x2 & 0xff;
mem[ofs + 5] = (joy.calib_data.x2 >> 8) & 0xff;
mem[ofs + 6] = (joy.calib_data.x2 >> 16) & 0xff;
mem[ofs + 7] = (joy.calib_data.x2 >> 24) & 0xff;
mem[ofs + 8] = joy.calib_data.x3 & 0xff;
mem[ofs + 9] = (joy.calib_data.x3 >> 8) & 0xff;
mem[ofs + 10] = (joy.calib_data.x3 >> 16) & 0xff;
mem[ofs + 11] = (joy.calib_data.x3 >> 24) & 0xff;
mem[ofs + 12] = joy.calib_data.y1 & 0xff;
mem[ofs + 13] = (joy.calib_data.y1 >> 8) & 0xff;
mem[ofs + 14] = (joy.calib_data.y1 >> 16) & 0xff;
mem[ofs + 15] = (joy.calib_data.y1 >> 24) & 0xff;
mem[ofs + 16] = joy.calib_data.y2 & 0xff;
mem[ofs + 17] = (joy.calib_data.y2 >> 8) & 0xff;
mem[ofs + 18] = (joy.calib_data.y2 >> 16) & 0xff;
mem[ofs + 19] = (joy.calib_data.y2 >> 24) & 0xff;
mem[ofs + 20] = joy.calib_data.y3 & 0xff;
mem[ofs + 21] = (joy.calib_data.y3 >> 8) & 0xff;
mem[ofs + 22] = (joy.calib_data.y3 >> 16) & 0xff;
mem[ofs + 23] = (joy.calib_data.y3 >> 24) & 0xff;
if ((handle = fopen(datfile_name, "wb")) == NULL)
return;
fwrite(mem, 1, len, handle);
fclose(handle);
}