Abstracting networking protocols - Step 4: Implemented new UDP layer with Client/Server communication, Packet Loss Prevention and strict Version checking. Netgames list will follow later.
This commit is contained in:
parent
57c71476fc
commit
febe5d124d
|
@ -1,5 +1,9 @@
|
|||
D2X-Rebirth Changelog
|
||||
|
||||
20091124
|
||||
--------
|
||||
include/args.h, INSTALL.txt, main/net_udp.c, main/net_udp.h, main/fireball.c, main/multi.c, main/multibot.c, main/multi.h, main/inferno.c, main/menu.c, main/object.c, main/kmatrix.c, main/kmatrix.h, main/newdemo.c, main/config.c, main/net_ipx.c, main/config.h, main/net_ipx.h, main/gamerend.c, main/gameseq.c, main/endlevel.c, main/vers_id.h, main/game.c, main/gauges.c, misc/args.c, SConstruct, d2x.ini, README.txt, arch/linux/ipx.c, arch/linux/ipx_kali.c, arch/win32/ipx.c: Abstracting networking protocols - Step 4: Implemented new UDP layer with Client/Server communication, Packet Loss Prevention and strict Version checking. Netgames list will follow later.
|
||||
|
||||
20091117
|
||||
--------
|
||||
arch/ogl/gr.c, arch/sdl/gr.c, include/gr.h, main/menu.c, main/piggy.c: Only list resolutions that can actually be used, using new gr_check_mode
|
||||
|
|
13
INSTALL.txt
13
INSTALL.txt
|
@ -26,19 +26,6 @@ For Mac OS X, an Xcode project is available (requires Xcode 2.1 or later). Xcode
|
|||
The SConstruct file provides various options to compile this program.
|
||||
To get a full list of all available commands, type scons -h within the Source directory.
|
||||
|
||||
Currently, the following variables are supported:
|
||||
|
||||
'sharepath=DIR' (non-Mac OS *NIX only) use DIR for shared game data. (default: /usr/local/share/games/d2x-rebirth)
|
||||
'sdl_only=1' don't include OpenGL, use SDL-only instead
|
||||
'sdlmixer=1' use SDL_Mixer for sound (includes external music support)
|
||||
'asm=1' use ASSEMBLER code (only with sdl_only=1, requires NASM and x86)
|
||||
'debug=1' build DEBUG binary which includes asserts, debugging output, cheats and more output
|
||||
'profiler=1' do profiler build
|
||||
'editor=1' build editor !EXPERIMENTAL!
|
||||
'arm=1' compile for ARM architecture
|
||||
|
||||
‘editor’ is currently *not* supported and will not work.
|
||||
|
||||
To compile the source, type:
|
||||
|
||||
scons
|
||||
|
|
11
README.txt
11
README.txt
|
@ -53,13 +53,10 @@ See INSTALL.txt.
|
|||
|
||||
3. Multiplayer
|
||||
|
||||
DXX-Rebirth supports Multiplayer over (obsoleted) IPX and UDP/IP.
|
||||
Using UDP/IP works over LAN and Internet. Since the Networking code of the Descent Engine is Peer-to-Peer, it is necessary for
|
||||
all players (Host and Clients) to open port UDP 31017.
|
||||
Clients can put an offset to this port by using '-ip_baseport OFFSET'.
|
||||
Hosts can also use option '-ip_relay' to route players with closed ports. Use this with caution. It will increase Lag and Ping drastically.
|
||||
Also game summary will not refresh correctly for relay-players until Host has escaped the level as well.
|
||||
UDP/IP also supports IPv6 by compiling the game with the designated flag. Please note IPv4- and IPv6-builds cannot play together.
|
||||
D2X-Rebirth supports Multiplayer over (obsoleted) IPX and UDP/IP.
|
||||
Please note that UDP/IP generally supports more features of D2X-Rebirth and uses Packet Loss Prevention while IPX is mainly meant to play together with non-D1X-Rebirth games.
|
||||
Using UDP/IP works over LAN and Internet. By default, each game communicates over UDP-Port 42424. This can be changed via the menus while creating a game and manually join a game, command-line argument or D2X.INI. To successfully host a game online, make sure UDP-Port 42424 (or otherwise if specified correctly) is opened on your Router/Firewall. Clients do not need to open any ports.
|
||||
The game also supports IPv6 if built in while compiling and should be backwards compatible to IPv4 builds as good as possible.
|
||||
|
||||
|
||||
4. Legal stuff
|
||||
|
|
|
@ -125,7 +125,6 @@ common_sources = [
|
|||
'main/hostage.c',
|
||||
'main/hud.c',
|
||||
'main/inferno.c',
|
||||
'main/ipxdrv.c',
|
||||
'main/kconfig.c',
|
||||
'main/kmatrix.c',
|
||||
'main/laser.c',
|
||||
|
@ -138,6 +137,7 @@ common_sources = [
|
|||
'main/multi.c',
|
||||
'main/multibot.c',
|
||||
'main/net_ipx.c',
|
||||
'main/net_udp.c',
|
||||
'main/newdemo.c',
|
||||
'main/newmenu.c',
|
||||
'main/object.c',
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "ipxdrv.h"
|
||||
#include "net_ipx.h"
|
||||
#include "console.h"
|
||||
|
||||
static int ipx_get_my_address( void )
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <netinet/in.h> /* for htons & co. */
|
||||
#include "ipxdrv.h"
|
||||
#include "net_ipx.h"
|
||||
#include "ukali.h"
|
||||
#include "console.h"
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <winsock.h>
|
||||
#include <wsipx.h>
|
||||
#include "ipxdrv.h"
|
||||
#include "net_ipx.h"
|
||||
#include "console.h"
|
||||
|
||||
static int ipx_get_my_address( void )
|
||||
|
|
6
d2x.ini
6
d2x.ini
|
@ -42,9 +42,9 @@
|
|||
;-norankings Disable multiplayer ranking system
|
||||
;-playermessages View only messages from other players in multi - overrides -noredundancy
|
||||
;-ipxnetwork <n> Use IPX network number <n>
|
||||
;-ip_baseport <n> Use <p> as offset from normal port
|
||||
;-ip_relay Relay players with closed port over host (increases traffic and lag)
|
||||
;-ip_hostaddr <n> Use <n> as host ip address
|
||||
;-udp_hostaddr <n> When manually joining a game use default IP Address <n> to connect to
|
||||
;-udp_hostport <n> When manually joining a game use default UDP Port <n> to connect to
|
||||
;-udp_myport <n> When hosting/joining a game use default UDP Port <n> to send packets from
|
||||
|
||||
Debug (use only if you know what you're doing):
|
||||
|
||||
|
|
|
@ -74,9 +74,9 @@ typedef struct Arg
|
|||
int MplNoRankings;
|
||||
int MplPlayerMessages;
|
||||
const char *MplIpxNetwork;
|
||||
int MplIpBasePort;
|
||||
int MplIpRelay;
|
||||
char *MplIpHostAddr;
|
||||
const char *MplUdpHostAddr;
|
||||
int MplUdpHostPort;
|
||||
int MplUdpMyPort;
|
||||
char *EdiAutoLoad;
|
||||
int EdiSaveHoardData;
|
||||
int EdiMacData; // also used for some read routines in non-editor build
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
/*
|
||||
*
|
||||
* IPX-based driver interface
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NET_DRV_H
|
||||
#define _NET_DRV_H
|
||||
|
||||
#include "pstypes.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <netinet/in.h> /* for htons & co. */
|
||||
#endif
|
||||
|
||||
#define MAX_PACKET_DATA 1500
|
||||
#define MAX_DATA_SIZE 542
|
||||
#define MAX_IPX_DATA 576
|
||||
|
||||
#define IPX_DEFAULT_SOCKET 0x5130
|
||||
|
||||
#define NETPROTO_IPX 1
|
||||
#define NETPROTO_KALINIX 2
|
||||
|
||||
typedef struct IPXAddressStruct {
|
||||
ubyte Network[4];
|
||||
ubyte Node[6];
|
||||
ubyte Socket[2];
|
||||
} IPXAddress_t;
|
||||
|
||||
typedef struct IPXPacketStructure {
|
||||
ushort Checksum;
|
||||
ushort Length;
|
||||
ubyte TransportControl;
|
||||
ubyte PacketType;
|
||||
IPXAddress_t Destination;
|
||||
IPXAddress_t Source;
|
||||
} IPXPacket_t;
|
||||
|
||||
typedef struct socket_struct {
|
||||
ushort socket;
|
||||
int fd;
|
||||
} socket_t;
|
||||
|
||||
struct recv_data {
|
||||
/* all network order */
|
||||
ubyte src_network[4];
|
||||
ubyte src_node[6];
|
||||
ushort src_socket;
|
||||
ushort dst_socket;
|
||||
int pkt_type;
|
||||
};
|
||||
|
||||
struct net_driver {
|
||||
int (*open_socket)(socket_t *sk, int port);
|
||||
void (*close_socket)(socket_t *mysock);
|
||||
int (*send_packet)(socket_t *mysock, IPXPacket_t *IPXHeader, ubyte *data, int dataLen);
|
||||
int (*receive_packet)(socket_t *s, char *buffer, int bufsize, struct recv_data *rec);
|
||||
int (*packet_ready)(socket_t *s);
|
||||
int usepacketnum;//we can save 4 bytes
|
||||
int type; // type of driver (NETPROTO_*). Can be used to make driver-specific rules in other parts of the multiplayer code.
|
||||
};
|
||||
|
||||
extern int ipxdrv_general_packet_ready(int fd);
|
||||
extern void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target );
|
||||
extern int ipxdrv_set(int arg);
|
||||
extern int ipxdrv_change_default_socket( ushort socket_number );
|
||||
extern ubyte * ipxdrv_get_my_local_address();
|
||||
extern ubyte * ipxdrv_get_my_server_address();
|
||||
extern int ipxdrv_get_packet_data( ubyte * data );
|
||||
extern void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize );
|
||||
extern void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address );
|
||||
extern void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address );
|
||||
extern int ipxdrv_type(void);
|
||||
|
||||
#ifndef __APPLE__
|
||||
extern struct net_driver ipxdrv_ipx;
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
extern struct net_driver ipxdrv_kali;
|
||||
#endif
|
||||
|
||||
extern unsigned char MyAddress[10];
|
||||
extern ubyte broadcast_addr[];
|
||||
extern ubyte null_addr[];
|
||||
extern u_int32_t ipx_network;
|
||||
|
||||
#endif /* _NET_DRV_H */
|
|
@ -58,7 +58,6 @@ static char *VSyncStr="VSync";
|
|||
static char *MultisampleStr="Multisample";
|
||||
static char *JukeboxOnStr="JukeboxOn";
|
||||
static char *JukeboxPathStr="JukeboxPath";
|
||||
static char *IPHostAddrStr="IPHostAddr";
|
||||
|
||||
int ReadConfigFile()
|
||||
{
|
||||
|
@ -92,7 +91,6 @@ int ReadConfigFile()
|
|||
#else
|
||||
strncpy(GameCfg.JukeboxPath, "::::Jukebox", PATH_MAX+1);
|
||||
#endif
|
||||
memset(GameCfg.MplIpHostAddr, '\x0', sizeof(GameCfg.MplIpHostAddr));
|
||||
|
||||
infile = PHYSFSX_openReadBuffered("descent.cfg");
|
||||
|
||||
|
@ -162,12 +160,6 @@ int ReadConfigFile()
|
|||
p = strchr( GameCfg.JukeboxPath, '\n');
|
||||
if ( p ) *p = 0;
|
||||
}
|
||||
else if (!strcmp(token, IPHostAddrStr)) {
|
||||
char * p;
|
||||
strncpy( GameCfg.MplIpHostAddr, value, 128 );
|
||||
p = strchr( GameCfg.MplIpHostAddr, '\n');
|
||||
if ( p ) *p = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,7 +206,6 @@ int WriteConfigFile()
|
|||
PHYSFSX_printf(infile, "%s=%i\n", MultisampleStr, GameCfg.Multisample);
|
||||
PHYSFSX_printf(infile, "%s=%i\n", JukeboxOnStr, GameCfg.JukeboxOn);
|
||||
PHYSFSX_printf(infile, "%s=%s\n", JukeboxPathStr, GameCfg.JukeboxPath);
|
||||
PHYSFSX_printf(infile, "%s=%s\n", IPHostAddrStr, GameCfg.MplIpHostAddr);
|
||||
|
||||
PHYSFS_close(infile);
|
||||
|
||||
|
|
|
@ -44,7 +44,6 @@ typedef struct Cfg
|
|||
int Multisample;
|
||||
int JukeboxOn;
|
||||
char JukeboxPath[PATH_MAX+1];
|
||||
char MplIpHostAddr[128];
|
||||
} __pack__ Cfg;
|
||||
|
||||
extern struct Cfg GameCfg;
|
||||
|
|
|
@ -231,13 +231,6 @@ int start_endlevel_movie()
|
|||
memcpy(gr_palette,save_pal,768);
|
||||
}
|
||||
|
||||
#ifdef NETWORK
|
||||
if (r==MOVIE_NOT_PLAYED && (Game_mode & GM_MULTI))
|
||||
Kmatrix_nomovie_message=1;
|
||||
else
|
||||
Kmatrix_nomovie_message=0;
|
||||
#endif
|
||||
|
||||
return (r);
|
||||
|
||||
}
|
||||
|
|
|
@ -530,7 +530,7 @@ int choose_drop_segment()
|
|||
while ((segnum == -1) && (cur_drop_depth > BASE_NET_DROP_DEPTH/2)) {
|
||||
pnum = (d_rand() * N_players) >> 15;
|
||||
count = 0;
|
||||
while ((count < N_players) && ((Players[pnum].connected == 0) || (pnum==Player_num) || ((Game_mode & (GM_TEAM|GM_CAPTURE)) && (get_team(pnum)==get_team(Player_num))))) {
|
||||
while ((count < N_players) && ((Players[pnum].connected == CONNECT_DISCONNECTED) || (pnum==Player_num) || ((Game_mode & (GM_TEAM|GM_CAPTURE)) && (get_team(pnum)==get_team(Player_num))))) {
|
||||
pnum = (pnum+1)%N_players;
|
||||
count++;
|
||||
}
|
||||
|
|
|
@ -1256,9 +1256,6 @@ int game_handler(window *wind, d_event *event, void *data)
|
|||
}
|
||||
|
||||
if ( (Function_mode != FMODE_GAME ) && (Newdemo_state != ND_STATE_PLAYBACK ) && (Function_mode!=FMODE_EDITOR)
|
||||
#ifdef NETWORK
|
||||
&& !IWasKicked
|
||||
#endif
|
||||
) {
|
||||
int choice, fmode;
|
||||
fmode = Function_mode;
|
||||
|
@ -1274,9 +1271,6 @@ int game_handler(window *wind, d_event *event, void *data)
|
|||
Function_mode = FMODE_GAME;
|
||||
}
|
||||
|
||||
#ifdef NETWORK
|
||||
IWasKicked=0;
|
||||
#endif
|
||||
if (Function_mode != FMODE_GAME)
|
||||
{
|
||||
window_close(wind);
|
||||
|
|
|
@ -176,7 +176,7 @@ void show_netplayerinfo()
|
|||
|
||||
// general game information
|
||||
y+=LINE_SPACING;
|
||||
gr_printf(0x8000,y,"%s by %s",Netgame.game_name,Players[multi_who_is_master()].callsign);
|
||||
gr_printf(0x8000,y,"%s",Netgame.game_name);
|
||||
y+=LINE_SPACING;
|
||||
gr_printf(0x8000,y,"%s - lvl: %i",Netgame.mission_title,Netgame.levelnum);
|
||||
|
||||
|
@ -206,8 +206,6 @@ void show_netplayerinfo()
|
|||
gr_printf(x+FSPACX(8)*18,y,"ping");
|
||||
gr_printf(x+FSPACX(8)*23,y,"efficiency");
|
||||
|
||||
multi_do_ping_frame();
|
||||
|
||||
// process players table
|
||||
for (i=0; i<MAX_PLAYERS; i++)
|
||||
{
|
||||
|
|
|
@ -1054,7 +1054,7 @@ void DoEndLevelScoreGlitz(int network)
|
|||
|
||||
#ifdef NETWORK
|
||||
if ( network && (Game_mode & GM_NETWORK) )
|
||||
newmenu_do2(NULL, title, c, m, (void (*))multi_endlevel_poll2, 0, STARS_BACKGROUND);
|
||||
newmenu_do2(NULL, title, c, m, (void (*))multi_endlevel_poll1, 0, STARS_BACKGROUND);
|
||||
else
|
||||
#endif
|
||||
// NOTE LINK TO ABOVE!!!
|
||||
|
@ -1341,7 +1341,7 @@ void PlayerFinishedLevel(int secret_flag)
|
|||
Players[Player_num].hostages_rescued_total += Players[Player_num].hostages_on_board;
|
||||
|
||||
if (Game_mode & GM_NETWORK)
|
||||
Players[Player_num].connected = 2; // Finished but did not die
|
||||
Players[Player_num].connected = CONNECT_WAITING; // Finished but did not die
|
||||
|
||||
last_drawn_cockpit = -1;
|
||||
|
||||
|
@ -1605,7 +1605,7 @@ void DoPlayerDead()
|
|||
Players[Player_num].hostages_on_board = 0;
|
||||
Players[Player_num].energy = 0;
|
||||
Players[Player_num].shields = 0;
|
||||
Players[Player_num].connected = 3;
|
||||
Players[Player_num].connected = CONNECT_DIED_IN_MINE;
|
||||
|
||||
died_in_mine_message(); // Give them some indication of what happened
|
||||
|
||||
|
@ -2057,7 +2057,6 @@ void StartLevel(int random_flag)
|
|||
{
|
||||
if (Game_mode & GM_MULTI_COOP)
|
||||
multi_send_score();
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
multi_send_reappear();
|
||||
}
|
||||
|
||||
|
|
|
@ -2523,7 +2523,7 @@ void hud_show_kill_list()
|
|||
{
|
||||
int color;
|
||||
|
||||
if (Players[player_num].connected != 1)
|
||||
if (Players[player_num].connected != CONNECT_PLAYING)
|
||||
gr_set_fontcolor(BM_XRGB(12, 12, 12), -1);
|
||||
else if (Game_mode & GM_TEAM) {
|
||||
color = get_team(player_num);
|
||||
|
|
|
@ -168,9 +168,9 @@ void print_commandline_help()
|
|||
printf( " -norankings %s\n", "Disable multiplayer ranking system");
|
||||
printf( " -playermessages %s\n", "View only messages from other players in multi - overrides -noredundancy");
|
||||
printf( " -ipxnetwork <n> %s\n", "Use IPX network number <n>");
|
||||
printf( " -ip_baseport <n> %s\n", "Use <n> as offset from normal port (allows multiple instances of d1x to be run on a single computer)");
|
||||
printf( " -ip_relay %s\n", "Relay players with closed port over host (increases traffic and lag)");
|
||||
printf( " -ip_hostaddr <n> %s\n", "Use <n> as host ip address");
|
||||
printf( " -udp_hostaddr <n> %s\n", "When manually joining a game use default IP Address <n> to connect to");
|
||||
printf( " -udp_hostport <n> %s\n", "When manually joining a game use default UDP Port <n> to connect to");
|
||||
printf( " -udp_myport <n> %s\n", "When hosting/joining a game use default UDP Port <n> to send packets from");
|
||||
#endif // NETWORK
|
||||
|
||||
#ifdef EDITOR
|
||||
|
|
360
main/ipxdrv.c
360
main/ipxdrv.c
|
@ -1,360 +0,0 @@
|
|||
/*
|
||||
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
||||
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
||||
END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
|
||||
ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
|
||||
IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
|
||||
SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
|
||||
FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
|
||||
CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS
|
||||
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
|
||||
COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* IPX-based driver interface
|
||||
* This is the main interface to send packets via arch-dependend IPX-code layers.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef _MSC_VER
|
||||
#include <WTypes.h>
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "args.h"
|
||||
#include "text.h"
|
||||
#include "net_ipx.h"
|
||||
#include "console.h"
|
||||
#include "ipxdrv.h"
|
||||
#include "checker.h"
|
||||
|
||||
ubyte broadcast_addr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
ubyte null_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
ubyte ipxdrv_installed=0;
|
||||
u_int32_t ipx_network = 0;
|
||||
ubyte MyAddress[10];
|
||||
int ipx_packetnum = 0; /* Sequence number */
|
||||
|
||||
/* User defined routing stuff */
|
||||
typedef struct user_address {
|
||||
ubyte network[4];
|
||||
ubyte node[6];
|
||||
ubyte address[6];
|
||||
} user_address;
|
||||
|
||||
socket_t socket_data;
|
||||
#define MAX_USERS 64
|
||||
int Ipx_num_users = 0;
|
||||
user_address Ipx_users[MAX_USERS];
|
||||
#define MAX_NETWORKS 64
|
||||
int Ipx_num_networks = 0;
|
||||
uint Ipx_networks[MAX_NETWORKS];
|
||||
|
||||
int ipxdrv_general_packet_ready(int fd)
|
||||
{
|
||||
fd_set set;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(fd, &set);
|
||||
tv.tv_sec = tv.tv_usec = 0;
|
||||
if (select(fd + 1, &set, NULL, NULL, &tv) > 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct net_driver *driver = NULL;
|
||||
|
||||
ubyte * ipxdrv_get_my_server_address()
|
||||
{
|
||||
return (ubyte *)&ipx_network;
|
||||
}
|
||||
|
||||
ubyte * ipxdrv_get_my_local_address()
|
||||
{
|
||||
return (ubyte *)(MyAddress + 4);
|
||||
}
|
||||
|
||||
void ipxdrv_close()
|
||||
{
|
||||
if (ipxdrv_installed)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSACleanup();
|
||||
#endif
|
||||
driver->close_socket(&socket_data);
|
||||
}
|
||||
|
||||
ipxdrv_installed = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Initializes all driver internals.
|
||||
// If socket_number==0, then opens next available socket.
|
||||
// Returns: 0 if successful.
|
||||
// -1 if socket already open.
|
||||
// -2 if socket table full.
|
||||
// -3 if driver not installed.
|
||||
// -4 if couldn't allocate low dos memory
|
||||
// -5 if error with getting internetwork address
|
||||
int ipxdrv_init( int socket_number )
|
||||
{
|
||||
static int cleanup = 0;
|
||||
#ifdef _WIN32
|
||||
WORD wVersionRequested;
|
||||
WSADATA wsaData;
|
||||
#endif
|
||||
|
||||
if (!driver)
|
||||
return -1;
|
||||
|
||||
#ifdef _WIN32
|
||||
wVersionRequested = MAKEWORD(2, 0);
|
||||
if (WSAStartup( wVersionRequested, &wsaData))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
memset(MyAddress,0,10);
|
||||
|
||||
if (GameArg.MplIpxNetwork)
|
||||
{
|
||||
unsigned long n = strtol(GameArg.MplIpxNetwork, NULL, 16);
|
||||
MyAddress[0] = n >> 24; MyAddress[1] = (n >> 16) & 255;
|
||||
MyAddress[2] = (n >> 8) & 255; MyAddress[3] = n & 255;
|
||||
con_printf(CON_DEBUG,"IPX: Using network %08x\n", (unsigned int)n);
|
||||
}
|
||||
|
||||
if (driver->open_socket(&socket_data, socket_number))
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
memcpy(&ipx_network, MyAddress, 4);
|
||||
Ipx_num_networks = 0;
|
||||
memcpy( &Ipx_networks[Ipx_num_networks++], &ipx_network, 4 );
|
||||
|
||||
ipxdrv_installed = 1;
|
||||
|
||||
if (!cleanup)
|
||||
atexit(ipxdrv_close);
|
||||
cleanup = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipxdrv_set(int arg)
|
||||
{
|
||||
int ipxdrv_err;
|
||||
|
||||
ipxdrv_close();
|
||||
|
||||
con_printf(CON_VERBOSE, "\n%s ", TXT_INITIALIZING_NETWORK);
|
||||
|
||||
switch (arg)
|
||||
{
|
||||
#ifndef __APPLE__
|
||||
case NETPROTO_IPX:
|
||||
driver = &ipxdrv_ipx;
|
||||
break;
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
case NETPROTO_KALINIX:
|
||||
driver = &ipxdrv_kali;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
driver = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ipxdrv_err=ipxdrv_init(IPX_DEFAULT_SOCKET))==0)
|
||||
{
|
||||
con_printf(CON_VERBOSE, "%s %d.\n", TXT_IPX_CHANNEL, IPX_DEFAULT_SOCKET );
|
||||
Network_active = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (ipxdrv_err)
|
||||
{
|
||||
case 3:
|
||||
con_printf(CON_VERBOSE, "%s\n", TXT_NO_NETWORK);
|
||||
break;
|
||||
case -2:
|
||||
con_printf(CON_VERBOSE, "%s 0x%x.\n", TXT_SOCKET_ERROR, IPX_DEFAULT_SOCKET);
|
||||
break;
|
||||
case -4:
|
||||
con_printf(CON_VERBOSE, "%s\n", TXT_MEMORY_IPX );
|
||||
break;
|
||||
default:
|
||||
con_printf(CON_VERBOSE, "%s %d", TXT_ERROR_IPX, ipxdrv_err );
|
||||
break;
|
||||
}
|
||||
|
||||
con_printf(CON_VERBOSE, "%s\n",TXT_NETWORK_DISABLED);
|
||||
Network_active = 0; // Assume no network
|
||||
}
|
||||
|
||||
return ipxdrv_installed?0:-1;
|
||||
}
|
||||
|
||||
int ipxdrv_get_packet_data( ubyte * data )
|
||||
{
|
||||
struct recv_data rd;
|
||||
char *buf;
|
||||
int size;
|
||||
|
||||
if (driver->usepacketnum)
|
||||
buf=alloca(MAX_IPX_DATA);
|
||||
else
|
||||
buf=(char *)data;
|
||||
|
||||
memset(rd.src_network,1,4);
|
||||
|
||||
while (driver->packet_ready(&socket_data))
|
||||
{
|
||||
if ((size = driver->receive_packet(&socket_data, buf, MAX_IPX_DATA, &rd)) > 4)
|
||||
{
|
||||
if (!memcmp(rd.src_network, MyAddress, 10))
|
||||
{
|
||||
continue; /* don't get own pkts */
|
||||
}
|
||||
|
||||
if (driver->usepacketnum)
|
||||
{
|
||||
memcpy(data, buf + 4, size - 4);
|
||||
return size-4;
|
||||
}
|
||||
else
|
||||
{
|
||||
return size;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address )
|
||||
{
|
||||
IPXPacket_t ipx_header;
|
||||
|
||||
if (!ipxdrv_installed)
|
||||
return;
|
||||
|
||||
memcpy(ipx_header.Destination.Network, network, 4);
|
||||
memcpy(ipx_header.Destination.Node, immediate_address, 6);
|
||||
ipx_header.PacketType = 4; /* Packet Exchange */
|
||||
|
||||
if (driver->usepacketnum)
|
||||
{
|
||||
ubyte buf[MAX_IPX_DATA];
|
||||
*(uint *)buf = ipx_packetnum++;
|
||||
|
||||
memcpy(buf + 4, data, datasize);
|
||||
driver->send_packet(&socket_data, &ipx_header, buf, datasize + 4);
|
||||
}
|
||||
else
|
||||
driver->send_packet(&socket_data, &ipx_header, data, datasize);//we can save 4 bytes
|
||||
}
|
||||
|
||||
void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
|
||||
{
|
||||
memcpy( local_target, node, 6 );
|
||||
}
|
||||
|
||||
void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize )
|
||||
{
|
||||
int i, j;
|
||||
ubyte local_address[6];
|
||||
|
||||
if (!ipxdrv_installed)
|
||||
return;
|
||||
|
||||
// Set to all networks besides mine
|
||||
for (i=0; i<Ipx_num_networks; i++ )
|
||||
{
|
||||
if ( memcmp( &Ipx_networks[i], &ipx_network, 4 ) )
|
||||
{
|
||||
ipxdrv_get_local_target( (ubyte *)&Ipx_networks[i], broadcast_addr, local_address );
|
||||
ipxdrv_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast_addr, local_address );
|
||||
}
|
||||
else
|
||||
{
|
||||
ipxdrv_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast_addr, broadcast_addr );
|
||||
}
|
||||
}
|
||||
|
||||
// Send directly to all users not on my network or in the network list.
|
||||
for (i=0; i<Ipx_num_users; i++ )
|
||||
{
|
||||
if ( memcmp( Ipx_users[i].network, &ipx_network, 4 ) )
|
||||
{
|
||||
for (j=0; j<Ipx_num_networks; j++ )
|
||||
{
|
||||
if (!memcmp( Ipx_users[i].network, &Ipx_networks[j], 4 ))
|
||||
goto SkipUser;
|
||||
}
|
||||
|
||||
ipxdrv_send_packet_data( data, datasize, Ipx_users[i].network, Ipx_users[i].node, Ipx_users[i].address );
|
||||
SkipUser:
|
||||
j = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sends a non-localized packet... needs 4 byte server, 6 byte address
|
||||
void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address )
|
||||
{
|
||||
ubyte local_address[6];
|
||||
|
||||
if (!ipxdrv_installed)
|
||||
return;
|
||||
|
||||
#ifdef WORDS_NEED_ALIGNMENT
|
||||
int zero = 0;
|
||||
if (memcmp(server, &zero, 4))
|
||||
#else // WORDS_NEED_ALIGNMENT
|
||||
if ((*(uint *)server) != 0)
|
||||
#endif // WORDS_NEED_ALIGNMENT
|
||||
{
|
||||
ipxdrv_get_local_target( server, address, local_address );
|
||||
ipxdrv_send_packet_data( data, datasize, server, address, local_address );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Old method, no server info.
|
||||
ipxdrv_send_packet_data( data, datasize, server, address, address );
|
||||
}
|
||||
}
|
||||
|
||||
int ipxdrv_change_default_socket( ushort socket_number )
|
||||
{
|
||||
if ( !ipxdrv_installed )
|
||||
return -3;
|
||||
|
||||
driver->close_socket(&socket_data);
|
||||
|
||||
if (driver->open_socket(&socket_data, socket_number))
|
||||
{
|
||||
return -3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Return type of net_driver
|
||||
int ipxdrv_type(void)
|
||||
{
|
||||
return driver->type;
|
||||
}
|
||||
|
519
main/kmatrix.c
519
main/kmatrix.c
|
@ -14,6 +14,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
/*
|
||||
*
|
||||
* Kill matrix displayed at end of level.
|
||||
* This source file contains code for both newer networking protocols and IPX. Pretty much redundant stuff but lets keep a clean cut until IPX dies completly.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -54,20 +55,19 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#define CENTERING_OFFSET(x) ((300 - (70 + (x)*25 ))/2)
|
||||
#define CENTERSCREEN (SWIDTH/2)
|
||||
|
||||
int kmatrix_kills_changed = 0;
|
||||
/* IPX CODE - START */
|
||||
|
||||
#define MAX_VIEW_TIME F1_0*15
|
||||
#define ENDLEVEL_IDLE_TIME F1_0*10
|
||||
fix StartAbortMenuTime;
|
||||
char ConditionLetters[]={' ','P','E','D','E','E','V','W'};
|
||||
char WaitingForOthers=0;
|
||||
|
||||
int Kmatrix_nomovie_message=0;
|
||||
|
||||
extern char MaxPowerupsAllowed[],PowerupsInMine[];
|
||||
extern void newmenu_close();
|
||||
|
||||
void kmatrix_reactor (char *message);
|
||||
void kmatrix_phallic ();
|
||||
void kmatrix_redraw_coop();
|
||||
void kmatrix_ipx_reactor (char *message);
|
||||
void kmatrix_ipx_phallic ();
|
||||
void kmatrix_ipx_redraw_coop();
|
||||
|
||||
void kmatrix_draw_item( int i, int *sorted )
|
||||
void kmatrix_ipx_draw_item( int i, int *sorted )
|
||||
{
|
||||
int j, x, y;
|
||||
char temp[10];
|
||||
|
@ -113,7 +113,7 @@ void kmatrix_draw_item( int i, int *sorted )
|
|||
gr_printf( x ,y,"%4d/%s",Players[sorted[i]].net_kills_total,temp);
|
||||
}
|
||||
|
||||
void kmatrix_draw_coop_item( int i, int *sorted )
|
||||
void kmatrix_ipx_draw_coop_item( int i, int *sorted )
|
||||
{
|
||||
int x, y;
|
||||
|
||||
|
@ -135,17 +135,10 @@ void kmatrix_draw_coop_item( int i, int *sorted )
|
|||
gr_printf( x, y, "%d", Players[sorted[i]].net_killed_total);
|
||||
}
|
||||
|
||||
|
||||
void kmatrix_draw_names(int *sorted)
|
||||
void kmatrix_ipx_draw_names(int *sorted)
|
||||
{
|
||||
int j, x, color;
|
||||
|
||||
if (Kmatrix_nomovie_message)
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(63,0,0),-1 );
|
||||
gr_printf( CENTERSCREEN-FSPACX(40), FSPACY(20), "(Movie not played)");
|
||||
}
|
||||
|
||||
for (j=0; j<N_players; j++) {
|
||||
if (Game_mode & GM_TEAM)
|
||||
color = get_team(sorted[j]);
|
||||
|
@ -154,7 +147,7 @@ void kmatrix_draw_names(int *sorted)
|
|||
|
||||
x = FSPACX (70 + CENTERING_OFFSET(N_players) + j*25);
|
||||
|
||||
if (Players[sorted[j]].connected==0)
|
||||
if (Players[sorted[j]].connected==CONNECT_DISCONNECTED)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
@ -167,24 +160,17 @@ void kmatrix_draw_names(int *sorted)
|
|||
gr_printf( x, FSPACY(40), "K/E");
|
||||
}
|
||||
|
||||
void kmatrix_draw_coop_names(int *sorted)
|
||||
void kmatrix_ipx_draw_coop_names(int *sorted)
|
||||
{
|
||||
sorted=sorted;
|
||||
|
||||
if (Kmatrix_nomovie_message)
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(63,0,0),-1 );
|
||||
gr_printf( CENTERSCREEN-FSPACX(40), FSPACY(20), "(Movie not played)");
|
||||
}
|
||||
|
||||
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
|
||||
gr_printf( CENTERSCREEN, FSPACY(40), "SCORE");
|
||||
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
|
||||
gr_printf( CENTERSCREEN+FSPACX(50), FSPACY(40), "DEATHS");
|
||||
}
|
||||
|
||||
|
||||
void kmatrix_draw_deaths(int *sorted)
|
||||
void kmatrix_ipx_draw_deaths(int *sorted)
|
||||
{
|
||||
int y,x;
|
||||
char reactor_message[50];
|
||||
|
@ -228,81 +214,18 @@ void kmatrix_draw_deaths(int *sorted)
|
|||
}
|
||||
|
||||
if (Countdown_seconds_left <=0)
|
||||
kmatrix_reactor(TXT_REACTOR_EXPLODED);
|
||||
kmatrix_ipx_reactor(TXT_REACTOR_EXPLODED);
|
||||
else
|
||||
{
|
||||
sprintf((char *)&reactor_message, "%s: %d %s ", TXT_TIME_REMAINING, Countdown_seconds_left, TXT_SECONDS);
|
||||
kmatrix_reactor ((char *)&reactor_message);
|
||||
kmatrix_ipx_reactor ((char *)&reactor_message);
|
||||
}
|
||||
|
||||
if (Game_mode & GM_HOARD)
|
||||
kmatrix_phallic();
|
||||
kmatrix_ipx_phallic();
|
||||
}
|
||||
|
||||
void kmatrix_draw_coop_deaths(int *sorted)
|
||||
{
|
||||
int j, x, y;
|
||||
char reactor_message[50];
|
||||
|
||||
y = FSPACY(55 + N_players * 9);
|
||||
|
||||
gr_set_fontcolor( BM_XRGB(31,31,31),-1 );
|
||||
|
||||
x = CENTERSCREEN+FSPACX(50);
|
||||
gr_printf( x, y, TXT_DEATHS );
|
||||
|
||||
for (j=0; j<N_players; j++) {
|
||||
x = CENTERSCREEN+FSPACX(50);
|
||||
gr_printf( x, y, "%d", Players[sorted[j]].net_killed_total );
|
||||
}
|
||||
|
||||
y = FSPACY(55 + 72 + 35);
|
||||
x = FSPACX(35);
|
||||
|
||||
{
|
||||
int sw, sh, aw;
|
||||
|
||||
gr_set_fontcolor(gr_find_closest_color(63,20,0),-1);
|
||||
gr_get_string_size("P-Playing E-Escaped D-Died", &sw, &sh, &aw);
|
||||
|
||||
gr_printf( CENTERSCREEN-(sw/2), y,"P-Playing E-Escaped D-Died");
|
||||
|
||||
y+=(sh+5);
|
||||
gr_get_string_size("V-Viewing scores W-Waiting", &sw, &sh, &aw);
|
||||
|
||||
gr_printf( CENTERSCREEN-(sw/2), y,"V-Viewing scores W-Waiting");
|
||||
|
||||
}
|
||||
|
||||
y+=FSPACY(20);
|
||||
|
||||
{
|
||||
int sw, sh, aw;
|
||||
|
||||
gr_set_fontcolor(gr_find_closest_color(63,63,63),-1);
|
||||
|
||||
if (Players[Player_num].connected==CONNECT_KMATRIX_WAITING)
|
||||
{
|
||||
gr_get_string_size("Waiting for other players...",&sw, &sh, &aw);
|
||||
gr_printf( CENTERSCREEN-(sw/2), y,"Waiting for other players...");
|
||||
}
|
||||
else
|
||||
{
|
||||
gr_get_string_size(TXT_PRESS_ANY_KEY2, &sw, &sh, &aw);
|
||||
gr_printf( CENTERSCREEN-(sw/2), y, TXT_PRESS_ANY_KEY2);
|
||||
}
|
||||
}
|
||||
|
||||
if (Countdown_seconds_left <=0)
|
||||
kmatrix_reactor(TXT_REACTOR_EXPLODED);
|
||||
else
|
||||
{
|
||||
sprintf((char *)&reactor_message, "%s: %d %s ", TXT_TIME_REMAINING, Countdown_seconds_left, TXT_SECONDS);
|
||||
kmatrix_reactor ((char *)&reactor_message);
|
||||
}
|
||||
}
|
||||
|
||||
void kmatrix_reactor (char *message)
|
||||
void kmatrix_ipx_reactor (char *message)
|
||||
{
|
||||
static char oldmessage[50]={0};
|
||||
int sw, sh, aw;
|
||||
|
@ -323,7 +246,7 @@ void kmatrix_reactor (char *message)
|
|||
|
||||
extern int PhallicLimit,PhallicMan;
|
||||
|
||||
void kmatrix_phallic ()
|
||||
void kmatrix_ipx_phallic ()
|
||||
{
|
||||
int sw, sh, aw;
|
||||
char message[80];
|
||||
|
@ -342,9 +265,7 @@ void kmatrix_phallic ()
|
|||
gr_printf( CENTERSCREEN-(sw/2), FSPACY(55+72+3), message);
|
||||
}
|
||||
|
||||
void load_stars(void);
|
||||
|
||||
void kmatrix_redraw()
|
||||
void kmatrix_ipx_redraw()
|
||||
{
|
||||
int i, pcx_error, color;
|
||||
int sorted[MAX_NUM_NET_PLAYERS];
|
||||
|
@ -354,7 +275,7 @@ void kmatrix_redraw()
|
|||
|
||||
if (Game_mode & GM_MULTI_COOP)
|
||||
{
|
||||
kmatrix_redraw_coop();
|
||||
kmatrix_ipx_redraw_coop();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -375,7 +296,7 @@ void kmatrix_redraw()
|
|||
|
||||
multi_get_kill_list(sorted);
|
||||
|
||||
kmatrix_draw_names(sorted);
|
||||
kmatrix_ipx_draw_names(sorted);
|
||||
|
||||
for (i=0; i<N_players; i++ ) {
|
||||
if (Game_mode & GM_TEAM)
|
||||
|
@ -383,20 +304,20 @@ void kmatrix_redraw()
|
|||
else
|
||||
color = sorted[i];
|
||||
|
||||
if (Players[sorted[i]].connected==0)
|
||||
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
||||
kmatrix_draw_item( i, sorted );
|
||||
kmatrix_ipx_draw_item( i, sorted );
|
||||
}
|
||||
|
||||
kmatrix_draw_deaths(sorted);
|
||||
kmatrix_ipx_draw_deaths(sorted);
|
||||
|
||||
gr_palette_load(gr_palette);
|
||||
}
|
||||
|
||||
void kmatrix_redraw_coop()
|
||||
void kmatrix_ipx_redraw_coop()
|
||||
{
|
||||
int i, color;
|
||||
int sorted[MAX_NUM_NET_PLAYERS];
|
||||
|
@ -412,48 +333,38 @@ void kmatrix_redraw_coop()
|
|||
|
||||
multi_get_kill_list(sorted);
|
||||
|
||||
kmatrix_draw_coop_names(sorted);
|
||||
kmatrix_ipx_draw_coop_names(sorted);
|
||||
|
||||
for (i=0; i<N_players; i++ ) {
|
||||
|
||||
color = sorted[i];
|
||||
|
||||
if (Players[sorted[i]].connected==0)
|
||||
if (Players[sorted[i]].connected==CONNECT_DIED_IN_MINE)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
||||
kmatrix_draw_coop_item( i, sorted );
|
||||
kmatrix_ipx_draw_coop_item( i, sorted );
|
||||
}
|
||||
|
||||
kmatrix_draw_deaths(sorted);
|
||||
kmatrix_ipx_draw_deaths(sorted);
|
||||
|
||||
gr_palette_load(gr_palette);
|
||||
}
|
||||
|
||||
#define MAX_VIEW_TIME F1_0*15
|
||||
#define ENDLEVEL_IDLE_TIME F1_0*10
|
||||
|
||||
fix StartAbortMenuTime;
|
||||
|
||||
void kmatrix_view(int network)
|
||||
void kmatrix_ipx_view(int network)
|
||||
{
|
||||
int i, k, done,choice;
|
||||
fix entry_time = timer_get_approx_seconds();
|
||||
int key;
|
||||
int oldstates[MAX_PLAYERS];
|
||||
int previous_seconds_left=-1;
|
||||
int num_ready,num_escaped;
|
||||
|
||||
network=Game_mode & GM_NETWORK;
|
||||
|
||||
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
|
||||
digi_kill_sound_linked_to_object (Players[i].objnum);
|
||||
|
||||
set_screen_mode( SCREEN_MENU );
|
||||
|
||||
WaitingForOthers=0;
|
||||
|
||||
game_flush_inputs();
|
||||
|
||||
done = 0;
|
||||
|
@ -467,8 +378,7 @@ void kmatrix_view(int network)
|
|||
while(!done)
|
||||
{
|
||||
timer_delay2(50);
|
||||
kmatrix_redraw();
|
||||
kmatrix_kills_changed = 0;
|
||||
kmatrix_ipx_redraw();
|
||||
|
||||
//see if redbook song needs to be restarted
|
||||
RBACheckFinishedHook();
|
||||
|
@ -481,11 +391,10 @@ void kmatrix_view(int network)
|
|||
{
|
||||
if (Current_level_num==8)
|
||||
{
|
||||
Players[Player_num].connected=0;
|
||||
Players[Player_num].connected=CONNECT_DISCONNECTED;
|
||||
if (network)
|
||||
multi_send_endlevel_packet();
|
||||
multi_leave_game();
|
||||
Kmatrix_nomovie_message=0;
|
||||
longjmp(LeaveGame, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -500,22 +409,19 @@ void kmatrix_view(int network)
|
|||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
StartAbortMenuTime=timer_get_approx_seconds();
|
||||
choice=nm_messagebox1( NULL,multi_endlevel_poll3, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
|
||||
choice=nm_messagebox1( NULL,multi_endlevel_poll2, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
|
||||
}
|
||||
else
|
||||
choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
|
||||
if (choice==0)
|
||||
{
|
||||
Players[Player_num].connected=0;
|
||||
Players[Player_num].connected=CONNECT_DISCONNECTED;
|
||||
if (network)
|
||||
multi_send_endlevel_packet();
|
||||
multi_leave_game();
|
||||
Kmatrix_nomovie_message=0;
|
||||
longjmp(LeaveGame, 0);
|
||||
return;
|
||||
}
|
||||
else
|
||||
kmatrix_kills_changed=1;
|
||||
break;
|
||||
|
||||
case KEY_PRINT_SCREEN:
|
||||
|
@ -536,11 +442,10 @@ void kmatrix_view(int network)
|
|||
{
|
||||
if (Current_level_num==8)
|
||||
{
|
||||
Players[Player_num].connected=0;
|
||||
Players[Player_num].connected=CONNECT_DISCONNECTED;
|
||||
if (network)
|
||||
multi_send_endlevel_packet();
|
||||
multi_leave_game();
|
||||
Kmatrix_nomovie_message=0;
|
||||
longjmp(LeaveGame, 0);
|
||||
return;
|
||||
}
|
||||
|
@ -553,7 +458,7 @@ void kmatrix_view(int network)
|
|||
|
||||
if (network && (Game_mode & GM_NETWORK))
|
||||
{
|
||||
multi_endlevel_poll2(0, NULL, &key, 0);
|
||||
multi_endlevel_poll1();
|
||||
|
||||
for (num_escaped=0,num_ready=0,i=0;i<N_players;i++)
|
||||
{
|
||||
|
@ -562,27 +467,26 @@ void kmatrix_view(int network)
|
|||
// Check timeout for idle players
|
||||
if (timer_get_approx_seconds() > Netgame.players[i].LastPacketTime+ENDLEVEL_IDLE_TIME)
|
||||
{
|
||||
Players[i].connected = 0;
|
||||
multi_send_endlevel_sub(i);
|
||||
Players[i].connected = CONNECT_DISCONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
// Important: Make sure we keep connected state CONNECT_KMATRIX_WAITING even if player exits kmatrix loop which will change to CONNECT_WAITING! If we don't get all palyer packets in sync and order this condition is very handy to keep all connections alive!
|
||||
if ((oldstates[i]==CONNECT_END_MENU || oldstates[i]==CONNECT_KMATRIX_WAITING) && (Players[i].connected!=0 || Players[i].connected!=CONNECT_END_MENU || Players[i].connected!=CONNECT_KMATRIX_WAITING))
|
||||
Players[i].connected=CONNECT_KMATRIX_WAITING;
|
||||
// HACK: If a player legally exits kmatrix loop he will send the previous connect byte which can invalidate us from setting him to ready and let us stuck here forever... it's stupid to solve it this way, but for now I have no better idea.
|
||||
if ((oldstates[i]==CONNECT_END_MENU || oldstates[i]==CONNECT_KMATRIX_WAITING) && // player was viewing scores before...
|
||||
(Players[i].connected!=CONNECT_DISCONNECTED || Players[i].connected!=CONNECT_END_MENU || Players[i].connected!=CONNECT_KMATRIX_WAITING)) // ... but now he sends neither disconnect or further waiting signal - so he MUST be out of kmatrix already
|
||||
Players[i].connected=CONNECT_KMATRIX_WAITING;
|
||||
|
||||
if (Players[i].connected!=oldstates[i])
|
||||
{
|
||||
if (ConditionLetters[Players[i].connected]!=ConditionLetters[oldstates[i]])
|
||||
kmatrix_kills_changed=1;
|
||||
oldstates[i]=Players[i].connected;
|
||||
multi_send_endlevel_packet();
|
||||
}
|
||||
|
||||
if (Players[i].connected==0 || Players[i].connected==CONNECT_KMATRIX_WAITING)
|
||||
if (Players[i].connected==CONNECT_DISCONNECTED || Players[i].connected==CONNECT_KMATRIX_WAITING)
|
||||
num_ready++;
|
||||
|
||||
if (Players[i].connected!=1)
|
||||
if (Players[i].connected!=CONNECT_PLAYING)
|
||||
num_escaped++;
|
||||
}
|
||||
|
||||
|
@ -590,18 +494,6 @@ void kmatrix_view(int network)
|
|||
done=1;
|
||||
if (num_escaped>=N_players)
|
||||
Countdown_seconds_left=-1;
|
||||
|
||||
if (previous_seconds_left != Countdown_seconds_left)
|
||||
{
|
||||
previous_seconds_left=Countdown_seconds_left;
|
||||
kmatrix_kills_changed=1;
|
||||
}
|
||||
|
||||
if ( kmatrix_kills_changed )
|
||||
{
|
||||
kmatrix_redraw();
|
||||
kmatrix_kills_changed=0;
|
||||
}
|
||||
}
|
||||
gr_flip();
|
||||
}
|
||||
|
@ -613,7 +505,324 @@ void kmatrix_view(int network)
|
|||
|
||||
game_flush_inputs();
|
||||
|
||||
Kmatrix_nomovie_message=0;
|
||||
|
||||
newmenu_close();
|
||||
}
|
||||
|
||||
/* IPX CODE - END */
|
||||
|
||||
/* NEW CODE - START */
|
||||
|
||||
#define KMATRIX_VIEW_SEC 7 // Time after reactor explosion until new level - in seconds
|
||||
void kmatrix_phallic ();
|
||||
void kmatrix_redraw_coop();
|
||||
|
||||
void kmatrix_draw_item( int i, int *sorted )
|
||||
{
|
||||
int j, x, y;
|
||||
char temp[10];
|
||||
|
||||
y = FSPACY(50+i*9);
|
||||
gr_printf( FSPACX(CENTERING_OFFSET(N_players)), y, "%s", Players[sorted[i]].callsign );
|
||||
|
||||
for (j=0; j<N_players; j++)
|
||||
{
|
||||
x = FSPACX(70 + CENTERING_OFFSET(N_players) + j*25);
|
||||
|
||||
if (sorted[i]==sorted[j])
|
||||
{
|
||||
if (kill_matrix[sorted[i]][sorted[j]] == 0)
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(10,10,10),-1 );
|
||||
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
|
||||
}
|
||||
else
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
|
||||
gr_printf( x, y, "-%d", kill_matrix[sorted[i]][sorted[j]] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (kill_matrix[sorted[i]][sorted[j]] <= 0)
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(10,10,10),-1 );
|
||||
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
|
||||
}
|
||||
else
|
||||
{
|
||||
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
|
||||
gr_printf( x, y, "%d", kill_matrix[sorted[i]][sorted[j]] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Players[sorted[i]].net_killed_total+Players[sorted[i]].net_kills_total==0)
|
||||
sprintf (temp,"NA");
|
||||
else
|
||||
sprintf (temp,"%d%%",(int)((float)((float)Players[sorted[i]].net_kills_total/((float)Players[sorted[i]].net_killed_total+(float)Players[sorted[i]].net_kills_total))*100.0));
|
||||
|
||||
x = FSPACX(60 + CENTERING_OFFSET(N_players) + N_players*25);
|
||||
gr_set_fontcolor( BM_XRGB(25,25,25),-1 );
|
||||
gr_printf( x ,y,"%4d/%s",Players[sorted[i]].net_kills_total,temp);
|
||||
}
|
||||
|
||||
void kmatrix_draw_coop_item( int i, int *sorted )
|
||||
{
|
||||
int x, y;
|
||||
|
||||
y = FSPACY(50+i*9);
|
||||
gr_printf( FSPACX(CENTERING_OFFSET(N_players)), y, "%s", Players[sorted[i]].callsign );
|
||||
x = CENTERSCREEN;
|
||||
gr_set_fontcolor( BM_XRGB(60,40,10),-1 );
|
||||
gr_printf( x, y, "%d", Players[sorted[i]].score );
|
||||
x = CENTERSCREEN+FSPACX(50);
|
||||
gr_set_fontcolor( BM_XRGB(60,40,10),-1 );
|
||||
gr_printf( x, y, "%d", Players[sorted[i]].net_killed_total);
|
||||
}
|
||||
|
||||
void kmatrix_draw_names(int *sorted)
|
||||
{
|
||||
int j, x, color;
|
||||
|
||||
for (j=0; j<N_players; j++)
|
||||
{
|
||||
if (Game_mode & GM_TEAM)
|
||||
color = get_team(sorted[j]);
|
||||
else
|
||||
color = sorted[j];
|
||||
|
||||
x = FSPACX (70 + CENTERING_OFFSET(N_players) + j*25);
|
||||
|
||||
if (Players[sorted[j]].connected==CONNECT_DISCONNECTED)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
||||
gr_printf( x, FSPACY(40), "%c", Players[sorted[j]].callsign[0] );
|
||||
}
|
||||
|
||||
x = FSPACX(72 + CENTERING_OFFSET(N_players) + N_players*25);
|
||||
gr_set_fontcolor( BM_XRGB(31,31,31),-1 );
|
||||
gr_printf( x, FSPACY(40), "K/E");
|
||||
}
|
||||
|
||||
void kmatrix_draw_coop_names(int *sorted)
|
||||
{
|
||||
sorted=sorted;
|
||||
|
||||
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
|
||||
gr_printf( CENTERSCREEN, FSPACY(40), "SCORE");
|
||||
gr_set_fontcolor( BM_XRGB(63,31,31),-1 );
|
||||
gr_printf( CENTERSCREEN+FSPACX(50), FSPACY(40), "DEATHS");
|
||||
}
|
||||
|
||||
extern int PhallicLimit,PhallicMan;
|
||||
|
||||
void kmatrix_phallic ()
|
||||
{
|
||||
int sw, sh, aw;
|
||||
char message[80];
|
||||
|
||||
if (PhallicMan==-1)
|
||||
strcpy (message,"There was no record set for this level.");
|
||||
else
|
||||
sprintf (message,"%s had the best record at %d points.",Players[PhallicMan].callsign,PhallicLimit);
|
||||
|
||||
grd_curcanv->cv_font = GAME_FONT;
|
||||
gr_set_fontcolor(gr_find_closest_color(63,63,63),-1);
|
||||
gr_get_string_size(message, &sw, &sh, &aw);
|
||||
gr_printf( CENTERSCREEN-(sw/2), FSPACY(55+72+3), message);
|
||||
}
|
||||
|
||||
void kmatrix_status_msg (fix time, int reactor)
|
||||
{
|
||||
grd_curcanv->cv_font = GAME_FONT;
|
||||
gr_set_fontcolor(gr_find_closest_color(255,255,255),-1);
|
||||
|
||||
if (reactor)
|
||||
gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Waiting for players to finish level. Reactor time: T-%d", time);
|
||||
else
|
||||
gr_printf(0x8000, SHEIGHT-LINE_SPACING, "Level finished. Wait (%d) to proceed or ESC to Quit.", time);
|
||||
}
|
||||
|
||||
void kmatrix_redraw()
|
||||
{
|
||||
int i, pcx_error, color;
|
||||
int sorted[MAX_NUM_NET_PLAYERS];
|
||||
|
||||
pcx_error = pcx_read_fullscr(STARS_BACKGROUND, gr_palette);
|
||||
Assert(pcx_error == PCX_ERROR_NONE);
|
||||
|
||||
if (Game_mode & GM_MULTI_COOP)
|
||||
{
|
||||
kmatrix_redraw_coop();
|
||||
}
|
||||
else
|
||||
{
|
||||
multi_sort_kill_list();
|
||||
gr_set_current_canvas(NULL);
|
||||
grd_curcanv->cv_font = MEDIUM3_FONT;
|
||||
|
||||
if (Game_mode & GM_CAPTURE)
|
||||
gr_string( 0x8000, FSPACY(10), "CAPTURE THE FLAG SUMMARY");
|
||||
else if (Game_mode & GM_HOARD)
|
||||
gr_string( 0x8000, FSPACY(10), "HOARD SUMMARY");
|
||||
else
|
||||
gr_string( 0x8000, FSPACY(10), TXT_KILL_MATRIX_TITLE);
|
||||
|
||||
grd_curcanv->cv_font = GAME_FONT;
|
||||
multi_get_kill_list(sorted);
|
||||
kmatrix_draw_names(sorted);
|
||||
|
||||
for (i=0; i<N_players; i++ )
|
||||
{
|
||||
if (Game_mode & GM_TEAM)
|
||||
color = get_team(sorted[i]);
|
||||
else
|
||||
color = sorted[i];
|
||||
|
||||
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
||||
kmatrix_draw_item( i, sorted );
|
||||
}
|
||||
}
|
||||
|
||||
gr_palette_load(gr_palette);
|
||||
}
|
||||
|
||||
void kmatrix_redraw_coop()
|
||||
{
|
||||
int i, color;
|
||||
int sorted[MAX_NUM_NET_PLAYERS];
|
||||
|
||||
multi_sort_kill_list();
|
||||
gr_set_current_canvas(NULL);
|
||||
grd_curcanv->cv_font = MEDIUM3_FONT;
|
||||
gr_string( 0x8000, FSPACY(10), "COOPERATIVE SUMMARY");
|
||||
grd_curcanv->cv_font = GAME_FONT;
|
||||
multi_get_kill_list(sorted);
|
||||
kmatrix_draw_coop_names(sorted);
|
||||
|
||||
for (i=0; i<N_players; i++ )
|
||||
{
|
||||
color = sorted[i];
|
||||
|
||||
if (Players[sorted[i]].connected==CONNECT_DISCONNECTED)
|
||||
gr_set_fontcolor(gr_find_closest_color(31,31,31),-1);
|
||||
else
|
||||
gr_set_fontcolor(BM_XRGB(player_rgb[color].r,player_rgb[color].g,player_rgb[color].b),-1 );
|
||||
|
||||
kmatrix_draw_coop_item( i, sorted );
|
||||
}
|
||||
|
||||
gr_palette_load(gr_palette);
|
||||
}
|
||||
|
||||
void kmatrix_view(int network)
|
||||
{
|
||||
int done = 0, i = 0, k = 0, choice = 0;
|
||||
fix end_time = -1;
|
||||
|
||||
set_screen_mode( SCREEN_MENU );
|
||||
game_flush_inputs();
|
||||
|
||||
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
|
||||
digi_kill_sound_linked_to_object (Players[i].objnum);
|
||||
|
||||
while (!done)
|
||||
{
|
||||
int playing = 0;
|
||||
fix time = timer_get_approx_seconds();
|
||||
|
||||
timer_delay2(50);
|
||||
kmatrix_redraw();
|
||||
RBACheckFinishedHook(); //see if redbook song needs to be restarted
|
||||
|
||||
if (network)
|
||||
multi_do_protocol_frame(0, 1);
|
||||
|
||||
// Check if all connected players are also looking at this screen ...
|
||||
for (i = 0; i < MAX_PLAYERS; i++)
|
||||
if (Players[i].connected)
|
||||
if (Players[i].connected != CONNECT_END_MENU && Players[i].connected != CONNECT_DIED_IN_MINE)
|
||||
playing = 1;
|
||||
|
||||
// ... and let the reactor blow sky high!
|
||||
if (!playing)
|
||||
Countdown_seconds_left = -1;
|
||||
|
||||
// If Reactor is finished and end_time not inited, set the time when we will exit this loop
|
||||
if (end_time == -1 && Countdown_seconds_left < 0 && !playing)
|
||||
end_time = time + (KMATRIX_VIEW_SEC * F1_0);
|
||||
|
||||
// Check if end_time has been reached and exit loop
|
||||
if (time >= end_time && end_time != -1)
|
||||
done = 1;
|
||||
|
||||
if (playing)
|
||||
kmatrix_status_msg(Countdown_seconds_left, 1);
|
||||
else
|
||||
kmatrix_status_msg(f2i(time-end_time), 0);
|
||||
|
||||
k = key_inkey();
|
||||
switch( k )
|
||||
{
|
||||
case KEY_ESC:
|
||||
if (network)
|
||||
{
|
||||
StartAbortMenuTime=timer_get_approx_seconds();
|
||||
choice=nm_messagebox1( NULL,multi_endlevel_poll2, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
|
||||
}
|
||||
else
|
||||
choice=nm_messagebox( NULL, 2, TXT_YES, TXT_NO, TXT_ABORT_GAME );
|
||||
|
||||
if (choice==0)
|
||||
{
|
||||
Players[Player_num].connected=CONNECT_DISCONNECTED;
|
||||
|
||||
if (network)
|
||||
multi_send_endlevel_packet();
|
||||
|
||||
multi_leave_game();
|
||||
longjmp(LeaveGame, 0);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
|
||||
case KEY_PRINT_SCREEN:
|
||||
save_screen_shot(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
gr_flip();
|
||||
}
|
||||
|
||||
if (network)
|
||||
multi_send_endlevel_packet(); // make sure
|
||||
|
||||
game_flush_inputs();
|
||||
newmenu_close();
|
||||
|
||||
if (is_D2_OEM)
|
||||
{
|
||||
if (Current_level_num==8)
|
||||
{
|
||||
Players[Player_num].connected=CONNECT_DISCONNECTED;
|
||||
|
||||
if (network)
|
||||
multi_send_endlevel_packet();
|
||||
|
||||
multi_leave_game();
|
||||
longjmp(LeaveGame, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NEW CODE - END */
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* $Id: kmatrix.h,v 1.1.1.1 2006/03/17 19:57:28 zicodxx Exp $ */
|
||||
/*
|
||||
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
||||
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
||||
|
@ -22,8 +21,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#ifndef _KMATRIX_H
|
||||
#define _KMATRIX_H
|
||||
|
||||
extern int kmatrix_kills_changed;
|
||||
|
||||
void kmatrix_ipx_view(int network);
|
||||
void kmatrix_view(int network);
|
||||
|
||||
#endif /* _KMATRIX_H */
|
||||
|
|
127
main/menu.c
127
main/menu.c
|
@ -45,11 +45,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#include "text.h"
|
||||
#include "gamefont.h"
|
||||
#include "newmenu.h"
|
||||
#ifdef NETWORK
|
||||
# include "net_ipx.h"
|
||||
# include "ipxdrv.h"
|
||||
# include "multi.h"
|
||||
#endif
|
||||
#include "scores.h"
|
||||
#include "playsave.h"
|
||||
#include "kconfig.h"
|
||||
|
@ -66,7 +61,11 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#include "gauges.h"
|
||||
#include "powerup.h"
|
||||
#include "strutil.h"
|
||||
|
||||
#ifdef NETWORK
|
||||
# include "net_ipx.h"
|
||||
# include "net_udp.h"
|
||||
# include "multi.h"
|
||||
#endif
|
||||
#ifdef EDITOR
|
||||
#include "editor/editor.h"
|
||||
#endif
|
||||
|
@ -84,8 +83,6 @@ enum MENUS
|
|||
MENU_SAVE_GAME,
|
||||
MENU_DEMO_PLAY,
|
||||
MENU_LOAD_LEVEL,
|
||||
MENU_START_IPX_NETGAME,
|
||||
MENU_JOIN_IPX_NETGAME,
|
||||
MENU_CONFIG,
|
||||
MENU_REJOIN_NETGAME,
|
||||
MENU_DIFFICULTY,
|
||||
|
@ -103,12 +100,12 @@ enum MENUS
|
|||
|
||||
// Only if networking is enabled...
|
||||
#ifdef NETWORK
|
||||
MENU_START_UDP_NETGAME,
|
||||
MENU_JOIN_MANUAL_UDP_NETGAME,
|
||||
MENU_JOIN_LIST_UDP_NETGAME,
|
||||
MENU_START_IPX_NETGAME,
|
||||
MENU_JOIN_IPX_NETGAME,
|
||||
MENU_BROWSE_UDP_NETGAME, // UDP/IP support
|
||||
MENU_START_UDP_NETGAME,
|
||||
MENU_JOIN_UDP_NETGAME,
|
||||
MENU_START_KALI_NETGAME, // Kali support
|
||||
MENU_START_KALI_NETGAME, // xKali support (not Windows Kali! Windows Kali is over IPX!)
|
||||
MENU_JOIN_KALI_NETGAME,
|
||||
#endif
|
||||
};
|
||||
|
@ -121,10 +118,7 @@ enum MENUS
|
|||
// Function Prototypes added after LINTING
|
||||
void do_option(int select);
|
||||
void do_new_game_menu(void);
|
||||
#ifdef NETWORK
|
||||
void do_multi_player_menu(void);
|
||||
void do_ip_manual_join_menu();
|
||||
#endif //NETWORK
|
||||
void do_multi_player_menu();
|
||||
extern void newmenu_close();
|
||||
extern void ReorderPrimary();
|
||||
extern void ReorderSecondary();
|
||||
|
@ -337,6 +331,18 @@ void do_option ( int select)
|
|||
|
||||
|
||||
#ifdef NETWORK
|
||||
case MENU_START_UDP_NETGAME:
|
||||
multi_protocol = MULTI_PROTO_UDP;
|
||||
net_udp_start_game();
|
||||
break;
|
||||
case MENU_JOIN_MANUAL_UDP_NETGAME:
|
||||
multi_protocol = MULTI_PROTO_UDP;
|
||||
net_udp_manual_join_game();
|
||||
break;
|
||||
case MENU_JOIN_LIST_UDP_NETGAME:
|
||||
multi_protocol = MULTI_PROTO_UDP;
|
||||
//net_udp_list_join_game();
|
||||
break;
|
||||
case MENU_START_IPX_NETGAME:
|
||||
multi_protocol = MULTI_PROTO_IPX;
|
||||
ipxdrv_set(NETPROTO_IPX);
|
||||
|
@ -357,12 +363,6 @@ void do_option ( int select)
|
|||
ipxdrv_set(NETPROTO_KALINIX);
|
||||
net_ipx_join_game();
|
||||
break;
|
||||
case MENU_START_UDP_NETGAME:
|
||||
// FIXME
|
||||
break;
|
||||
case MENU_JOIN_UDP_NETGAME:
|
||||
// FIXME
|
||||
break;
|
||||
case MENU_MULTIPLAYER:
|
||||
do_multi_player_menu();
|
||||
break;
|
||||
|
@ -813,8 +813,8 @@ void do_misc_menu()
|
|||
#ifdef NETWORK
|
||||
void do_multi_player_menu()
|
||||
{
|
||||
int menu_choice[9];
|
||||
newmenu_item m[9];
|
||||
int menu_choice[12];
|
||||
newmenu_item m[12];
|
||||
int choice = 0, num_options = 0;
|
||||
int old_game_mode;
|
||||
|
||||
|
@ -822,16 +822,24 @@ void do_multi_player_menu()
|
|||
old_game_mode = Game_mode;
|
||||
num_options = 0;
|
||||
|
||||
#ifdef NATIVE_IPX
|
||||
ADD_ITEM("Start IPX Netgame", MENU_START_IPX_NETGAME, -1);
|
||||
ADD_ITEM("Join IPX Netgame\n", MENU_JOIN_IPX_NETGAME, -1);
|
||||
#endif //NATIVE_IPX
|
||||
ADD_ITEM("Start UDP/IP Netgame", MENU_START_UDP_NETGAME, -1);
|
||||
ADD_ITEM("Join UDP/IP Netgame\n", MENU_JOIN_UDP_NETGAME, -1);
|
||||
#ifdef KALINIX
|
||||
ADD_ITEM("Start Kali Netgame", MENU_START_KALI_NETGAME, -1);
|
||||
ADD_ITEM("Join Kali Netgame", MENU_JOIN_KALI_NETGAME, -1);
|
||||
#endif // KALINIX
|
||||
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="UDP:"; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_UDP_NETGAME; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++;
|
||||
//m[num_options].type=NM_TYPE_MENU; m[num_options].text="FIND LAN/ONLINE GAMES"; menu_choice[num_options]=MENU_JOIN_LIST_UDP_NETGAME; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME MANUALLY"; menu_choice[num_options]=MENU_JOIN_MANUAL_UDP_NETGAME; num_options++;
|
||||
|
||||
#ifdef HAVE_NETIPX_IPX_H
|
||||
m[num_options].type=NM_TYPE_TEXT; m[num_options].text=""; num_options++;
|
||||
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="IPX:"; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_IPX_NETGAME; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME"; menu_choice[num_options]=MENU_JOIN_IPX_NETGAME; num_options++;
|
||||
#endif //HAVE_NETIPX_IPX_H
|
||||
#ifdef __LINUX__
|
||||
m[num_options].type=NM_TYPE_TEXT; m[num_options].text=""; num_options++;
|
||||
m[num_options].type=NM_TYPE_TEXT; m[num_options].text="XKALI:"; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="HOST GAME"; menu_choice[num_options]=MENU_START_KALI_NETGAME; num_options++;
|
||||
m[num_options].type=NM_TYPE_MENU; m[num_options].text="JOIN GAME"; menu_choice[num_options]=MENU_JOIN_KALI_NETGAME; num_options++;
|
||||
#endif // __LINUX__
|
||||
|
||||
choice = newmenu_do1( NULL, TXT_MULTIPLAYER, num_options, m, NULL, choice );
|
||||
|
||||
|
@ -843,57 +851,6 @@ void do_multi_player_menu()
|
|||
|
||||
} while( choice > -1 );
|
||||
}
|
||||
|
||||
void do_ip_manual_join_menu()
|
||||
{
|
||||
int menu_choice[3];
|
||||
newmenu_item m[3];
|
||||
int choice = 0, num_options = 0, j = 0;
|
||||
int old_game_mode;
|
||||
char buf[128]="";
|
||||
|
||||
if (*GameCfg.MplIpHostAddr) {
|
||||
sprintf(buf,"%s",GameCfg.MplIpHostAddr);
|
||||
|
||||
for (j=0; buf[j] != '\0'; j++) {
|
||||
switch (buf[j]) {
|
||||
case ' ':
|
||||
buf[j] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (*GameArg.MplIpHostAddr) {
|
||||
sprintf(buf,"%s",GameArg.MplIpHostAddr);
|
||||
|
||||
for (j=0; buf[j] != '\0'; j++) {
|
||||
switch (buf[j]) {
|
||||
case ' ':
|
||||
buf[j] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
old_game_mode = Game_mode;
|
||||
num_options = 0;
|
||||
|
||||
m[num_options].type = NM_TYPE_INPUT; m[num_options].text=buf; m[num_options].text_len=128;menu_choice[num_options]=-1; num_options++;
|
||||
|
||||
choice = newmenu_do1( NULL, "ENTER IP OR HOSTNAME", num_options, m, NULL, choice );
|
||||
|
||||
if ( choice > -1 ){
|
||||
strncpy(GameCfg.MplIpHostAddr, buf, 128);
|
||||
// FIXME !! UDPConnectManual(buf);
|
||||
}
|
||||
|
||||
if (old_game_mode != Game_mode)
|
||||
{
|
||||
strncpy(GameCfg.MplIpHostAddr, buf, 128);
|
||||
break; // leave menu
|
||||
}
|
||||
} while( choice > -1 );
|
||||
}
|
||||
#endif // NETWORK
|
||||
|
||||
void do_options_menu()
|
||||
|
|
421
main/multi.c
421
main/multi.c
|
@ -27,6 +27,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#include "strutil.h"
|
||||
#include "game.h"
|
||||
#include "net_ipx.h"
|
||||
#include "net_udp.h"
|
||||
#include "multi.h"
|
||||
#include "object.h"
|
||||
#include "laser.h"
|
||||
|
@ -148,12 +149,16 @@ int multi_leave_menu = 0;
|
|||
int multi_quit_game = 0;
|
||||
int PacketUrgent = 0;
|
||||
|
||||
// For rejoin object syncing
|
||||
// For rejoin object syncing (used here and all protocols - globally)
|
||||
|
||||
int Network_send_objects = 0; // Are we in the process of sending objects to a player?
|
||||
int Network_send_object_mode = 0; // What type of objects are we sending, static or dynamic?
|
||||
int Network_send_objnum = -1; // What object are we sending next?
|
||||
int Network_rejoined = 0; // Did WE rejoin this game?
|
||||
int Network_new_game = 0; // Is this the first level of a new game?
|
||||
int Network_sending_extras=0;
|
||||
int Player_joining_extras=-1; // This is so we know who to send 'latecomer' packets to.
|
||||
int Network_player_added = 0; // Is this a new player or a returning player?
|
||||
|
||||
ushort my_segments_checksum = 0;
|
||||
|
||||
|
@ -161,6 +166,10 @@ netgame_info Netgame;
|
|||
|
||||
bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEXTURES];
|
||||
|
||||
// Globals for protocol-bound Refuse-functions
|
||||
char RefuseThisPlayer=0,WaitForRefuseAnswer=0,RefuseTeam,RefusePlayerName[12];
|
||||
fix RefuseTimeLimit=0;
|
||||
|
||||
typedef struct netplayer_stats {
|
||||
ubyte message_type;
|
||||
ubyte Player_num; // Who am i?
|
||||
|
@ -192,7 +201,7 @@ typedef struct netplayer_stats {
|
|||
} netplayer_stats;
|
||||
|
||||
int message_length[MULTI_MAX_TYPE+1] = {
|
||||
24, // POSITION
|
||||
25, // POSITION
|
||||
3, // REAPPEAR
|
||||
8, // FIRE
|
||||
5, // KILL
|
||||
|
@ -247,7 +256,7 @@ int message_length[MULTI_MAX_TYPE+1] = {
|
|||
2, // MULTI_CAPTURE_BONUS
|
||||
2, // MULTI_GOT_FLAG
|
||||
12, // MULTI_DROP_FLAG
|
||||
142, // MULTI_ROBOT_CONTROLS
|
||||
1, // MULTI_ROBOT_CONTROLS - UNUSED
|
||||
2, // MULTI_FINISH_GAME
|
||||
3, // MULTI_RANK
|
||||
1, // MULTI_MODEM_PING
|
||||
|
@ -301,6 +310,13 @@ int GetMyNetRanking()
|
|||
return (rank+1);
|
||||
}
|
||||
|
||||
void ClipRank (ubyte *rank)
|
||||
{
|
||||
// This function insures no crashes when dealing with D2 1.0
|
||||
if (*rank > 9)
|
||||
*rank = 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Functions that replace what used to be macros
|
||||
//
|
||||
|
@ -413,25 +429,15 @@ int multi_objnum_is_past(int objnum)
|
|||
case MULTI_PROTO_IPX:
|
||||
return net_ipx_objnum_is_past(objnum);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
return net_udp_objnum_is_past(objnum);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_objnum_is_past\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void multi_do_ping_frame()
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
return net_ipx_ping_all();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_do_ping_frame\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Part 1 : functions whose main purpose in life is to divert the flow
|
||||
// of execution to either network specific code based
|
||||
|
@ -450,19 +456,20 @@ multi_endlevel_score(void)
|
|||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
old_connect = Players[Player_num].connected;
|
||||
if (Players[Player_num].connected!=3)
|
||||
if (Players[Player_num].connected!=CONNECT_DIED_IN_MINE)
|
||||
Players[Player_num].connected = CONNECT_END_MENU;
|
||||
Network_status = NETSTAT_ENDLEVEL;
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Do the actual screen we wish to show
|
||||
|
||||
Function_mode = FMODE_MENU;
|
||||
|
||||
kmatrix_view(Game_mode & GM_NETWORK);
|
||||
if (multi_protocol == MULTI_PROTO_IPX)
|
||||
kmatrix_ipx_view(Game_mode & GM_NETWORK);
|
||||
else
|
||||
kmatrix_view(Game_mode & GM_NETWORK);
|
||||
|
||||
Function_mode = FMODE_GAME;
|
||||
|
||||
|
@ -473,19 +480,16 @@ multi_endlevel_score(void)
|
|||
Players[Player_num].connected = old_connect;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_COOP)
|
||||
{
|
||||
for (i = 0; i < MaxNumNetPlayers; i++)
|
||||
// Reset keys
|
||||
Players[i].flags &= ~(PLAYER_FLAGS_BLUE_KEY | PLAYER_FLAGS_RED_KEY | PLAYER_FLAGS_GOLD_KEY);
|
||||
}
|
||||
|
||||
for (i = 0; i < MaxNumNetPlayers; i++)
|
||||
Players[i].flags &= ~(PLAYER_FLAGS_FLAG); // Clear capture flag
|
||||
|
||||
#endif
|
||||
|
||||
for (i=0;i<MAX_PLAYERS;i++)
|
||||
Players[i].KillGoalCount=0;
|
||||
|
||||
|
@ -494,7 +498,6 @@ multi_endlevel_score(void)
|
|||
MaxPowerupsAllowed[i]=0;
|
||||
PowerupsInMine[i]=0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -526,14 +529,12 @@ multi_new_game(void)
|
|||
Players[i].KillGoalCount=0;
|
||||
}
|
||||
|
||||
#ifndef SHAREWARE
|
||||
for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
|
||||
{
|
||||
robot_controlled[i] = -1;
|
||||
robot_agitation[i] = 0;
|
||||
robot_fired[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
team_kills[0] = team_kills[1] = 0;
|
||||
Endlevel_sequence = 0;
|
||||
|
@ -616,11 +617,9 @@ multi_sort_kill_list(void)
|
|||
|
||||
for (i = 0; i < MAX_NUM_NET_PLAYERS; i++)
|
||||
{
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_COOP)
|
||||
kills[i] = Players[i].score;
|
||||
else
|
||||
#endif
|
||||
if (Show_kill_list==2)
|
||||
{
|
||||
if (Players[i].net_killed_total+Players[i].net_kills_total==0)
|
||||
|
@ -662,7 +661,6 @@ void multi_compute_kill(int killer, int killed)
|
|||
char killed_name[(CALLSIGN_LEN*2)+4];
|
||||
char killer_name[(CALLSIGN_LEN*2)+4];
|
||||
|
||||
kmatrix_kills_changed = 1;
|
||||
Multi_killed_yourself=0;
|
||||
|
||||
// Both object numbers are localized already!
|
||||
|
@ -700,7 +698,7 @@ void multi_compute_kill(int killer, int killed)
|
|||
digi_play_sample( SOUND_HUD_KILL, F3_0 );
|
||||
|
||||
if (Control_center_destroyed)
|
||||
Players[killed_pnum].connected=3;
|
||||
Players[killed_pnum].connected=CONNECT_DIED_IN_MINE;
|
||||
|
||||
if (killer_type == OBJ_CNTRLCEN)
|
||||
{
|
||||
|
@ -720,7 +718,6 @@ void multi_compute_kill(int killer, int killed)
|
|||
return;
|
||||
}
|
||||
|
||||
#ifndef SHAREWARE
|
||||
else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST))
|
||||
{
|
||||
if (killer_id==PMINE_ID && killer_type!=OBJ_ROBOT)
|
||||
|
@ -743,24 +740,6 @@ void multi_compute_kill(int killer, int killed)
|
|||
Players[killed_pnum].net_killed_total++;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
else if ((killer_type != OBJ_PLAYER) && (killer_type != OBJ_GHOST) && (killer_id!=PMINE_ID))
|
||||
{
|
||||
Int3(); // Illegal killer type?
|
||||
return;
|
||||
}
|
||||
if (killer_id==PMINE_ID)
|
||||
{
|
||||
if (killed_pnum==Player_num)
|
||||
HUD_init_message("You were killed by a mine!");
|
||||
else
|
||||
HUD_init_message("%s was killed by a mine!",killed_name);
|
||||
|
||||
Players[killed_pnum].net_killed_total++;
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
killer_pnum = Objects[killer].id;
|
||||
|
||||
|
@ -883,6 +862,9 @@ void multi_do_protocol_frame(int force, int listen)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_do_frame(force, listen);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_do_frame(force, listen);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_do_protocol_frame\n");
|
||||
break;
|
||||
|
@ -920,12 +902,10 @@ multi_do_frame(void)
|
|||
if (!multi_in_menu)
|
||||
multi_leave_menu = 0;
|
||||
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_ROBOTS)
|
||||
{
|
||||
multi_check_robot_timeout();
|
||||
}
|
||||
#endif
|
||||
|
||||
multi_do_protocol_frame(0, 1);
|
||||
|
||||
|
@ -937,21 +917,20 @@ multi_do_frame(void)
|
|||
}
|
||||
|
||||
void
|
||||
multi_send_data(char *buf, int len, int repeat)
|
||||
multi_send_data(char *buf, int len, int priority)
|
||||
{
|
||||
Assert(len == message_length[(int)buf[0]]);
|
||||
Assert(buf[0] <= MULTI_MAX_TYPE);
|
||||
// Assert(buf[0] >= 0);
|
||||
|
||||
if (Game_mode & GM_NETWORK)
|
||||
Assert(buf[0] > 0);
|
||||
|
||||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_data((unsigned char *)buf, len, repeat);
|
||||
net_ipx_send_data((unsigned char *)buf, len, priority);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_data((unsigned char *)buf, len, priority);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_data_real\n");
|
||||
|
@ -973,10 +952,10 @@ multi_leave_game(void)
|
|||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
Net_create_loc = 0;
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
AdjustMineSpawn();
|
||||
multi_cap_objects();
|
||||
drop_player_eggs(ConsoleObject);
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
multi_send_player_explode(MULTI_PLAYER_DROP);
|
||||
}
|
||||
|
||||
|
@ -989,6 +968,9 @@ multi_leave_game(void)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_leave_game();
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_leave_game();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_leave_game\n");
|
||||
break;
|
||||
|
@ -1024,6 +1006,9 @@ multi_endlevel(int *secret)
|
|||
case MULTI_PROTO_IPX:
|
||||
result = net_ipx_endlevel(secret);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
result = net_udp_endlevel(secret);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_endlevel\n");
|
||||
break;
|
||||
|
@ -1032,12 +1017,31 @@ multi_endlevel(int *secret)
|
|||
return(result);
|
||||
}
|
||||
|
||||
void multi_endlevel_poll1( int nitems, struct newmenu_item * menus, int * key, int citem )
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_kmatrix_poll1( nitems, menus, key, citem );
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_kmatrix_poll1( nitems, menus, key, citem );
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_endlevel_poll1\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, int citem )
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_endlevel_poll2( nitems, menus, key, citem );
|
||||
net_ipx_kmatrix_poll2( nitems, menus, key, citem );
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_kmatrix_poll2( nitems, menus, key, citem );
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_endlevel_poll2\n");
|
||||
|
@ -1045,19 +1049,6 @@ void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, i
|
|||
}
|
||||
}
|
||||
|
||||
void multi_endlevel_poll3( int nitems, struct newmenu_item * menus, int * key, int citem )
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_endlevel_poll3( nitems, menus, key, citem );
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_endlevel_poll3\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void multi_send_endlevel_packet()
|
||||
{
|
||||
switch (multi_protocol)
|
||||
|
@ -1065,25 +1056,15 @@ void multi_send_endlevel_packet()
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_endlevel_packet();
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_endlevel_packet();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_endlevel_packet\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void multi_send_endlevel_sub(int player_num)
|
||||
{
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_endlevel_sub(player_num);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_endlevel_sub\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Part 2 : functions that act on network messages and change the
|
||||
// the state of the game in some way.
|
||||
|
@ -1114,7 +1095,7 @@ multi_menu_poll(void)
|
|||
// The following three [hackish] lines will go away eventually
|
||||
calc_frame_time();
|
||||
memset(&Controls,0,sizeof(control_info)); // from game.c (was in below function)
|
||||
GameProcessFrame(void);
|
||||
GameProcessFrame();
|
||||
|
||||
multi_in_menu--;
|
||||
|
||||
|
@ -1346,6 +1327,9 @@ void multi_send_message_end()
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_netgame_update();
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_netgame_update();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_message_end\n");
|
||||
break;
|
||||
|
@ -1417,7 +1401,10 @@ void multi_send_message_end()
|
|||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_dump_player(Netgame.players[i].protocol.ipx.server,Netgame.players[i].protocol.ipx.node, 7);
|
||||
net_ipx_dump_player(Netgame.players[i].protocol.ipx.server,Netgame.players[i].protocol.ipx.node, DUMP_KICKED);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_dump_player(Netgame.players[i].protocol.udp.addr, DUMP_KICKED);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_message_end\n");
|
||||
|
@ -1686,28 +1673,22 @@ multi_do_message(char *buf)
|
|||
void
|
||||
multi_do_position(char *buf)
|
||||
{
|
||||
ubyte pnum = 0;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
shortpos sp;
|
||||
#endif
|
||||
|
||||
// This routine does only player positions, mode game only
|
||||
|
||||
int pnum = (Player_num+1)%2;
|
||||
|
||||
Assert(&Objects[Players[pnum].objnum] != ConsoleObject);
|
||||
|
||||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
Int3(); // Get Jason, what the hell are we doing here?
|
||||
// this is unused in IPX - position is forced within net_ipx_do_frame()
|
||||
if (multi_protocol == MULTI_PROTO_IPX)
|
||||
return;
|
||||
}
|
||||
|
||||
pnum = buf[1];
|
||||
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf+1),0);
|
||||
extract_shortpos(&Objects[Players[pnum].objnum], (shortpos *)(buf + 2),0);
|
||||
#else
|
||||
memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 1), 9);
|
||||
memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 10), 14);
|
||||
memcpy((ubyte *)(sp.bytemat), (ubyte *)(buf + 2), 9);
|
||||
memcpy((ubyte *)&(sp.xo), (ubyte *)(buf + 11), 14);
|
||||
extract_shortpos(&Objects[Players[pnum].objnum], &sp, 1);
|
||||
#endif
|
||||
|
||||
|
@ -1851,16 +1832,7 @@ multi_do_kill(char *buf)
|
|||
if (killer > 0)
|
||||
killer = objnum_remote_to_local(killer, (sbyte)buf[count+2]);
|
||||
|
||||
#ifdef SHAREWARE
|
||||
if ((Objects[killed].type != OBJ_PLAYER) && (Objects[killed].type != OBJ_GHOST))
|
||||
{
|
||||
Int3();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
multi_compute_kill(killer, killed);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -1988,6 +1960,9 @@ multi_do_quit(char *buf)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_disconnect_player(buf[1]);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_disconnect_player(buf[1]);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_do_quit\n");
|
||||
break;
|
||||
|
@ -2020,10 +1995,8 @@ multi_do_cloak(char *buf)
|
|||
Players[pnum].cloak_time = GameTime;
|
||||
ai_do_cloak_stuff();
|
||||
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_ROBOTS)
|
||||
multi_strip_robots(pnum);
|
||||
#endif
|
||||
|
||||
if (Newdemo_state == ND_STATE_RECORDING)
|
||||
newdemo_record_multi_cloak(pnum);
|
||||
|
@ -2290,7 +2263,7 @@ void multi_do_req_player(char *buf)
|
|||
extract_netplayer_stats( &ps, &Players[Player_num] );
|
||||
ps.Player_num = Player_num;
|
||||
ps.message_type = MULTI_SEND_PLAYER; // SET
|
||||
multi_send_data((char*)&ps, sizeof(netplayer_stats), 0);
|
||||
multi_send_data((char*)&ps, sizeof(netplayer_stats), 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2461,7 +2434,7 @@ multi_send_destroy_controlcen(int objnum, int player)
|
|||
multibuf[0] = (char)MULTI_CONTROLCEN;
|
||||
PUT_INTEL_SHORT(multibuf+1, objnum);
|
||||
multibuf[3] = player;
|
||||
multi_send_data(multibuf, 4, 2);
|
||||
multi_send_data(multibuf, 4, 1);
|
||||
}
|
||||
|
||||
void multi_send_drop_marker (int player,vms_vector position,char messagenum,char text[])
|
||||
|
@ -2497,12 +2470,15 @@ multi_send_endlevel_start(int secret)
|
|||
multi_send_data(multibuf, 3, 1);
|
||||
if (Game_mode & GM_NETWORK)
|
||||
{
|
||||
Players[Player_num].connected = 5;
|
||||
Players[Player_num].connected = CONNECT_ESCAPE_TUNNEL;
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_endlevel_packet();
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_endlevel_packet();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_endlevel_start\n");
|
||||
break;
|
||||
|
@ -2518,8 +2494,6 @@ multi_send_player_explode(char type)
|
|||
|
||||
Assert( (type == MULTI_PLAYER_DROP) || (type == MULTI_PLAYER_EXPLODE) );
|
||||
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
|
||||
if (Network_send_objects)
|
||||
{
|
||||
Network_send_objnum = -1;
|
||||
|
@ -2580,7 +2554,7 @@ multi_send_player_explode(char type)
|
|||
Int3(); // See Rob
|
||||
}
|
||||
|
||||
multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 2);
|
||||
multi_send_data(multibuf, message_length[MULTI_PLAYER_EXPLODE], 1);
|
||||
if (Players[Player_num].flags & PLAYER_FLAGS_CLOAKED)
|
||||
multi_send_decloak();
|
||||
if (Game_mode & GM_MULTI_ROBOTS)
|
||||
|
@ -2809,10 +2783,12 @@ multi_send_message(void)
|
|||
void
|
||||
multi_send_reappear()
|
||||
{
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
|
||||
multibuf[0] = (char)MULTI_REAPPEAR;
|
||||
PUT_INTEL_SHORT(multibuf+1, Players[Player_num].objnum);
|
||||
|
||||
multi_send_data(multibuf, 3, 2);
|
||||
multi_send_data(multibuf, 3, 1);
|
||||
PKilledFlags[Player_num]=0;
|
||||
}
|
||||
|
||||
|
@ -2824,11 +2800,12 @@ multi_send_position(int objnum)
|
|||
#endif
|
||||
int count=0;
|
||||
|
||||
if (Game_mode & GM_NETWORK) {
|
||||
// this is unused in IPX - position is forced within net_ipx_do_frame()
|
||||
if (multi_protocol == MULTI_PROTO_IPX)
|
||||
return;
|
||||
}
|
||||
|
||||
multibuf[count++] = (char)MULTI_POSITION;
|
||||
multibuf[count++] = (char)Player_num;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
create_shortpos((shortpos *)(multibuf+count), Objects+objnum,0);
|
||||
count += sizeof(shortpos);
|
||||
|
@ -2839,7 +2816,8 @@ multi_send_position(int objnum)
|
|||
memcpy(&(multibuf[count]), (ubyte *)&(sp.xo), 14);
|
||||
count += 14;
|
||||
#endif
|
||||
|
||||
// send twice while first has priority so the next one will be attached to the next bigdata packet
|
||||
multi_send_data(multibuf, count, 1);
|
||||
multi_send_data(multibuf, count, 0);
|
||||
}
|
||||
|
||||
|
@ -2872,10 +2850,8 @@ multi_send_kill(int objnum)
|
|||
count += 3;
|
||||
multi_send_data(multibuf, count, 1);
|
||||
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_ROBOTS)
|
||||
multi_strip_robots(Player_num);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2941,10 +2917,8 @@ multi_send_cloak(void)
|
|||
|
||||
multi_send_data(multibuf, 2, 1);
|
||||
|
||||
#ifndef SHAREWARE
|
||||
if (Game_mode & GM_MULTI_ROBOTS)
|
||||
multi_strip_robots(Player_num);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -2968,13 +2942,12 @@ multi_send_door_open(int segnum, int side,ubyte flag)
|
|||
multibuf[3] = (sbyte)side;
|
||||
multibuf[4] = flag;
|
||||
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 1);
|
||||
}
|
||||
|
||||
extern void net_ipx_send_naked_packet (char *,short,int);
|
||||
|
||||
void
|
||||
multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
|
||||
void multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
|
||||
{
|
||||
// For sending doors only to a specific person (usually when they're joining)
|
||||
|
||||
|
@ -2991,6 +2964,9 @@ multi_send_door_open_specific(int pnum,int segnum, int side,ubyte flag)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_naked_packet(multibuf, 5, pnum);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_mdata_direct((ubyte *)multibuf, 5, pnum, 1);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_door_open_specific\n");
|
||||
break;
|
||||
|
@ -3054,6 +3030,8 @@ multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *
|
|||
#endif
|
||||
int count = 0;
|
||||
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
|
||||
if (Game_mode & GM_NETWORK)
|
||||
PowerupsInMine[powerup_type]++;
|
||||
|
||||
|
@ -3072,7 +3050,7 @@ multi_send_create_powerup(int powerup_type, int segnum, int objnum, vms_vector *
|
|||
#endif
|
||||
// -----------
|
||||
// Total = 19
|
||||
multi_send_data(multibuf, count, 2);
|
||||
multi_send_data(multibuf, count, 1);
|
||||
|
||||
if (Network_send_objects && multi_objnum_is_past(objnum))
|
||||
{
|
||||
|
@ -3156,7 +3134,6 @@ multi_send_trigger(int triggernum)
|
|||
multibuf[count] = (ubyte)triggernum; count += 1;
|
||||
|
||||
multi_send_data(multibuf, count, 1);
|
||||
//multi_send_data(multibuf, count, 1); // twice?
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -3176,11 +3153,30 @@ multi_send_hostage_door_status(int wallnum)
|
|||
multi_send_data(multibuf, count, 0);
|
||||
}
|
||||
|
||||
extern int ConsistencyCount;
|
||||
extern int Drop_afterburner_blob_flag;
|
||||
int PhallicLimit=0;
|
||||
int PhallicMan=-1;
|
||||
|
||||
void multi_consistency_error(int reset)
|
||||
{
|
||||
static int count = 0;
|
||||
|
||||
if (reset)
|
||||
count = 0;
|
||||
|
||||
if (++count < 10)
|
||||
return;
|
||||
|
||||
Function_mode = FMODE_MENU;
|
||||
nm_messagebox(NULL, 1, TXT_OK, TXT_CONSISTENCY_ERROR);
|
||||
Function_mode = FMODE_GAME;
|
||||
count = 0;
|
||||
multi_quit_game = 1;
|
||||
multi_leave_menu = 1;
|
||||
multi_reset_stuff();
|
||||
Function_mode = FMODE_MENU;
|
||||
}
|
||||
|
||||
void multi_prep_level(void)
|
||||
{
|
||||
// Do any special stuff to the level required for games
|
||||
|
@ -3202,7 +3198,7 @@ void multi_prep_level(void)
|
|||
PhallicLimit=0;
|
||||
PhallicMan=-1;
|
||||
Drop_afterburner_blob_flag=0;
|
||||
ConsistencyCount=0;
|
||||
multi_consistency_error(1);
|
||||
|
||||
for (i=0;i<MAX_NUM_NET_PLAYERS;i++)
|
||||
PKilledFlags[i]=0;
|
||||
|
@ -3216,14 +3212,12 @@ void multi_prep_level(void)
|
|||
Netgame.players[i].LastPacketTime = 0;
|
||||
}
|
||||
|
||||
#ifndef SHAREWARE
|
||||
for (i = 0; i < MAX_ROBOTS_CONTROLLED; i++)
|
||||
{
|
||||
robot_controlled[i] = -1;
|
||||
robot_agitation[i] = 0;
|
||||
robot_fired[i] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
Viewer = ConsoleObject = &Objects[Players[Player_num].objnum];
|
||||
|
||||
|
@ -3418,8 +3412,11 @@ int multi_level_sync(void)
|
|||
case MULTI_PROTO_IPX:
|
||||
return net_ipx_level_sync();
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
return net_udp_level_sync();
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_levl_sync\n");
|
||||
Error("Protocol handling missing in multi_level_sync\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -3545,35 +3542,48 @@ int multi_delete_extra_objects()
|
|||
return nnp;
|
||||
}
|
||||
|
||||
int
|
||||
multi_i_am_master(void)
|
||||
// Returns 1 if player is Master/Host of this game
|
||||
int multi_i_am_master(void)
|
||||
{
|
||||
// I am the lowest numbered player in this game?
|
||||
// IPX has variable Hosts, but we might not want to continue this for newer protocols
|
||||
if (multi_protocol == MULTI_PROTO_IPX)
|
||||
{
|
||||
int i;
|
||||
|
||||
int i;
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
return (Player_num == 0);
|
||||
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
for (i = 0; i < Player_num; i++)
|
||||
if (Players[i].connected)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (Player_num == 0);
|
||||
|
||||
for (i = 0; i < Player_num; i++)
|
||||
if (Players[i].connected)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the Player_num of Master/Host of this game
|
||||
int multi_who_is_master(void)
|
||||
{
|
||||
// Who is the master of this game?
|
||||
// IPX has variable Hosts, but we might not want to continue this for newer protocols
|
||||
if (multi_protocol == MULTI_PROTO_IPX)
|
||||
{
|
||||
int i;
|
||||
|
||||
int i;
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
return (Player_num == 0);
|
||||
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
return (Player_num == 0);
|
||||
|
||||
for (i = 0; i < N_players; i++)
|
||||
if (Players[i].connected)
|
||||
return i;
|
||||
return Player_num;
|
||||
for (i = 0; i < N_players; i++)
|
||||
if (Players[i].connected)
|
||||
return i;
|
||||
return Player_num;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void change_playernum_to( int new_Player_num )
|
||||
|
@ -3679,6 +3689,8 @@ void multi_send_drop_weapon (int objnum,int seed)
|
|||
int count=0;
|
||||
int ammo_count;
|
||||
|
||||
multi_send_position(Players[Player_num].objnum);
|
||||
|
||||
objp = &Objects[objnum];
|
||||
|
||||
ammo_count = objp->ctype.powerup_info.count;
|
||||
|
@ -3701,7 +3713,7 @@ void multi_send_drop_weapon (int objnum,int seed)
|
|||
if (Game_mode & GM_NETWORK)
|
||||
PowerupsInMine[objp->id]++;
|
||||
|
||||
multi_send_data(multibuf, 12, 2);
|
||||
multi_send_data(multibuf, 12, 1);
|
||||
}
|
||||
|
||||
void multi_do_drop_weapon (char *buf)
|
||||
|
@ -3835,7 +3847,6 @@ void multi_send_wall_status (int wallnum,ubyte type,ubyte flags,ubyte state)
|
|||
multibuf[count]=flags; count++;
|
||||
multibuf[count]=state; count++;
|
||||
|
||||
multi_send_data(multibuf, count, 1); // twice, just to be sure
|
||||
multi_send_data(multibuf, count, 1);
|
||||
}
|
||||
|
||||
|
@ -3860,6 +3871,9 @@ void multi_send_wall_status_specific (int pnum,int wallnum,ubyte type,ubyte flag
|
|||
net_ipx_send_naked_packet(multibuf, count,pnum); // twice, just to be sure
|
||||
net_ipx_send_naked_packet(multibuf, count,pnum);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_mdata_direct((ubyte *)multibuf, count, pnum, 1);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_wall_status_specific\n");
|
||||
break;
|
||||
|
@ -4026,6 +4040,9 @@ void multi_send_light_specific (int pnum,int segnum,ubyte val)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_naked_packet(multibuf, count, pnum);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_mdata_direct((ubyte *)multibuf, count, pnum, 1);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_light_specific\n");
|
||||
break;
|
||||
|
@ -4125,7 +4142,6 @@ void multi_send_active_door (int i)
|
|||
PUT_INTEL_SHORT(multibuf + count, ActiveDoors[i].back_wallnum[1]); count += 2;
|
||||
PUT_INTEL_INT(multibuf + count, ActiveDoors[i].time); count += 4;
|
||||
#endif
|
||||
//multi_send_data (multibuf,sizeof(struct active_door)+3,1);
|
||||
multi_send_data (multibuf,count,1);
|
||||
}
|
||||
#endif // 0 (never used)
|
||||
|
@ -4174,7 +4190,7 @@ void multi_do_sound_function (char *buf)
|
|||
char pnum,whichfunc;
|
||||
int sound;
|
||||
|
||||
if (Players[Player_num].connected!=1)
|
||||
if (Players[Player_num].connected!=CONNECT_PLAYING)
|
||||
return;
|
||||
|
||||
pnum=buf[1];
|
||||
|
@ -4216,8 +4232,6 @@ void multi_do_capture_bonus(char *buf)
|
|||
char pnum=buf[1];
|
||||
int TheGoal;
|
||||
|
||||
kmatrix_kills_changed = 1;
|
||||
|
||||
if (pnum==Player_num)
|
||||
HUD_init_message("You have Scored!");
|
||||
else
|
||||
|
@ -4276,8 +4290,6 @@ void multi_do_orb_bonus(char *buf)
|
|||
int TheGoal;
|
||||
int bonus=GetOrbBonus (buf[2]);
|
||||
|
||||
kmatrix_kills_changed = 1;
|
||||
|
||||
if (pnum==Player_num)
|
||||
HUD_init_message("You have scored %d points!",bonus);
|
||||
else
|
||||
|
@ -4490,7 +4502,7 @@ void multi_send_drop_flag (int objnum,int seed)
|
|||
if (Game_mode & GM_NETWORK)
|
||||
PowerupsInMine[objp->id]++;
|
||||
|
||||
multi_send_data(multibuf, 12, 2);
|
||||
multi_send_data(multibuf, 12, 1);
|
||||
}
|
||||
|
||||
void multi_do_drop_flag (char *buf)
|
||||
|
@ -4532,63 +4544,6 @@ extern int robot_fired[MAX_ROBOTS_CONTROLLED];
|
|||
extern sbyte robot_fire_buf[MAX_ROBOTS_CONTROLLED][18+3];
|
||||
|
||||
|
||||
void multi_send_robot_controls (char pnum)
|
||||
{
|
||||
int count=2;
|
||||
|
||||
multibuf[0]=MULTI_ROBOT_CONTROLS;
|
||||
multibuf[1]=pnum;
|
||||
memcpy (&(multibuf[count]),&robot_controlled,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_agitation,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_controlled_time,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_last_send_time,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_last_message_time,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_send_pending,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&(multibuf[count]),&robot_fired,MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
|
||||
switch (multi_protocol)
|
||||
{
|
||||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_naked_packet (multibuf,142,pnum);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_robot_controls\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
void multi_do_robot_controls(char *buf)
|
||||
{
|
||||
int count=2;
|
||||
|
||||
if (buf[1]!=Player_num)
|
||||
{
|
||||
Int3(); // Get Jason! Recieved a coop_sync that wasn't ours!
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy (&robot_controlled,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_agitation,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_controlled_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_last_send_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_last_message_time,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_send_pending,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
memcpy (&robot_fired,&(buf[count]),MAX_ROBOTS_CONTROLLED*4);
|
||||
count+=(MAX_ROBOTS_CONTROLLED*4);
|
||||
}
|
||||
|
||||
#define POWERUPADJUSTS 5
|
||||
int PowerupAdjustMapping[]={11,19,39,41,44};
|
||||
|
||||
|
@ -4705,6 +4660,9 @@ void multi_send_trigger_specific (char pnum,char trig)
|
|||
case MULTI_PROTO_IPX:
|
||||
net_ipx_send_naked_packet(multibuf, 2, pnum);
|
||||
break;
|
||||
case MULTI_PROTO_UDP:
|
||||
net_udp_send_mdata_direct((ubyte *)multibuf, 2, pnum, 1);
|
||||
break;
|
||||
default:
|
||||
Error("Protocol handling missing in multi_send_trigger_specific\n");
|
||||
break;
|
||||
|
@ -4724,7 +4682,7 @@ void multi_add_lifetime_kills ()
|
|||
|
||||
int oldrank;
|
||||
|
||||
if (!Game_mode & GM_NETWORK)
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
return;
|
||||
|
||||
oldrank=GetMyNetRanking();
|
||||
|
@ -4751,7 +4709,7 @@ void multi_add_lifetime_killed ()
|
|||
|
||||
int oldrank;
|
||||
|
||||
if (!Game_mode & GM_NETWORK)
|
||||
if (!(Game_mode & GM_NETWORK))
|
||||
return;
|
||||
|
||||
oldrank=GetMyNetRanking();
|
||||
|
@ -4856,6 +4814,19 @@ void multi_do_play_by_play (char *buf)
|
|||
/// CODE TO LOAD HOARD DATA
|
||||
///
|
||||
|
||||
int HoardEquipped()
|
||||
{
|
||||
static int checked=-1;
|
||||
|
||||
if (checked==-1)
|
||||
{
|
||||
if (cfexist("hoard.ham") || cfexist("Data/hoard.ham"))
|
||||
checked=1;
|
||||
else
|
||||
checked=0;
|
||||
}
|
||||
return (checked);
|
||||
}
|
||||
|
||||
void init_bitmap(grs_bitmap *bm,int w,int h,int flags,ubyte *data)
|
||||
{
|
||||
|
@ -5179,11 +5150,10 @@ multi_process_data(char *buf, int len)
|
|||
if (!Endlevel_sequence) multi_do_play_by_play(buf); break;
|
||||
case MULTI_RANK:
|
||||
if (!Endlevel_sequence) multi_do_ranking (buf); break;
|
||||
#ifndef SHAREWARE
|
||||
case MULTI_FINISH_GAME:
|
||||
multi_do_finish_game(buf); break; // do this one regardless of endsequence
|
||||
case MULTI_ROBOT_CONTROLS:
|
||||
if (!Endlevel_sequence) multi_do_robot_controls(buf); break;
|
||||
break;
|
||||
case MULTI_ROBOT_CLAIM:
|
||||
if (!Endlevel_sequence) multi_do_claim_robot(buf); break;
|
||||
case MULTI_ROBOT_POSITION:
|
||||
|
@ -5194,7 +5164,6 @@ multi_process_data(char *buf, int len)
|
|||
if (!Endlevel_sequence) multi_do_release_robot(buf); break;
|
||||
case MULTI_ROBOT_FIRE:
|
||||
if (!Endlevel_sequence) multi_do_robot_fire(buf); break;
|
||||
#endif
|
||||
case MULTI_SCORE:
|
||||
if (!Endlevel_sequence) multi_do_score(buf); break;
|
||||
case MULTI_CREATE_ROBOT:
|
||||
|
|
92
main/multi.h
92
main/multi.h
|
@ -25,30 +25,28 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#include "piggy.h"
|
||||
#include "vers_id.h"
|
||||
#include "newmenu.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#ifdef IPv6
|
||||
#define _sockaddr sockaddr_in6
|
||||
#define _af AF_INET6
|
||||
#define _pf PF_INET6
|
||||
#define _sockaddr sockaddr_in6
|
||||
#define _af AF_INET6
|
||||
#define _pf PF_INET6
|
||||
#else
|
||||
#define _sockaddr sockaddr_in
|
||||
#define _af AF_INET
|
||||
#define _pf PF_INET
|
||||
#define _sockaddr sockaddr_in
|
||||
#define _af AF_INET
|
||||
#define _pf PF_INET
|
||||
#endif
|
||||
|
||||
|
||||
// PROTOCOL VARIABLES AND DEFINES
|
||||
extern int multi_protocol; // set and determinate used protocol
|
||||
#define MULTI_PROTO_IPX 1 // IPX-type protocol (IPX, KALI)
|
||||
|
@ -126,7 +124,7 @@ extern int multi_protocol; // set and determinate used protocol
|
|||
#define MULTI_CAPTURE_BONUS 52
|
||||
#define MULTI_GOT_FLAG 53
|
||||
#define MULTI_DROP_FLAG 54
|
||||
#define MULTI_ROBOT_CONTROLS 55
|
||||
#define MULTI_ROBOT_CONTROLS 55 // unused!
|
||||
#define MULTI_FINISH_GAME 56
|
||||
#define MULTI_RANK 57
|
||||
#define MULTI_MODEM_PING 58
|
||||
|
@ -142,6 +140,14 @@ extern int multi_protocol; // set and determinate used protocol
|
|||
|
||||
#define MAX_MULTI_MESSAGE_LEN 120
|
||||
|
||||
#define NETGAME_ANARCHY 0
|
||||
#define NETGAME_TEAM_ANARCHY 1
|
||||
#define NETGAME_ROBOT_ANARCHY 2
|
||||
#define NETGAME_COOPERATIVE 3
|
||||
#define NETGAME_CAPTURE_FLAG 4
|
||||
#define NETGAME_HOARD 5
|
||||
#define NETGAME_TEAM_HOARD 6
|
||||
|
||||
#define NETSTAT_MENU 0
|
||||
#define NETSTAT_PLAYING 1
|
||||
#define NETSTAT_BROWSING 2
|
||||
|
@ -158,6 +164,16 @@ extern int multi_protocol; // set and determinate used protocol
|
|||
#define CONNECT_END_MENU 6
|
||||
#define CONNECT_KMATRIX_WAITING 7 // Like CONNECT_WAITING but used especially in kmatrix.c to seperate "escaped" and "waiting"
|
||||
|
||||
// reasons for a packet with type PID_DUMP
|
||||
#define DUMP_CLOSED 0 // no new players allowed after game started
|
||||
#define DUMP_FULL 1 // player cound maxed out
|
||||
#define DUMP_ENDLEVEL 2
|
||||
#define DUMP_DORK 3
|
||||
#define DUMP_ABORTED 4
|
||||
#define DUMP_CONNECTED 5 // never used
|
||||
#define DUMP_LEVEL 6
|
||||
#define DUMP_KICKED 7
|
||||
|
||||
// Bitmask for netgame_info->AllowedItems to set allowed items in Netgame
|
||||
#define NETFLAG_DOLASER 1
|
||||
#define NETFLAG_DOSUPERLASER 2
|
||||
|
@ -193,6 +209,7 @@ extern char *multi_allow_powerup_text[MULTI_ALLOW_POWERUP_MAX];
|
|||
// Exported functions
|
||||
|
||||
extern int GetMyNetRanking();
|
||||
extern void ClipRank (ubyte *rank);
|
||||
int objnum_remote_to_local(int remote_obj, int owner);
|
||||
int objnum_local_to_remote(int local_obj, sbyte *owner);
|
||||
void map_objnum_local_to_remote(int local, int remote, int owner);
|
||||
|
@ -236,13 +253,13 @@ void multi_send_guided_info (object *miss,char);
|
|||
|
||||
|
||||
void multi_endlevel_score(void);
|
||||
void multi_consistency_error(int reset);
|
||||
void multi_prep_level(void);
|
||||
int multi_level_sync(void);
|
||||
int multi_endlevel(int *secret);
|
||||
void multi_endlevel_poll1();
|
||||
void multi_endlevel_poll2( int nitems, struct newmenu_item * menus, int * key, int citem );
|
||||
void multi_endlevel_poll3( int nitems, struct newmenu_item * menus, int * key, int citem );
|
||||
void multi_send_endlevel_packet();
|
||||
void multi_send_endlevel_sub(int player_num);
|
||||
int multi_menu_poll(void);
|
||||
void multi_leave_game(void);
|
||||
void multi_process_data(char *dat, int len);
|
||||
|
@ -258,14 +275,13 @@ int multi_get_kill_list(int *plist);
|
|||
void multi_new_game(void);
|
||||
void multi_sort_kill_list(void);
|
||||
void multi_reset_stuff(void);
|
||||
void multi_send_data(char *buf, int len, int repeat);
|
||||
void multi_send_data(char *buf, int len, int priority);
|
||||
int get_team(int pnum);
|
||||
|
||||
|
||||
// Exported variables
|
||||
|
||||
extern int PacketUrgent;
|
||||
extern int Network_active;
|
||||
extern int Network_status;
|
||||
extern int Network_laser_gun;
|
||||
extern int Network_laser_fired;
|
||||
|
@ -274,9 +290,13 @@ extern int Network_laser_flags;
|
|||
|
||||
// IMPORTANT: These variables needed for player rejoining done by protocol-specific code
|
||||
extern int Network_send_objects;
|
||||
extern int Network_send_object_mode;
|
||||
extern int Network_send_objnum;
|
||||
extern int Network_rejoined;
|
||||
extern int Network_new_game;
|
||||
extern int Network_sending_extras;
|
||||
extern int Player_joining_extras;
|
||||
extern int Network_player_added;
|
||||
|
||||
extern int message_length[MULTI_MAX_TYPE+1];
|
||||
extern char multibuf[MAX_MULTI_MESSAGE_LEN+4];
|
||||
|
@ -329,6 +349,11 @@ extern bitmap_index multi_player_textures[MAX_NUM_NET_PLAYERS][N_PLAYER_SHIP_TEX
|
|||
|
||||
extern char *RankStrings[];
|
||||
|
||||
// Globals for protocol-bound Refuse-functions
|
||||
extern char RefuseThisPlayer,WaitForRefuseAnswer,RefuseTeam,RefusePlayerName[12];
|
||||
extern fix RefuseTimeLimit;
|
||||
#define REFUSE_INTERVAL (F1_0*8)
|
||||
|
||||
#define NETGAME_FLAG_CLOSED 1
|
||||
#define NETGAME_FLAG_SHOW_ID 2
|
||||
#define NETGAME_FLAG_SHOW_MAP 4
|
||||
|
@ -351,13 +376,11 @@ void change_playernum_to(int new_pnum);
|
|||
#define MISSILE_ADJUST 100
|
||||
#define FLARE_ADJUST 127
|
||||
|
||||
int HoardEquipped();
|
||||
#ifdef EDITOR
|
||||
void save_hoard_data(void);
|
||||
#endif
|
||||
|
||||
|
||||
enum comp_type {DOS,WIN_32,WIN_95,MAC} __pack__ ;
|
||||
|
||||
/*
|
||||
* The Network Players structure
|
||||
* Contains both IPX- and UDP-specific data with designated prefixes and general player-related data.
|
||||
|
@ -373,16 +396,12 @@ typedef struct netplayer_info
|
|||
ubyte server[4];
|
||||
ubyte node[6];
|
||||
ushort socket;
|
||||
enum comp_type computer_type;
|
||||
ubyte computer_type; // {DOS,WIN_32,WIN_95,MAC}
|
||||
} ipx;
|
||||
struct
|
||||
{
|
||||
struct _sockaddr addr; // IP address of this peer
|
||||
int valid; // 1 = client connected / 2 = client ready for handshaking / 3 = client done with handshake and fully joined / 0 between clients = no connection -> relay
|
||||
fix timestamp; // time of received packet - used for timeout
|
||||
char hs_list[MAX_PLAYERS+4]; // list to store all handshake results for this player from already connected clients
|
||||
int hstimeout; // counts the number of tries the client tried to connect - if reached 10, client put to relay if allowed
|
||||
int relay; // relay packets by/to this clients over host
|
||||
ubyte isyou; // This flag is set true while sending info to tell player his designated (re)join position
|
||||
} udp;
|
||||
} protocol;
|
||||
|
||||
|
@ -418,6 +437,7 @@ typedef struct netgame_info
|
|||
{
|
||||
struct _sockaddr addr; // IP address of this netgame's host
|
||||
int program_iver; // IVER of program for version checking
|
||||
sbyte valid; // Status of Netgame info: -1 = Failed, Wrong version; 0 = No info, yet; 1 = Success
|
||||
} udp;
|
||||
} protocol;
|
||||
|
||||
|
@ -438,11 +458,11 @@ typedef struct netgame_info
|
|||
ubyte game_flags;
|
||||
ubyte team_vector;
|
||||
u_int32_t AllowedItems;
|
||||
short Allow_marker_view:1;
|
||||
short AlwaysLighting:1;
|
||||
short ShowAllNames:1;
|
||||
short BrightPlayers:1;
|
||||
short InvulAppear:1;
|
||||
short Allow_marker_view;
|
||||
short AlwaysLighting;
|
||||
short ShowAllNames;
|
||||
short BrightPlayers;
|
||||
short InvulAppear;
|
||||
char team_name[2][CALLSIGN_LEN+1];
|
||||
int locations[MAX_PLAYERS];
|
||||
short kills[MAX_PLAYERS][MAX_PLAYERS];
|
||||
|
@ -458,7 +478,7 @@ typedef struct netgame_info
|
|||
int player_score[MAX_PLAYERS];
|
||||
ubyte player_flags[MAX_PLAYERS];
|
||||
short PacketsPerSec;
|
||||
ubyte PacketLossPrevention;
|
||||
ubyte PacketLossPrevention; // FIXME: IMPLEMENT ME!
|
||||
} __pack__ netgame_info;
|
||||
|
||||
|
||||
|
|
|
@ -338,10 +338,7 @@ multi_send_claim_robot(int objnum)
|
|||
s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]);
|
||||
PUT_INTEL_SHORT(multibuf+2, s);
|
||||
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
|
||||
multi_send_data(multibuf, 5, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -368,9 +365,7 @@ multi_send_release_robot(int objnum)
|
|||
s = objnum_local_to_remote(objnum, (sbyte *)&multibuf[4]);
|
||||
PUT_INTEL_SHORT(multibuf+2, s);
|
||||
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 2);
|
||||
multi_send_data(multibuf, 5, 1);
|
||||
}
|
||||
|
||||
#define MIN_ROBOT_COM_GAP F1_0/12
|
||||
|
@ -518,7 +513,7 @@ multi_send_robot_fire(int objnum, int gun_num, vms_vector *fire)
|
|||
PacketUrgent = 1;
|
||||
}
|
||||
else
|
||||
multi_send_data(multibuf, loc, 2); // Not our robot, send ASAP
|
||||
multi_send_data(multibuf, loc, 1); // Not our robot, send ASAP
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -559,7 +554,7 @@ multi_send_create_robot(int station, int objnum, int type)
|
|||
|
||||
map_objnum_local_to_local((short)objnum);
|
||||
|
||||
multi_send_data(multibuf, loc, 2);
|
||||
multi_send_data(multibuf, loc, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -638,7 +633,7 @@ multi_send_create_robot_powerups(object *del_obj)
|
|||
|
||||
Net_create_loc = 0;
|
||||
|
||||
multi_send_data(multibuf, 27, 2);
|
||||
multi_send_data(multibuf, 27, 1);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
1242
main/net_ipx.c
1242
main/net_ipx.c
File diff suppressed because it is too large
Load diff
119
main/net_ipx.h
119
main/net_ipx.h
|
@ -1,4 +1,3 @@
|
|||
/* $Id: net_ipx.h,v 1.1.1.1 2006/03/17 19:56:24 zicodxx Exp $ */
|
||||
/*
|
||||
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
|
||||
SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO
|
||||
|
@ -14,7 +13,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
|
||||
/*
|
||||
*
|
||||
* Prototypes for network management functions.
|
||||
* Prototypes for IPX-protocol network management functions.
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -24,9 +23,15 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
|
||||
#include "gameseq.h"
|
||||
#include "multi.h"
|
||||
#include "pstypes.h"
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#else
|
||||
#include <netinet/in.h> /* for htons & co. */
|
||||
#endif
|
||||
|
||||
#define NETWORK_TIMEOUT (15*F1_0) // 15 seconds disconnect timeout
|
||||
#define MAX_ACTIVE_NETGAMES 12
|
||||
#define IPX_TIMEOUT (15*F1_0) // 15 seconds disconnect timeout
|
||||
#define IPX_MAX_NETGAMES 12
|
||||
|
||||
/* the following are the possible packet identificators.
|
||||
* they are stored in the "type" field of the packet structs.
|
||||
|
@ -56,14 +61,6 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
#define PID_GAME_PLAYERS 63
|
||||
#define PID_NAMES_RETURN 64 // 0x40
|
||||
|
||||
#define NETGAME_ANARCHY 0
|
||||
#define NETGAME_TEAM_ANARCHY 1
|
||||
#define NETGAME_ROBOT_ANARCHY 2
|
||||
#define NETGAME_COOPERATIVE 3
|
||||
#define NETGAME_CAPTURE_FLAG 4
|
||||
#define NETGAME_HOARD 5
|
||||
#define NETGAME_TEAM_HOARD 6
|
||||
|
||||
/* The following are values for NetSecurityFlag */
|
||||
#define NETSECURITY_OFF 0
|
||||
#define NETSECURITY_WAIT_FOR_PLAYERS 1
|
||||
|
@ -74,12 +71,12 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
|
|||
* (the one that did "start netgame").
|
||||
*/
|
||||
|
||||
typedef struct sequence_packet {
|
||||
typedef struct IPX_sequence_packet {
|
||||
ubyte type;
|
||||
int Security;
|
||||
ubyte pad1[3];
|
||||
netplayer_info player;
|
||||
} __pack__ sequence_packet;
|
||||
} __pack__ IPX_sequence_packet;
|
||||
|
||||
#define NET_XDATA_SIZE 454
|
||||
|
||||
|
@ -91,7 +88,7 @@ typedef struct sequence_packet {
|
|||
// shorts on even byte boundries
|
||||
// ints on even byte boundries
|
||||
|
||||
typedef struct frame_info {
|
||||
typedef struct IPX_frame_info {
|
||||
ubyte type; // What type of packet
|
||||
ubyte pad[3]; // Pad out length of frame_info packet
|
||||
int numpackets;
|
||||
|
@ -105,13 +102,13 @@ typedef struct frame_info {
|
|||
ubyte obj_render_type;
|
||||
ubyte level_num;
|
||||
char data[NET_XDATA_SIZE]; // extra data to be tacked on the end
|
||||
} __pack__ frame_info;
|
||||
} __pack__ IPX_frame_info;
|
||||
|
||||
// short_frame_info is not aligned -- 01/18/96 -- MWA
|
||||
// IPX_short_frame_info is not aligned -- 01/18/96 -- MWA
|
||||
// won't align because of shortpos. Shortpos needs
|
||||
// to stay in current form.
|
||||
|
||||
typedef struct short_frame_info {
|
||||
typedef struct IPX_short_frame_info {
|
||||
ubyte type; // What type of packet
|
||||
ubyte pad[3]; // Pad out length of frame_info packet
|
||||
int numpackets;
|
||||
|
@ -121,7 +118,7 @@ typedef struct short_frame_info {
|
|||
ubyte obj_render_type;
|
||||
ubyte level_num;
|
||||
char data[NET_XDATA_SIZE]; // extra data to be tacked on the end
|
||||
} __pack__ short_frame_info;
|
||||
} __pack__ IPX_short_frame_info;
|
||||
|
||||
typedef struct IPX_netplayer_info {
|
||||
char callsign[CALLSIGN_LEN+1];
|
||||
|
@ -139,7 +136,7 @@ typedef struct IPX_netplayer_info {
|
|||
|
||||
ubyte version_major;
|
||||
ubyte version_minor;
|
||||
enum comp_type computer_type;
|
||||
ubyte computer_type;
|
||||
sbyte connected;
|
||||
|
||||
ushort socket;
|
||||
|
@ -252,8 +249,8 @@ void net_ipx_join_game();
|
|||
void network_rejoin_game();
|
||||
void net_ipx_leave_game();
|
||||
int net_ipx_endlevel(int *secret);
|
||||
void net_ipx_endlevel_poll2(int nitems, struct newmenu_item * menus, int * key, int citem);
|
||||
void net_ipx_endlevel_poll3(int nitems, struct newmenu_item * menus, int * key, int citem);
|
||||
void net_ipx_kmatrix_poll1( int nitems, newmenu_item * menus, int * key, int citem );
|
||||
void net_ipx_kmatrix_poll2( int nitems, newmenu_item * menus, int * key, int citem );
|
||||
|
||||
int net_ipx_level_sync();
|
||||
void net_ipx_send_endlevel_packet();
|
||||
|
@ -266,8 +263,6 @@ void net_ipx_disconnect_player(int playernum);
|
|||
extern void net_ipx_dump_player(ubyte * server, ubyte *node, int why);
|
||||
extern void net_ipx_send_netgame_update();
|
||||
|
||||
extern int NetGameType;
|
||||
|
||||
// By putting an up-to-20-char-message into Network_message and
|
||||
// setting Network_message_reciever to the player num you want to
|
||||
// send it to (100 for broadcast) the next frame the player will
|
||||
|
@ -283,7 +278,81 @@ void net_ipx_send_data(ubyte * ptr, int len, int urgent);
|
|||
// returns 1 if hoard.ham available
|
||||
extern int HoardEquipped();
|
||||
|
||||
extern void net_ipx_ping_all();
|
||||
extern int IPX_Socket;
|
||||
extern int IPX_active;
|
||||
|
||||
/* General IPX stuff - START */
|
||||
#define MAX_PACKET_DATA 1500
|
||||
#define MAX_DATA_SIZE 542
|
||||
#define MAX_IPX_DATA 576
|
||||
|
||||
#define IPX_DEFAULT_SOCKET 0x5130
|
||||
|
||||
#define NETPROTO_IPX 1
|
||||
#define NETPROTO_KALINIX 2
|
||||
|
||||
typedef struct IPXAddressStruct {
|
||||
ubyte Network[4];
|
||||
ubyte Node[6];
|
||||
ubyte Socket[2];
|
||||
} IPXAddress_t;
|
||||
|
||||
typedef struct IPXPacketStructure {
|
||||
ushort Checksum;
|
||||
ushort Length;
|
||||
ubyte TransportControl;
|
||||
ubyte PacketType;
|
||||
IPXAddress_t Destination;
|
||||
IPXAddress_t Source;
|
||||
} IPXPacket_t;
|
||||
|
||||
typedef struct socket_struct {
|
||||
ushort socket;
|
||||
int fd;
|
||||
} socket_t;
|
||||
|
||||
struct recv_data {
|
||||
/* all network order */
|
||||
ubyte src_network[4];
|
||||
ubyte src_node[6];
|
||||
ushort src_socket;
|
||||
ushort dst_socket;
|
||||
int pkt_type;
|
||||
};
|
||||
|
||||
struct net_driver {
|
||||
int (*open_socket)(socket_t *sk, int port);
|
||||
void (*close_socket)(socket_t *mysock);
|
||||
int (*send_packet)(socket_t *mysock, IPXPacket_t *IPXHeader, ubyte *data, int dataLen);
|
||||
int (*receive_packet)(socket_t *s, char *buffer, int bufsize, struct recv_data *rec);
|
||||
int (*packet_ready)(socket_t *s);
|
||||
int usepacketnum;//we can save 4 bytes
|
||||
int type; // type of driver (NETPROTO_*). Can be used to make driver-specific rules in other parts of the multiplayer code.
|
||||
};
|
||||
|
||||
extern int ipxdrv_general_packet_ready(int fd);
|
||||
extern void ipxdrv_get_local_target( ubyte * server, ubyte * node, ubyte * local_target );
|
||||
extern int ipxdrv_set(int arg);
|
||||
extern int ipxdrv_change_default_socket( ushort socket_number );
|
||||
extern ubyte * ipxdrv_get_my_local_address();
|
||||
extern ubyte * ipxdrv_get_my_server_address();
|
||||
extern int ipxdrv_get_packet_data( ubyte * data );
|
||||
extern void ipxdrv_send_broadcast_packet_data( ubyte * data, int datasize );
|
||||
extern void ipxdrv_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address );
|
||||
extern void ipxdrv_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address );
|
||||
extern int ipxdrv_type(void);
|
||||
|
||||
#ifndef __APPLE__
|
||||
extern struct net_driver ipxdrv_ipx;
|
||||
#endif
|
||||
#ifdef __LINUX__
|
||||
extern struct net_driver ipxdrv_kali;
|
||||
#endif
|
||||
|
||||
extern unsigned char MyAddress[10];
|
||||
extern ubyte broadcast_addr[];
|
||||
extern ubyte null_addr[];
|
||||
extern u_int32_t ipx_network;
|
||||
/* General IPX stuff - END */
|
||||
|
||||
#endif /* _NETWORK_H */
|
||||
|
|
4793
main/net_udp.c
Normal file
4793
main/net_udp.c
Normal file
File diff suppressed because it is too large
Load diff
130
main/net_udp.h
Normal file
130
main/net_udp.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
/*
|
||||
*
|
||||
* Prototypes for UDP-protocol network management functions.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "multi.h"
|
||||
|
||||
// Exported functions
|
||||
void net_udp_start_game(void);
|
||||
void net_udp_manual_join_game();
|
||||
int net_udp_objnum_is_past(int objnum);
|
||||
void net_udp_do_frame(int force, int listen);
|
||||
void net_udp_send_data( ubyte * ptr, int len, int priority );
|
||||
void net_udp_leave_game();
|
||||
int net_udp_endlevel(int *secret);
|
||||
void net_udp_kmatrix_poll1( int nitems, newmenu_item * menus, int * key, int citem );
|
||||
void net_udp_kmatrix_poll2( int nitems, newmenu_item * menus, int * key, int citem );
|
||||
void net_udp_send_endlevel_packet();
|
||||
void net_udp_dump_player(struct _sockaddr dump_addr, int why);
|
||||
void net_udp_disconnect_player(int playernum);
|
||||
int net_udp_level_sync();
|
||||
void net_udp_send_mdata_direct(ubyte *data, int data_len, int pnum, int priority);
|
||||
void net_udp_send_netgame_update();
|
||||
|
||||
// Some defines
|
||||
#define UDP_PORT_DEFAULT 42424 // Our default port - easy to remember: D = 4, X = 24, X = 24
|
||||
#define UDP_REQ_ID "D2XR" // ID string for a request packet
|
||||
#define UDP_MAX_NETGAMES 600
|
||||
#define UDP_NETGAMES_PPAGE 12 // Netgames on one page of Netlist
|
||||
#define UDP_NETGAMES_PAGES 50 // Pages available on Netlist (UDP_MAX_NETGAMES/UDP_NETGAMES_PPAGE)
|
||||
#define UDP_TIMEOUT (10*F1_0) // 10 seconds disconnect timeout
|
||||
#define UDP_MDATA_STOR_QUEUE_SIZE 500 // Store up to 500 MDATA packets
|
||||
#define UDP_OBJ_PACKETS_PER_FRAME 20
|
||||
|
||||
// Following are static defines for the buffer size of various packets. IF you change the packets, you must change the size, too.
|
||||
#define UPKT_MAX_SIZE 1024 // Max size for a packet - just for the buffers
|
||||
#define UPKT_GAME_INFO_REQ_SIZE 9
|
||||
#define UPKT_SEQUENCE_SIZE 14
|
||||
#define UPKT_PING_SIZE 33
|
||||
#define UPKT_PONG_SIZE 6
|
||||
#define UPKT_MBUF_SIZE 454
|
||||
|
||||
// UDP-Packet identificators (ubyte).
|
||||
#define UPID_VERSION_DENY 1 // Netgame join or info has been denied due to version difference.
|
||||
#define UPID_GAME_INFO_REQ 2 // Requesting all info about a netgame.
|
||||
#define UPID_GAME_INFO 3 // Packet containing all info about a netgame.
|
||||
#define UPID_GAME_INFO_LITE_REQ 4 // Requesting lite info about a netgame. Used for discovering games.
|
||||
#define UPID_GAME_INFO_LITE 5 // Packet containing lite netgame info.
|
||||
#define UPID_DUMP 6 // Packet containing why player cannot join this game.
|
||||
#define UPID_ADDPLAYER 7 // Packet from Host containing info about a new player.
|
||||
#define UPID_REQUEST 8 // New player says: "I want to be inside of you!" (haha, sorry I could not resist) / Packet containing request to join the game actually.
|
||||
#define UPID_QUIT_JOINING 9 // Packet from a player who suddenly quits joining.
|
||||
#define UPID_SYNC 10 // Packet from host containing full netgame info to sync players up.
|
||||
#define UPID_OBJECT_DATA 11 // Packet from host containing object buffer.
|
||||
#define UPID_PING 12 // Packet from host containing his GameTime and the Ping list. Client returns this time to host as UPID_PONG and adapts the ping list.
|
||||
#define UPID_PONG 13 // Packet answer from client to UPID_PING. Contains the time the initial ping packet was sent.
|
||||
#define UPID_ENDLEVEL_H 14 // Packet from Host to all Clients containing connect-states and kills information about everyone in the game.
|
||||
#define UPID_ENDLEVEL_C 15 // Packet from Client to Host containing connect-state and kills information from this Client.
|
||||
#define UPID_PDATA_H 16 // Packet from Host to all Clients containing all players movement data.
|
||||
#define UPID_PDATA_C 17 // Packet from Client to Host containing his movement data.
|
||||
#define UPID_MDATA_P0 18 // Packet containing multi buffer from a player. Priority 0 - no ACK needed.
|
||||
#define UPID_MDATA_P1 19 // Packet containing multi buffer from a player. Priority 1 - ACK needed. Also contains pkt_num
|
||||
#define UPID_MDATA_ACK 20 // ACK packet for UPID_MDATA_P1.
|
||||
|
||||
// Structure keeping lite game infos (for netlist, etc.)
|
||||
typedef struct UDP_netgame_info_lite
|
||||
{
|
||||
struct _sockaddr game_addr;
|
||||
int program_iver;
|
||||
char game_name[NETGAME_NAME_LEN+1];
|
||||
char mission_title[MISSION_NAME_LEN+1];
|
||||
char mission_name[9];
|
||||
int levelnum;
|
||||
ubyte gamemode;
|
||||
ubyte RefusePlayers;
|
||||
ubyte difficulty;
|
||||
ubyte game_status;
|
||||
ubyte numplayers;
|
||||
ubyte max_numplayers;
|
||||
ubyte game_flags;
|
||||
ubyte team_vector;
|
||||
} __pack__ UDP_netgame_info_lite;
|
||||
|
||||
typedef struct UDP_sequence_packet
|
||||
{
|
||||
ubyte type;
|
||||
netplayer_info player;
|
||||
} __pack__ UDP_sequence_packet;
|
||||
|
||||
// player position packet structure
|
||||
typedef struct UDP_frame_info
|
||||
{
|
||||
ubyte type;
|
||||
ubyte Player_num;
|
||||
ubyte connected;
|
||||
ubyte obj_render_type;
|
||||
shortpos pos;
|
||||
} __pack__ UDP_frame_info;
|
||||
|
||||
// packet structure for multi-buffer
|
||||
typedef struct UDP_mdata_info
|
||||
{
|
||||
ubyte type;
|
||||
ubyte Player_num;
|
||||
uint32_t pkt_num;
|
||||
ushort mbuf_size;
|
||||
ubyte mbuf[UPKT_MBUF_SIZE];
|
||||
} __pack__ UDP_mdata_info;
|
||||
|
||||
// structure to store MDATA to maybe resend
|
||||
typedef struct UDP_mdata_store
|
||||
{
|
||||
int used;
|
||||
fix pkt_initial_timestamp; // initial timestamp to see if packet is outdated
|
||||
fix pkt_timestamp[MAX_PLAYERS]; // Packet timestamp
|
||||
int pkt_num; // Packet number
|
||||
ubyte Player_num; // sender of this packet
|
||||
ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected
|
||||
ubyte data[UPKT_MBUF_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose
|
||||
ushort data_size;
|
||||
} __pack__ UDP_mdata_store;
|
||||
|
||||
// structure to keep track of MDATA packets we've already got
|
||||
typedef struct UDP_mdata_recv
|
||||
{
|
||||
int pkt_num[UDP_MDATA_STOR_QUEUE_SIZE];
|
||||
int cur_slot; // index we can use for a new pkt_num
|
||||
} __pack__ UDP_mdata_recv;
|
||||
|
|
@ -1,658 +0,0 @@
|
|||
// UDP/IP driver
|
||||
// Taken inspiration from bomberclone - Thanks Steffen!
|
||||
|
||||
#define UDP_LEN_HOSTNAME 128
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "console.h"
|
||||
#include "error.h"
|
||||
#include "netdrv.h"
|
||||
#include "net_ipx.h"
|
||||
#include "timer.h"
|
||||
#include "netdrv_udp.h"
|
||||
#include "key.h"
|
||||
#include "text.h"
|
||||
|
||||
int UDP_sock = -1;
|
||||
unsigned int myid=0; // My personal ID which I will get from host and will be used for IPX-Node
|
||||
struct peer_list UDP_Peers[MAX_CONNECTIONS]; // The Peer list.
|
||||
void udp_close_socket(socket_t *unused);
|
||||
|
||||
// Receive Configuration: Exchanging Peers, doing Handshakes, etc.
|
||||
void udp_receive_cfg(char *text, struct _sockaddr *sAddr)
|
||||
{
|
||||
switch (text[4])
|
||||
{
|
||||
case CFG_FIRSTCONTACT_REQ:
|
||||
{
|
||||
int i, clientid=0;
|
||||
ubyte outbuf[6];
|
||||
|
||||
// Check if sAddr is not used already (existing client or if client got this packet)
|
||||
for (i = 1; i < MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
|
||||
{
|
||||
clientid=i;
|
||||
}
|
||||
}
|
||||
|
||||
// If we haven't found a place already...
|
||||
if (!clientid)
|
||||
{
|
||||
for (i = 1; i < MAX_CONNECTIONS; i++) // ... find a free place in list...
|
||||
{
|
||||
if (!UDP_Peers[i].valid) // ... Found it!
|
||||
{
|
||||
clientid=i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!clientid)
|
||||
return;
|
||||
|
||||
UDP_Peers[clientid].valid=1;
|
||||
UDP_Peers[clientid].timestamp=timer_get_fixed_seconds();
|
||||
memset(UDP_Peers[clientid].hs_list,0,MAX_CONNECTIONS);
|
||||
UDP_Peers[clientid].hstimeout=0;
|
||||
UDP_Peers[clientid].relay=0;
|
||||
memcpy(&UDP_Peers[clientid].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
|
||||
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
|
||||
outbuf[4]=CFG_FIRSTCONTACT_ACK; // CFG Type
|
||||
outbuf[5]=clientid; // personal ID for the client
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) sAddr, sizeof(struct _sockaddr)); // Send!
|
||||
return;
|
||||
}
|
||||
|
||||
case CFG_FIRSTCONTACT_ACK:
|
||||
{
|
||||
My_Seq.player.network.ipx.node[0] = MyAddress[4] = myid = text[5]; // got my ID
|
||||
memcpy(&UDP_Peers[0].addr,sAddr,sizeof(struct _sockaddr)); // Add sender -> host!
|
||||
UDP_Peers[0].valid=1;
|
||||
UDP_Peers[0].timestamp=timer_get_fixed_seconds();
|
||||
return;
|
||||
}
|
||||
|
||||
// got signal from host to connect with a new client
|
||||
case CFG_HANDSHAKE_INIT:
|
||||
{
|
||||
int i;
|
||||
struct _sockaddr tmpAddr;
|
||||
ubyte outbuf[6];
|
||||
|
||||
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
|
||||
outbuf[4]=CFG_HANDSHAKE_PING; // CFG Type
|
||||
outbuf[5]=myid; // my ID that will be assigned to the new client
|
||||
memcpy(&tmpAddr,text+5,sizeof(struct _sockaddr));
|
||||
for (i=0; i<3; i++)
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &tmpAddr, sizeof(struct _sockaddr)); // send!
|
||||
return;
|
||||
}
|
||||
|
||||
// Got a Handshake Ping from a connected client -> Add it to peer list and Pong back
|
||||
case CFG_HANDSHAKE_PING:
|
||||
{
|
||||
int i;
|
||||
ubyte outbuf[6];
|
||||
|
||||
memcpy(&UDP_Peers[(int)text[5]].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
|
||||
UDP_Peers[(int)text[5]].valid=1;
|
||||
UDP_Peers[(int)text[5]].timestamp=timer_get_fixed_seconds();
|
||||
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
|
||||
outbuf[4]=CFG_HANDSHAKE_PONG; // CFG Type
|
||||
outbuf[5]=myid; // my ID
|
||||
for (i=0; i<3; i++)
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) sAddr, sizeof(struct _sockaddr)); // send!
|
||||
return;
|
||||
}
|
||||
|
||||
// Got response from new client -> Send this to host and add new client to peer list
|
||||
case CFG_HANDSHAKE_PONG:
|
||||
{
|
||||
int i;
|
||||
ubyte outbuf[7];
|
||||
|
||||
memcpy(&UDP_Peers[(int)text[5]].addr,sAddr,sizeof(struct _sockaddr)); // Copy address of new client to Peer list
|
||||
UDP_Peers[(int)text[5]].valid=1;
|
||||
UDP_Peers[(int)text[5]].timestamp=timer_get_fixed_seconds();
|
||||
memcpy(outbuf+0,DXXcfgid,4); // PacketCFG ID
|
||||
outbuf[4]=CFG_HANDSHAKE_ACK; // CFG Type
|
||||
outbuf[5]=myid; // my ID
|
||||
outbuf[6]=text[5]; // ID of the added client
|
||||
for (i=0; i<3; i++)
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &UDP_Peers[0].addr, sizeof(struct _sockaddr)); // send!
|
||||
return;
|
||||
}
|
||||
|
||||
// Got a message from a client about a new client -> Add hs_list info!
|
||||
case CFG_HANDSHAKE_ACK:
|
||||
{
|
||||
UDP_Peers[(int)text[6]].hs_list[(int)text[5]]=1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Handshaking between clients
|
||||
// Here the HOST will motivate existing clients to connect to a new one
|
||||
// If all went good, client can join, if not host will relay this client if GameArg.MplIpRelay or being dumped
|
||||
int udp_handshake_frame(struct _sockaddr *sAddr, char *inbuf)
|
||||
{
|
||||
int i,checkid=-1;
|
||||
|
||||
if (Network_send_objects)
|
||||
return 0;//if we are currently letting someone else join, we don't know if this person can join ok.
|
||||
|
||||
// Find the player we want to Handshake
|
||||
for (i=1; i<MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (!memcmp(sAddr,(struct sockaddr*)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
|
||||
{
|
||||
checkid=i;
|
||||
UDP_Peers[checkid].valid=2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkid<0)
|
||||
return 0;
|
||||
|
||||
if (UDP_Peers[checkid].relay)
|
||||
return 1;
|
||||
|
||||
// send Handshake init to all valid players except the new one (checkid)
|
||||
for (i=1; i<MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (UDP_Peers[i].valid == 3 && i != checkid && !UDP_Peers[i].relay && memcmp(sAddr,(struct sockaddr*)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
|
||||
{
|
||||
char outbuf[6+sizeof(struct _sockaddr)];
|
||||
|
||||
// send request to connected clients to handshake with new client
|
||||
memcpy(outbuf+0,DXXcfgid,4);
|
||||
outbuf[4]=CFG_HANDSHAKE_INIT;
|
||||
memcpy(outbuf+5,sAddr,sizeof(struct _sockaddr));
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
|
||||
}
|
||||
}
|
||||
|
||||
// check if that client is already fully joined
|
||||
if (UDP_Peers[checkid].valid == 3)
|
||||
return 1;
|
||||
|
||||
// Now check if Handshake was successful on requesting player - if not, return 0
|
||||
for (i=1; i<MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (UDP_Peers[i].valid == 3 && memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
|
||||
{
|
||||
if (UDP_Peers[checkid].hs_list[i] != 1 && !UDP_Peers[i].relay)
|
||||
{
|
||||
if (UDP_Peers[checkid].hstimeout > 10)
|
||||
{
|
||||
if (GameArg.MplIpRelay)
|
||||
{
|
||||
con_printf(CON_NORMAL,"UDP: Relaying Client #%i over Host\n",checkid);
|
||||
UDP_Peers[checkid].relay=1;
|
||||
memset(UDP_Peers[checkid].hs_list,1,MAX_CONNECTIONS);
|
||||
UDP_Peers[checkid].valid=3;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
UDP_Peers[checkid].hstimeout++;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set all vals to true since this could be the first client in our list that had no need to Handshake.
|
||||
// However in that case this should be true for the next client joning
|
||||
memset(UDP_Peers[checkid].hs_list,1,MAX_CONNECTIONS);
|
||||
UDP_Peers[checkid].valid=3;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Check if we got data from sAddr within the last 10 seconds (NETWORK_TIMEOUT). If yes, update timestamp of peer, otherwise remove it.
|
||||
void udp_check_disconnect(struct _sockaddr *sAddr, char *text)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Check all connections for Disconnect or Timeout.
|
||||
for (i = 0; i < MAX_CONNECTIONS; i++)
|
||||
{
|
||||
// Find the player we got the packet from
|
||||
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)))
|
||||
{
|
||||
// Update timestamp
|
||||
UDP_Peers[i].timestamp=timer_get_fixed_seconds();
|
||||
}
|
||||
else if (UDP_Peers[i].valid && UDP_Peers[i].timestamp + NETWORK_TIMEOUT <= timer_get_fixed_seconds())
|
||||
{
|
||||
// Timeout!
|
||||
UDP_Peers[i].valid=0;
|
||||
UDP_Peers[i].timestamp=0;
|
||||
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
|
||||
UDP_Peers[i].hstimeout=0;
|
||||
UDP_Peers[i].relay=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Relay packets over Host
|
||||
void udp_packet_relay(char *text, int len, struct _sockaddr *sAddr)
|
||||
{
|
||||
int i, relayid=0;
|
||||
|
||||
// Only host will relay
|
||||
if (myid)
|
||||
return;
|
||||
|
||||
// Never relay PING packets
|
||||
if (text[0] == PID_PING_SEND || text[0] == PID_PING_RETURN)
|
||||
return;
|
||||
|
||||
// We got an PID_PDATA_ACK packet - check if it is for me (host). If not, transfer it to designated client if sender or receiver is relay client.
|
||||
if (text[0] == PID_PDATA_ACK)
|
||||
{
|
||||
if ((int)text[2] != Player_num && (UDP_Peers[NetPlayers.players[(int)text[1]].network.ipx.node[0]].relay || UDP_Peers[NetPlayers.players[(int)text[2]].network.ipx.node[0]].relay))
|
||||
{
|
||||
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[NetPlayers.players[(int)text[2]].network.ipx.node[0]].addr, sizeof(struct _sockaddr));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if sender is a relay client and store ID if so
|
||||
for (i = 1; i < MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (!memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && UDP_Peers[i].relay)
|
||||
{
|
||||
relayid=i;
|
||||
}
|
||||
}
|
||||
|
||||
if (relayid>0) // Relay packets from relay client to all others
|
||||
{
|
||||
for (i = 1; i < MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && i != relayid && UDP_Peers[i].valid>1)
|
||||
{
|
||||
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
|
||||
}
|
||||
}
|
||||
}
|
||||
else // Relay packets from normal client to relay clients
|
||||
{
|
||||
for (i = 1; i < MAX_CONNECTIONS; i++)
|
||||
{
|
||||
if (memcmp(sAddr,(struct _sockaddr *)&UDP_Peers[i].addr,sizeof(struct _sockaddr)) && UDP_Peers[i].relay)
|
||||
{
|
||||
sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[i].addr, sizeof(struct _sockaddr));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve address
|
||||
int udp_dns_filladdr(char *host, int hostlen, int port, int portlen, struct _sockaddr *sAddr)
|
||||
{
|
||||
struct hostent *he;
|
||||
|
||||
#ifdef IPv6
|
||||
int socktype=AF_INET6;
|
||||
|
||||
he = gethostbyname2 (host,socktype);
|
||||
|
||||
if (!he)
|
||||
{
|
||||
socktype=AF_INET;
|
||||
he = gethostbyname2 (host,socktype);
|
||||
}
|
||||
|
||||
if (!he)
|
||||
{
|
||||
con_printf(CON_URGENT,"udp_dns_filladdr (gethostbyname) failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
((struct _sockaddr *) sAddr)->sin6_family = socktype; // host byte order
|
||||
((struct _sockaddr *) sAddr)->sin6_port = htons (port); // short, network byte order
|
||||
((struct _sockaddr *) sAddr)->sin6_flowinfo = 0;
|
||||
((struct _sockaddr *) sAddr)->sin6_addr = *((struct in6_addr *) he->h_addr);
|
||||
((struct _sockaddr *) sAddr)->sin6_scope_id = 0;
|
||||
#else
|
||||
if ((he = gethostbyname (host)) == NULL) // get the host info
|
||||
{
|
||||
con_printf(CON_URGENT,"udp_dns_filladdr (gethostbyname) failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not resolve address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
((struct _sockaddr *) sAddr)->sin_family = _af; // host byte order
|
||||
((struct _sockaddr *) sAddr)->sin_port = htons (port); // short, network byte order
|
||||
((struct _sockaddr *) sAddr)->sin_addr = *((struct in_addr *) he->h_addr);
|
||||
memset (&(((struct _sockaddr *) sAddr)->sin_zero), '\0', 8); // zero the rest of the struct
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Connect to a game host - we want to play!
|
||||
int UDPConnectManual(char *textaddr)
|
||||
{
|
||||
struct _sockaddr HostAddr;
|
||||
fix start_time = 0;
|
||||
ubyte node[6];
|
||||
char outbuf[12], inbuf[5];
|
||||
ubyte null_addr[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
// Resolve address
|
||||
if (udp_dns_filladdr(textaddr, LEN_SERVERNAME, UDP_BASEPORT, LEN_PORT, &HostAddr) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
network_init();
|
||||
N_players = 0;
|
||||
memset(node,0,6); // Host is always on ID 0
|
||||
memset(inbuf,0,5);
|
||||
memset(outbuf,0,12);
|
||||
start_time = timer_get_fixed_seconds();
|
||||
|
||||
while (!(!memcmp(inbuf+0,DXXcfgid,4) && inbuf[4] == CFG_FIRSTCONTACT_ACK)) // Yay! got ACK by this host!
|
||||
{
|
||||
// Cancel this with ESC
|
||||
if (key_inkey()==KEY_ESC)
|
||||
return 0;
|
||||
|
||||
// Timeout after 10 seconds
|
||||
if (timer_get_fixed_seconds() >= start_time + (F1_0*10) || timer_get_fixed_seconds() < start_time)
|
||||
{
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"No response by host");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Send request to get added by host...
|
||||
memcpy(outbuf+0,DXXcfgid,4);
|
||||
outbuf[4]=CFG_FIRSTCONTACT_REQ;
|
||||
sendto (UDP_sock, outbuf, sizeof(outbuf), 0, (struct sockaddr *) &HostAddr, sizeof(struct _sockaddr));
|
||||
timer_delay(500);
|
||||
// ... and wait for answer
|
||||
udp_receive_packet(NULL,inbuf,6,NULL);
|
||||
}
|
||||
|
||||
|
||||
if (get_and_show_netgame_info(null_addr,node,NULL)) // show netgame info and keep connection alive!
|
||||
return network_do_join_game(0); // join the game actually
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Open socket
|
||||
int udp_open_socket(socket_t *unused, int port)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef _WIN32
|
||||
struct _sockaddr sAddr; // my address information
|
||||
int reuse_on = -1;
|
||||
|
||||
// close stale socket
|
||||
if( UDP_sock != -1 )
|
||||
udp_close_socket(NULL);
|
||||
|
||||
memset( &sAddr, '\0', sizeof( sAddr ) );
|
||||
|
||||
if ((UDP_sock = socket (_af, SOCK_DGRAM, 0)) == -1) {
|
||||
con_printf(CON_URGENT,"udp_open_socket: socket creation failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not create socket");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// this is pretty annoying in win32. Not doing that will lead to
|
||||
// "Could not bind name to socket" errors. It may be suitable for other
|
||||
// socket implementations, too
|
||||
(void)setsockopt( UDP_sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &reuse_on, sizeof( reuse_on ));
|
||||
|
||||
#ifdef IPv6
|
||||
sAddr.sin6_family = _pf; // host byte order
|
||||
sAddr.sin6_port = htons (GameArg.MplIpBasePort+UDP_BASEPORT);; // short, network byte order
|
||||
sAddr.sin6_flowinfo = 0;
|
||||
sAddr.sin6_addr = in6addr_any; // automatically fill with my IP
|
||||
sAddr.sin6_scope_id = 0;
|
||||
#else
|
||||
sAddr.sin_family = _pf; // host byte order
|
||||
sAddr.sin_port = htons (GameArg.MplIpBasePort+UDP_BASEPORT); // short, network byte order
|
||||
sAddr.sin_addr.s_addr = INADDR_ANY; // automatically fill with my IP
|
||||
#endif
|
||||
|
||||
memset (&(sAddr.sin_zero), '\0', 8); // zero the rest of the struct
|
||||
|
||||
if (bind (UDP_sock, (struct sockaddr *) &sAddr, sizeof (struct sockaddr)) == -1)
|
||||
{
|
||||
con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not bind name to socket");
|
||||
udp_close_socket(NULL);
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
struct addrinfo hints,*res,*sres;
|
||||
int err,ai_family_;
|
||||
char cport[LEN_PORT];
|
||||
|
||||
// close stale socket
|
||||
if( UDP_sock != -1 )
|
||||
udp_close_socket(NULL);
|
||||
|
||||
memset (&hints, '\0', sizeof (struct addrinfo));
|
||||
memset(cport,'\0',sizeof(char)*LEN_PORT);
|
||||
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
hints.ai_family = _pf;
|
||||
hints.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
ai_family_ = 0;
|
||||
|
||||
sprintf(cport,"%i",UDP_BASEPORT+GameArg.MplIpBasePort);
|
||||
|
||||
if ((err = getaddrinfo (NULL, cport, &hints, &res)) == 0)
|
||||
{
|
||||
sres = res;
|
||||
while ((ai_family_ == 0) && (sres))
|
||||
{
|
||||
if (sres->ai_family == _pf || _pf == PF_UNSPEC)
|
||||
ai_family_ = sres->ai_family;
|
||||
else
|
||||
sres = sres->ai_next;
|
||||
}
|
||||
|
||||
if (sres == NULL)
|
||||
sres = res;
|
||||
|
||||
ai_family_ = sres->ai_family;
|
||||
if (ai_family_ != _pf && _pf != PF_UNSPEC)
|
||||
{
|
||||
// ai_family is not identic
|
||||
freeaddrinfo (res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((UDP_sock = socket (sres->ai_family, SOCK_DGRAM, 0)) < 0)
|
||||
{
|
||||
con_printf(CON_URGENT,"udp_open_socket: socket creation failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not create socket");
|
||||
freeaddrinfo (res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((err = bind (UDP_sock, sres->ai_addr, sres->ai_addrlen)) < 0)
|
||||
{
|
||||
con_printf(CON_URGENT,"udp_open_socket: bind name to socket failed\n");
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not bind name to socket");
|
||||
udp_close_socket(NULL);
|
||||
freeaddrinfo (res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
freeaddrinfo (res);
|
||||
}
|
||||
else {
|
||||
UDP_sock = -1;
|
||||
con_printf(CON_URGENT,"udp_open_socket (getaddrinfo):%s\n", gai_strerror (err));
|
||||
nm_messagebox(TXT_ERROR,1,TXT_OK,"Could not get address information:\n%s",gai_strerror (err));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Prepare UDP_Peers
|
||||
for (i=0; i<MAX_CONNECTIONS;i++)
|
||||
{
|
||||
memset(&UDP_Peers[i].addr,0,sizeof(struct _sockaddr));
|
||||
UDP_Peers[i].valid=0;
|
||||
UDP_Peers[i].timestamp=0;
|
||||
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
|
||||
UDP_Peers[i].hstimeout=0;
|
||||
UDP_Peers[i].relay=0;
|
||||
}
|
||||
myid=0;
|
||||
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
// Closes an existing udp socket
|
||||
void udp_close_socket(socket_t *unused)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (UDP_sock != -1)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
closesocket(UDP_sock);
|
||||
#else
|
||||
close (UDP_sock);
|
||||
#endif
|
||||
}
|
||||
UDP_sock = -1;
|
||||
|
||||
// Prepare UDP_Peers
|
||||
for (i=0; i<MAX_CONNECTIONS;i++)
|
||||
{
|
||||
memset(&UDP_Peers[i].addr,0,sizeof(struct _sockaddr));
|
||||
UDP_Peers[i].valid=0;
|
||||
UDP_Peers[i].timestamp=0;
|
||||
memset(UDP_Peers[i].hs_list,0,MAX_CONNECTIONS);
|
||||
UDP_Peers[i].hstimeout=0;
|
||||
UDP_Peers[i].relay=0;
|
||||
}
|
||||
myid=0;
|
||||
}
|
||||
|
||||
// Send text to someone
|
||||
// This function get's IPXHeader as address. The first byte in this header represents the UDP_Peers ID, so sAddr can be assigned.
|
||||
static int udp_send_packet(socket_t *unused, IPXPacket_t *IPXHeader, ubyte *text, int len)
|
||||
{
|
||||
// check if Header is in a sane range for UDP_Peers
|
||||
if (IPXHeader->Destination.Node[0] >= MAX_CONNECTIONS)
|
||||
return 0;
|
||||
|
||||
if (!UDP_Peers[IPXHeader->Destination.Node[0]].valid)
|
||||
{
|
||||
// PID_PDATA_ACK needs to be delivered to designated peer. If there's a relay player, Host cannot relay, as PID_PDATA_ACK is sent specifically.
|
||||
// So in this case, if we encounter invalid ID while PID_PDATA_ACK, wrap this packet to Host so it can be relayed.
|
||||
if (text[0] == PID_PDATA_ACK)
|
||||
return sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[0].addr, sizeof(struct _sockaddr));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sendto (UDP_sock, text, len, 0, (struct sockaddr *) &UDP_Peers[IPXHeader->Destination.Node[0]].addr, sizeof(struct _sockaddr));
|
||||
}
|
||||
|
||||
// Gets some text
|
||||
// Returns 0 if nothing on there
|
||||
// rd can safely be ignored here
|
||||
int udp_receive_packet(socket_t *unused, char *text, int len, struct recv_data *rd)
|
||||
{
|
||||
unsigned int clen = sizeof (struct _sockaddr), msglen = 0;
|
||||
struct _sockaddr sAddr;
|
||||
|
||||
if (UDP_sock == -1)
|
||||
return -1;
|
||||
|
||||
if (udp_general_packet_ready(NULL))
|
||||
{
|
||||
msglen = recvfrom (UDP_sock, text, len, 0, (struct sockaddr *) &sAddr, &clen);
|
||||
|
||||
if (msglen < 0)
|
||||
return 0;
|
||||
|
||||
if ((msglen >= 0) && (msglen < len))
|
||||
text[msglen] = 0;
|
||||
|
||||
// Wrap UDP CFG packets here!
|
||||
if (!memcmp(text+0,DXXcfgid,4))
|
||||
{
|
||||
udp_receive_cfg(text,&sAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Check for Disconnect!
|
||||
udp_check_disconnect(&sAddr, text);
|
||||
|
||||
// Seems someone wants to enter the game actually.
|
||||
// If I am host, init handshakes! if not sccessful, return 0 and never process this player's request signal - cool thing, eh?
|
||||
if (text[0] == PID_REQUEST && myid == 0)
|
||||
if (!udp_handshake_frame(&sAddr,text))
|
||||
return 0;
|
||||
|
||||
udp_packet_relay(text, msglen, &sAddr);
|
||||
}
|
||||
|
||||
return msglen;
|
||||
}
|
||||
|
||||
int udp_general_packet_ready(socket_t *unused)
|
||||
{
|
||||
fd_set set;
|
||||
struct timeval tv;
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(UDP_sock, &set);
|
||||
tv.tv_sec = tv.tv_usec = 0;
|
||||
if (select(UDP_sock + 1, &set, NULL, NULL, &tv) > 0)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct net_driver netdrv_udp =
|
||||
{
|
||||
udp_open_socket,
|
||||
udp_close_socket,
|
||||
udp_send_packet,
|
||||
udp_receive_packet,
|
||||
udp_general_packet_ready,
|
||||
0, //save 4 bytes. udp/ip is completely inaccessable by the other methods, so we don't need to worry about compatibility.
|
||||
NETPROTO_UDP
|
||||
};
|
|
@ -1,71 +0,0 @@
|
|||
/* $Id: udp.h,v 1.2 2005/03/27 01:31:50 stpohle Exp $
|
||||
* UDP Network */
|
||||
|
||||
#ifndef _UDP_H
|
||||
#define _UDP_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#ifndef _MSC_VER
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
#include <winsock.h>
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
// #define IPv6 // just here for debugging - set via SConstruct
|
||||
|
||||
#ifdef IPv6
|
||||
#define _sockaddr sockaddr_in6
|
||||
#define _af AF_INET6
|
||||
#define _pf PF_INET6
|
||||
#else
|
||||
#define _sockaddr sockaddr_in
|
||||
#define _af AF_INET
|
||||
#define _pf PF_INET
|
||||
#endif
|
||||
|
||||
#define DXXcfgid "D2Rc" // identification string for UDP/IP configuration packets
|
||||
#define MAX_CONNECTIONS 32 // maximum connections that can be stored in UDPPeers - as this currently bases on player node[0] this must NOT exceed ubyte!
|
||||
#define LEN_SERVERNAME 41
|
||||
#define LEN_PORT 6
|
||||
#define UDP_BASEPORT 31017
|
||||
|
||||
// CFGFlags
|
||||
#define CFG_FIRSTCONTACT_REQ 1 // Request to get in contact with host for the first time to show the game
|
||||
#define CFG_FIRSTCONTACT_ACK 2 // Ack so client proceeds and adds host addr to it's peer list
|
||||
#define CFG_HANDSHAKE_INIT 3 // Request from Host to Handshake between two clients
|
||||
#define CFG_HANDSHAKE_ACK 4 // Handshake OK answer
|
||||
#define CFG_HANDSHAKE_PING 5 // Contact from connected client to a new one
|
||||
#define CFG_HANDSHAKE_PONG 6 // Answer from new client - Handshake successful
|
||||
|
||||
typedef struct peer_list
|
||||
{
|
||||
struct _sockaddr addr; // real address information about this peer
|
||||
int valid; // 1 = client connected / 2 = client ready for handshaking / 3 = client done with handshake and fully joined / 0 between clients = no connection -> relay
|
||||
fix timestamp; // time of received packet - used for timeout
|
||||
char hs_list[MAX_CONNECTIONS]; // list to store all handshake results from clients assigned to this peer
|
||||
int hstimeout; // counts the number of tries the client tried to connect - if reached 10, client put to relay if allowed
|
||||
int relay; // relay packets by/to this clients over host
|
||||
} __pack__ peer_list;
|
||||
|
||||
extern sequence_packet My_Seq;
|
||||
extern void network_init(void);
|
||||
extern int network_do_join_game();
|
||||
extern int get_and_show_netgame_info(ubyte *server, ubyte *node, ubyte *net_address);
|
||||
extern int udp_receive_packet(socket_t *unused, char *text, int len, struct recv_data *rd);
|
||||
extern int udp_general_packet_ready(socket_t *unused);
|
||||
|
||||
#endif
|
|
@ -1534,6 +1534,9 @@ int newdemo_read_demo_start(enum purpose_type purpose)
|
|||
}
|
||||
#endif
|
||||
|
||||
nd_read_int(&Game_mode);
|
||||
Game_mode &= ~GM_NETWORK;
|
||||
|
||||
#ifdef NETWORK
|
||||
change_playernum_to((Game_mode >> 16) & 0x7);
|
||||
if (Game_mode & GM_TEAM) {
|
||||
|
@ -2488,7 +2491,7 @@ int newdemo_read_frame_information(int rewrite)
|
|||
break;
|
||||
}
|
||||
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD)) {
|
||||
Players[pnum].connected = 0;
|
||||
Players[pnum].connected = CONNECT_DISCONNECTED;
|
||||
if (!new_player) {
|
||||
memcpy(Players[pnum].callsign, old_callsign, CALLSIGN_LEN+1);
|
||||
Players[pnum].net_killed_total = killed_total;
|
||||
|
@ -2497,7 +2500,7 @@ int newdemo_read_frame_information(int rewrite)
|
|||
N_players--;
|
||||
}
|
||||
} else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD)) {
|
||||
Players[pnum].connected = 1;
|
||||
Players[pnum].connected = CONNECT_PLAYING;
|
||||
Players[pnum].net_kills_total = 0;
|
||||
Players[pnum].net_killed_total = 0;
|
||||
memcpy(Players[pnum].callsign, new_callsign, CALLSIGN_LEN+1);
|
||||
|
@ -2517,9 +2520,9 @@ int newdemo_read_frame_information(int rewrite)
|
|||
break;
|
||||
}
|
||||
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
|
||||
Players[pnum].connected = 0;
|
||||
Players[pnum].connected = CONNECT_DISCONNECTED;
|
||||
else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
|
||||
Players[pnum].connected = 1;
|
||||
Players[pnum].connected = CONNECT_PLAYING;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2533,9 +2536,9 @@ int newdemo_read_frame_information(int rewrite)
|
|||
break;
|
||||
}
|
||||
if ((Newdemo_vcr_state == ND_STATE_REWINDING) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEBACKWARD))
|
||||
Players[pnum].connected = 1;
|
||||
Players[pnum].connected = CONNECT_PLAYING;
|
||||
else if ((Newdemo_vcr_state == ND_STATE_PLAYBACK) || (Newdemo_vcr_state == ND_STATE_FASTFORWARD) || (Newdemo_vcr_state == ND_STATE_ONEFRAMEFORWARD))
|
||||
Players[pnum].connected = 0;
|
||||
Players[pnum].connected = CONNECT_DISCONNECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
252
main/noloss.c
252
main/noloss.c
|
@ -1,252 +0,0 @@
|
|||
/*
|
||||
* Packet-loss-prevention code for DXX-Rebirth
|
||||
* This code will save the data field of a netgame packet to a queue.
|
||||
* Saving is only done for urgent packets.
|
||||
* Each PDATA packet will be ACK'd by the receiver.
|
||||
* If all receivers submitted their ACK packets to initial sender, the packet is removed from the queue.
|
||||
* If a player has not ACK'd a PDATA packet within a second, it will resend to him.
|
||||
* Timeout, disconnects, or changes in player count are handled as well.
|
||||
*/
|
||||
|
||||
#include "noloss.h"
|
||||
|
||||
struct pdata_noloss_store noloss_queue[NOLOSS_QUEUE_SIZE];
|
||||
struct pdata_recv noloss_pdata_got[MAX_PLAYERS];
|
||||
extern frame_info MySyncPack;
|
||||
extern int MaxXDataSize;
|
||||
extern int N_players;
|
||||
|
||||
// Adds a packet to our queue
|
||||
// Should be called when an IMPORTANT frameinfo packet is created
|
||||
void noloss_add_packet_to_queue(int urgent, int pkt_num, char *data, ushort data_size)
|
||||
{
|
||||
int i;
|
||||
|
||||
// Only proceed if this is a version-checked game
|
||||
if (Netgame.protocol_version != MULTI_PROTO_D2X_VER)
|
||||
return;
|
||||
|
||||
// Only add urgent packets
|
||||
if (!urgent)
|
||||
return;
|
||||
|
||||
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
|
||||
{
|
||||
int j;
|
||||
|
||||
if (noloss_queue[i].used)
|
||||
continue;
|
||||
|
||||
noloss_queue[i].used = 1;
|
||||
noloss_queue[i].pkt_initial_timestamp = GameTime;
|
||||
noloss_queue[i].pkt_timestamp = GameTime;
|
||||
noloss_queue[i].pkt_num = pkt_num;
|
||||
for (j = 0; j < MAX_PLAYERS; j++)
|
||||
{
|
||||
if (Players[j].connected)
|
||||
noloss_queue[i].player_ack[j] = 0;
|
||||
else
|
||||
noloss_queue[i].player_ack[j] = 1; // Player is not connected so set to positive in case he joins
|
||||
}
|
||||
memcpy( &noloss_queue[i].data[0], data, data_size );
|
||||
noloss_queue[i].data_size = data_size;
|
||||
|
||||
return;
|
||||
}
|
||||
con_printf(CON_DEBUG, "Noloss queue is full!\n");
|
||||
}
|
||||
|
||||
// Send the packet stored in queue list at index to given receiver_pnum
|
||||
// Called from inside noloss_process_queue()
|
||||
void noloss_send_queued_packet(int queue_index)
|
||||
{
|
||||
short_frame_info ShortSyncPack;
|
||||
int objnum = Players[Player_num].objnum;
|
||||
|
||||
// Update Timestamp
|
||||
noloss_queue[queue_index].pkt_timestamp = GameTime;
|
||||
// Copy the multibuf data to MySyncPack
|
||||
memcpy( &MySyncPack.data[0],&noloss_queue[queue_index].data[0], noloss_queue[queue_index].data_size );
|
||||
MySyncPack.data_size = noloss_queue[queue_index].data_size;
|
||||
|
||||
// The following code HEAVILY borrows from network_do_frame()
|
||||
// Create a frameinfo packet
|
||||
if (Netgame.ShortPackets)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ubyte send_data[MAX_DATA_SIZE];
|
||||
#endif
|
||||
int i;
|
||||
|
||||
memset(&ShortSyncPack,0,sizeof(short_frame_info));
|
||||
create_shortpos(&ShortSyncPack.thepos, Objects+objnum, 0);
|
||||
ShortSyncPack.type = PID_PDATA_NOLOSS;
|
||||
ShortSyncPack.playernum = Player_num;
|
||||
ShortSyncPack.obj_render_type = Objects[objnum].render_type;
|
||||
ShortSyncPack.level_num = Current_level_num;
|
||||
ShortSyncPack.data_size = MySyncPack.data_size;
|
||||
memcpy (&ShortSyncPack.data[0],&MySyncPack.data[0],MySyncPack.data_size);
|
||||
|
||||
MySyncPack.numpackets = INTEL_INT(noloss_queue[queue_index].pkt_num);
|
||||
ShortSyncPack.numpackets = MySyncPack.numpackets;
|
||||
#ifndef WORDS_BIGENDIAN
|
||||
for(i=0; i<N_players; i++)
|
||||
{
|
||||
// Check if a player is not connected anymore so we won't send a packet and set positive
|
||||
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
|
||||
noloss_queue[queue_index].player_ack[i] = 1;
|
||||
|
||||
if(Players[i].connected && (i != Player_num))
|
||||
netdrv_send_packet_data((ubyte*)&ShortSyncPack, sizeof(short_frame_info) - MaxXDataSize + MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
|
||||
}
|
||||
#else
|
||||
squish_short_frame_info(ShortSyncPack, send_data);
|
||||
|
||||
for(i=0; i<N_players; i++) {
|
||||
// Check if a player is not connected anymore so we won't send a packet and set positive
|
||||
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
|
||||
noloss_queue[queue_index].player_ack[i] = 1;
|
||||
|
||||
if(!noloss_queue[queue_index].player_ack[i] && Players[i].connected && (i != Player_num))
|
||||
netdrv_send_packet_data((ubyte*)send_data, IPX_SHORT_INFO_SIZE-MaxXDataSize+MySyncPack.data_size, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
else // If long packets
|
||||
{
|
||||
int i;
|
||||
|
||||
MySyncPack.numpackets = noloss_queue[queue_index].pkt_num;
|
||||
MySyncPack.type = PID_PDATA_NOLOSS;
|
||||
MySyncPack.playernum = Player_num;
|
||||
MySyncPack.obj_render_type = Objects[objnum].render_type;
|
||||
MySyncPack.level_num = Current_level_num;
|
||||
MySyncPack.obj_segnum = Objects[objnum].segnum;
|
||||
MySyncPack.obj_pos = Objects[objnum].pos;
|
||||
MySyncPack.obj_orient = Objects[objnum].orient;
|
||||
MySyncPack.phys_velocity = Objects[objnum].mtype.phys_info.velocity;
|
||||
MySyncPack.phys_rotvel = Objects[objnum].mtype.phys_info.rotvel;
|
||||
|
||||
for(i=0; i<N_players; i++)
|
||||
{
|
||||
// Check if a player is not connected anymore so we won't send a packet and set positive
|
||||
if (!noloss_queue[queue_index].player_ack[i] && !Players[i].connected)
|
||||
noloss_queue[queue_index].player_ack[i] = 1;
|
||||
|
||||
if(!noloss_queue[queue_index].player_ack[i] && Players[i].connected && (i != Player_num))
|
||||
{
|
||||
send_frameinfo_packet(&MySyncPack, NetPlayers.players[i].network.ipx.server, NetPlayers.players[i].network.ipx.node,Players[i].net_address);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MySyncPack.data_size = 0; // Start data over at 0 length.
|
||||
}
|
||||
|
||||
// We have received a PDATA packet. Send ACK response to sender!
|
||||
// ACK packet needs to contain: packet num, sender player num, receiver player num
|
||||
// Call in network_process_packet() at case PID_PDATA
|
||||
// Also check in our noloss_pdata_got list, if we got this packet already.
|
||||
// If yes, return 0 (not valid)! If not, add this pkt_num to our list and return 1 so the pdata packet will be processed!
|
||||
int noloss_validate_pdata(int pkt_num, ubyte receiver_pnum)
|
||||
{
|
||||
noloss_ack ack;
|
||||
int i;
|
||||
|
||||
memset(&ack,0,sizeof(noloss_ack));
|
||||
|
||||
ack.type = PID_PDATA_ACK;
|
||||
ack.sender_pnum = Player_num;
|
||||
ack.receiver_pnum = receiver_pnum;
|
||||
ack.pkt_num = pkt_num;
|
||||
|
||||
netdrv_send_packet_data( (ubyte *)&ack, sizeof(noloss_ack), NetPlayers.players[receiver_pnum].network.ipx.server, NetPlayers.players[receiver_pnum].network.ipx.node,Players[receiver_pnum].net_address );
|
||||
|
||||
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
|
||||
{
|
||||
if (pkt_num == noloss_pdata_got[receiver_pnum].pkt_num[i])
|
||||
return 0;
|
||||
}
|
||||
noloss_pdata_got[receiver_pnum].cur_slot++;
|
||||
if (noloss_pdata_got[receiver_pnum].cur_slot >= NOLOSS_QUEUE_SIZE)
|
||||
noloss_pdata_got[receiver_pnum].cur_slot=0;
|
||||
noloss_pdata_got[receiver_pnum].pkt_num[noloss_pdata_got[receiver_pnum].cur_slot] = pkt_num;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// We got an ACK by a player. Set this player slot to positive!
|
||||
void noloss_got_ack(ubyte *data)
|
||||
{
|
||||
int i;
|
||||
noloss_ack *gotack = (noloss_ack *)data;
|
||||
|
||||
if (gotack->receiver_pnum != Player_num)
|
||||
return;
|
||||
|
||||
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
|
||||
{
|
||||
if (gotack->pkt_num == noloss_queue[i].pkt_num)
|
||||
{
|
||||
noloss_queue[i].player_ack[gotack->sender_pnum] = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Init/Free the queue. Call at start and end of a game or level.
|
||||
void noloss_init_queue(void)
|
||||
{
|
||||
memset(&noloss_queue,0,sizeof(pdata_noloss_store)*NOLOSS_QUEUE_SIZE);
|
||||
memset(&noloss_pdata_got,-1,sizeof(pdata_recv)*MAX_PLAYERS);
|
||||
}
|
||||
|
||||
// Reset the trace list for given player when disconnect happens
|
||||
void noloss_update_pdata_got(int player_num)
|
||||
{
|
||||
memset(&noloss_pdata_got[player_num].pkt_num,-1,sizeof(int)*NOLOSS_QUEUE_SIZE);
|
||||
noloss_pdata_got[player_num].cur_slot = -1;
|
||||
}
|
||||
|
||||
// The main queue-process function.
|
||||
// 1) Check if we can remove a packet from queue (all players positive or packet too old)
|
||||
// 2) Check if there are packets in queue which we need to re-send to player(s) (if packet is older than one second)
|
||||
void noloss_process_queue(void)
|
||||
{
|
||||
int i, count = 0;
|
||||
|
||||
for (i = 0; i < NOLOSS_QUEUE_SIZE; i++)
|
||||
{
|
||||
int j, resend = 0;
|
||||
|
||||
if (!noloss_queue[i].used)
|
||||
continue;
|
||||
|
||||
// Check if at least one connected player has not ACK'd the packet
|
||||
for (j = 0; j < N_players; j++)
|
||||
{
|
||||
if (!noloss_queue[i].player_ack[j] && Players[j].connected && j != Player_num)
|
||||
{
|
||||
resend = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we can remove a packet...
|
||||
if (!resend ||
|
||||
((noloss_queue[i].pkt_initial_timestamp + (F1_0*15) <= GameTime) || (GameTime < noloss_queue[i].pkt_initial_timestamp)))
|
||||
{
|
||||
memset(&noloss_queue[i],0,sizeof(pdata_noloss_store));
|
||||
}
|
||||
// ... otherwise resend if a second has passed
|
||||
else if ((noloss_queue[i].pkt_timestamp + F1_0 <= GameTime) || (GameTime < noloss_queue[i].pkt_timestamp))
|
||||
{
|
||||
con_printf(CON_DEBUG, "Re-Sending queued packet %i\n",i);
|
||||
noloss_send_queued_packet(i);
|
||||
count++;
|
||||
}
|
||||
|
||||
// Only send 5 packets from the queue by each time the queue process is called
|
||||
if (count >= 5)
|
||||
break;
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "strutil.h"
|
||||
#include "pstypes.h"
|
||||
#include "netpkt.h"
|
||||
#include "net_ipx.h"
|
||||
#include "game.h"
|
||||
#include "multi.h"
|
||||
#include "netpkt.h"
|
||||
#include "netdrv.h"
|
||||
#include "byteswap.h"
|
||||
|
||||
#define NOLOSS_QUEUE_SIZE 512 // Store up to 512 packets
|
||||
|
||||
// the structure list keeping the data we may want to resend
|
||||
// this does only contain the extra data field of a PDATA packet (if that isn't enough, the whole PDATA struct info still could be added later)
|
||||
typedef struct pdata_noloss_store {
|
||||
int used;
|
||||
fix pkt_initial_timestamp; // initial timestamp to see if packet is outdated
|
||||
fix pkt_timestamp; // Packet timestamp
|
||||
int pkt_num; // Packet number
|
||||
ubyte player_ack[MAX_PLAYERS]; // 0 if player has not ACK'd this packet, 1 if ACK'd or not connected
|
||||
char data[NET_XDATA_SIZE]; // extra data of a packet - contains all multibuf data we don't want to loose
|
||||
ushort data_size;
|
||||
} __pack__ pdata_noloss_store;
|
||||
|
||||
// ACK signal packet
|
||||
typedef struct noloss_ack {
|
||||
ubyte type;
|
||||
ubyte sender_pnum;
|
||||
ubyte receiver_pnum;
|
||||
int pkt_num;
|
||||
} __pack__ noloss_ack;
|
||||
|
||||
// keeps track of PDATA packets we've already got
|
||||
typedef struct pdata_recv {
|
||||
int pkt_num[NOLOSS_QUEUE_SIZE];
|
||||
int cur_slot; // index we can use for a new pkt_num
|
||||
} __pack__ pdata_recv;
|
||||
|
||||
void noloss_add_packet_to_queue(int urgent, int pkt_num, char *data, ushort data_size);
|
||||
int noloss_validate_pdata(int pkt_num, ubyte receiver_pnum);
|
||||
void noloss_got_ack(ubyte *data);
|
||||
void noloss_init_queue(void);
|
||||
void noloss_update_pdata_got(int player_num);
|
||||
void noloss_process_queue(void);
|
|
@ -1547,7 +1547,6 @@ void dead_player_frame(void)
|
|||
#ifdef NETWORK
|
||||
if (Game_mode & GM_MULTI)
|
||||
{
|
||||
//multi_send_position(Players[Player_num].objnum);
|
||||
multi_send_player_explode(MULTI_PLAYER_EXPLODE);
|
||||
}
|
||||
#endif
|
||||
|
@ -1588,7 +1587,6 @@ void dead_player_frame(void)
|
|||
#ifdef NETWORK
|
||||
if (Game_mode & GM_MULTI)
|
||||
{
|
||||
//multi_send_position(Players[Player_num].objnum);
|
||||
multi_send_player_explode(MULTI_PLAYER_EXPLODE);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
#ifdef D2XMICRO
|
||||
#define VERSION D2XMAJOR "." D2XMINOR "." D2XMICRO
|
||||
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100+atoi(D2XMICRO)
|
||||
#else
|
||||
#define VERSION D2XMAJOR "." D2XMINOR
|
||||
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100)
|
||||
#endif
|
||||
|
||||
#define D2X_IVER (atoi(D2XMAJOR)*10000+atoi(D2XMINOR)*100)
|
||||
#define DESCENT_VERSION "D2X-Rebirth v" VERSION
|
||||
|
||||
#endif /* _VERS_ID */
|
||||
|
|
|
@ -187,9 +187,9 @@ void ReadCmdArgs(void)
|
|||
GameArg.MplNoRankings = FindArg("-norankings");
|
||||
GameArg.MplPlayerMessages = FindArg("-playermessages");
|
||||
GameArg.MplIpxNetwork = get_str_arg("-ipxnetwork", NULL);
|
||||
GameArg.MplIpBasePort = get_int_arg("-ip_baseport", 0);
|
||||
GameArg.MplIpRelay = FindArg("-ip_relay");
|
||||
GameArg.MplIpHostAddr = get_str_arg("-ip_hostaddr", "");
|
||||
GameArg.MplUdpHostAddr = get_str_arg("-udp_hostaddr", "localhost");
|
||||
GameArg.MplUdpHostPort = get_int_arg("-udp_hostport", 0);
|
||||
GameArg.MplUdpMyPort = get_int_arg("-udp_myport", 0);
|
||||
|
||||
#ifdef EDITOR
|
||||
// Editor Options
|
||||
|
|
Loading…
Reference in a new issue