Adding the release of the DOOM IPX driver.

This commit is contained in:
Travis Bradshaw 2012-01-31 15:32:25 -06:00
parent 4eb368a960
commit 73424b6129
8 changed files with 1003 additions and 0 deletions

73
ipx/DOOMNET.C Normal file
View File

@ -0,0 +1,73 @@
//#define DOOM2
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <conio.h>
#include <dos.h>
#include "doomnet.h"
//#include "ipxstr.h"
#include "ipx_frch.h" // FRENCH VERSION
doomcom_t doomcom;
int vectorishooked;
void interrupt (*olddoomvect) (void);
/*
=============
=
= LaunchDOOM
=
These fields in doomcom should be filled in before calling:
short numnodes; // console is allways node 0
short ticdup; // 1 = no duplication, 2-5 = dup for
slow nets
short extratics; // 1 = send a backup tic in every
packet
short consoleplayer; // 0-3 = player number
short numplayers; // 1-4
short angleoffset; // 1 = left, 0 = center, -1 = right
short drone; // 1 = drone
=============
*/
void LaunchDOOM (void)
{
char *newargs[99];
char adrstring[10];
long flatadr;
// prepare for DOOM
doomcom.id = DOOMCOM_ID;
// hook the interrupt vector
olddoomvect = getvect (doomcom.intnum);
setvect (doomcom.intnum,(void interrupt (*)(void))MK_FP(_CS,
(int)NetISR));
vectorishooked = 1;
// build the argument list for DOOM, adding a -net &doomcom
memcpy (newargs, _argv, (_argc+1)*2);
newargs[_argc] = "-net";
flatadr = (long)_DS*16 + (unsigned)&doomcom;
sprintf (adrstring,"%lu",flatadr);
newargs[_argc+1] = adrstring;
newargs[_argc+2] = NULL;
if (!access("doom2.exe",0))
spawnv (P_WAIT, "doom2", newargs);
else
spawnv (P_WAIT, "doom", newargs);
#ifdef DOOM2
printf (STR_RETURNED"\n");
#else
printf ("Returned from DOOM\n");
#endif
}

58
ipx/DOOMNET.H Normal file
View File

@ -0,0 +1,58 @@
// doomnet.h
#define PEL_WRITE_ADR 0x3c8
#define PEL_DATA 0x3c9
#define I_ColorBlack(r,g,b) {outp(PEL_WRITE_ADR,0);outp(PEL_DATA,r);outp(PEL_DATA,g);outp(PEL_DATA,b);};
#define MAXNETNODES 8 // max computers in a game
#define MAXPLAYERS 4 // 4 players max + drones
#define CMD_SEND 1
#define CMD_GET 2
#define DOOMCOM_ID 0x12345678l
typedef struct
{
long id;
short intnum; // DOOM executes an int to send commands
// communication between DOOM and the driver
short command; // CMD_SEND or CMD_GET
short remotenode; // dest for send, set by get (-1 = no packet)
short datalength; // bytes in doomdata to be sent / bytes read
// info common to all nodes
short numnodes; // console is allways node 0
short ticdup; // 1 = no duplication, 2-5 = dup for slow nets
short extratics; // 1 = send a backup tic in every packet
short deathmatch; // 1 = deathmatch
short savegame; // -1 = new game, 0-5 = load savegame
short episode; // 1-3
short map; // 1-9
short skill; // 1-5
// info specific to this node
short consoleplayer; // 0-3 = player number
short numplayers; // 1-4
short angleoffset; // 1 = left, 0 = center, -1 = right
short drone; // 1 = drone
// packet data to be sent
char data[512];
} doomcom_t;
extern doomcom_t doomcom;
extern void interrupt (*olddoomvect) (void);
extern int vectorishooked;
int CheckParm (char *check);
void LaunchDOOM (void);
void interrupt NetISR (void);

294
ipx/IPXNET.C Normal file
View File

@ -0,0 +1,294 @@
// ipxnet.c
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <process.h>
#include <values.h>
#include "ipxnet.h"
/*
==========================================================================
===
IPX PACKET DRIVER
==========================================================================
===
*/
packet_t packets[NUMPACKETS];
nodeadr_t nodeadr[MAXNETNODES+1]; // first is local, last is broadcast
nodeadr_t remoteadr; // set by each GetPacket
localadr_t localadr; // set at startup
extern int socketid;
void far (*IPX)(void);
long localtime; // for time stamp in packets
long remotetime;
//===========================================================================
int OpenSocket(short socketNumber)
{
_DX = socketNumber;
_BX = 0;
_AL = 0;
IPX();
if(_AL)
Error ("OpenSocket: 0x%x", _AL);
return _DX;
}
void CloseSocket(short socketNumber)
{
_DX = socketNumber;
_BX = 1;
IPX();
}
void ListenForPacket(ECB *ecb)
{
_SI = FP_OFF(ecb);
_ES = FP_SEG(ecb);
_BX = 4;
IPX();
if(_AL)
Error ("ListenForPacket: 0x%x", _AL);
}
void GetLocalAddress (void)
{
_SI = FP_OFF(&localadr);
_ES = FP_SEG(&localadr);
_BX = 9;
IPX();
}
/*
====================
=
= InitNetwork
=
====================
*/
void InitNetwork (void)
{
int i,j;
//
// get IPX function address
//
_AX = 0x7a00;
geninterrupt(0x2f);
if(_AL != 0xff)
Error ("IPX not detected\n");
IPX = MK_FP(_ES, _DI);
//
// allocate a socket for sending and receiving
//
socketid = OpenSocket ( (socketid>>8) + ((socketid&255)<<8) );
GetLocalAddress();
//
// set up several receiving ECBs
//
memset (packets,0,NUMPACKETS*sizeof(packet_t));
for (i=1 ; i<NUMPACKETS ; i++)
{
packets[i].ecb.ECBSocket = socketid;
packets[i].ecb.FragmentCount = 1;
packets[i].ecb.fAddress[0] = FP_OFF(&packets[i].ipx);
packets[i].ecb.fAddress[1] = FP_SEG(&packets[i].ipx);
packets[i].ecb.fSize = sizeof(packet_t)-sizeof(ECB);
ListenForPacket (&packets[i].ecb);
}
//
// set up a sending ECB
//
memset (&packets[0],0,sizeof(packets[0]));
packets[0].ecb.ECBSocket = socketid;
packets[0].ecb.FragmentCount = 2;
packets[0].ecb.fAddress[0] = FP_OFF(&packets[0].ipx);
packets[0].ecb.fAddress[1] = FP_SEG(&packets[0].ipx);
for (j=0 ; j<4 ; j++)
packets[0].ipx.dNetwork[j] = localadr.network[j];
packets[0].ipx.dSocket[0] = socketid&255;
packets[0].ipx.dSocket[1] = socketid>>8;
packets[0].ecb.f2Address[0] = FP_OFF(&doomcom.data);
packets[0].ecb.f2Address[1] = FP_SEG(&doomcom.data);
// known local node at 0
for (i=0 ; i<6 ; i++)
nodeadr[0].node[i] = localadr.node[i];
// broadcast node at MAXNETNODES
for (j=0 ; j<6 ; j++)
nodeadr[MAXNETNODES].node[j] = 0xff;
}
/*
====================
=
= ShutdownNetwork
=
====================
*/
void ShutdownNetwork (void)
{
if (IPX)
CloseSocket (socketid);
}
/*
==============
=
= SendPacket
=
= A destination of MAXNETNODES is a broadcast
==============
*/
void SendPacket (int destination)
{
int j;
// set the time
packets[0].time = localtime;
// set the address
for (j=0 ; j<6 ; j++)
packets[0].ipx.dNode[j] =
packets[0].ecb.ImmediateAddress[j] =
nodeadr[destination].node[j];
// set the length (ipx + time + datalength)
packets[0].ecb.fSize = sizeof(IPXPacket) + 4;
packets[0].ecb.f2Size = doomcom.datalength + 4;
// send the packet
_SI = FP_OFF(&packets[0]);
_ES = FP_SEG(&packets[0]);
_BX = 3;
IPX();
if(_AL)
Error("SendPacket: 0x%x", _AL);
while(packets[0].ecb.InUseFlag != 0)
{
// IPX Relinquish Control - polled drivers MUST have this here!
_BX = 10;
IPX();
}
}
unsigned short ShortSwap (unsigned short i)
{
return ((i&255)<<8) + ((i>>8)&255);
}
/*
==============
=
= GetPacket
=
= Returns false if no packet is waiting
=
==============
*/
int GetPacket (void)
{
int packetnum;
int i, j;
long besttic;
packet_t *packet;
// if multiple packets are waiting, return them in order by time
besttic = MAXLONG;
packetnum = -1;
doomcom.remotenode = -1;
for ( i = 1 ; i < NUMPACKETS ; i++)
{
if (packets[i].ecb.InUseFlag)
{
continue;
}
if (packets[i].time < besttic)
{
besttic = packets[i].time;
packetnum = i;
}
}
if (besttic == MAXLONG)
return 0; // no packets
packet = &packets[packetnum];
if (besttic == -1 && localtime != -1)
{
ListenForPacket (&packet->ecb);
return 0; // setup broadcast from other game
}
remotetime = besttic;
//
// got a good packet
//
if (packet->ecb.CompletionCode)
Error ("GetPacket: ecb.ComletionCode = 0x%x",packet->ecb.CompletionCode);
// set remoteadr to the sender of the packet
memcpy (&remoteadr, packet->ipx.sNode, sizeof(remoteadr));
for (i=0 ; i<doomcom.numnodes ; i++)
if (!memcmp(&remoteadr, &nodeadr[i], sizeof(remoteadr)))
break;
if (i < doomcom.numnodes)
doomcom.remotenode = i;
else
{
if (localtime != -1)
{ // this really shouldn't happen
ListenForPacket (&packet->ecb);
return 0;
}
}
// copy out the data
doomcom.datalength = ShortSwap(packet->ipx.PacketLength) - 38;
memcpy (&doomcom.data, &packet->data, doomcom.datalength);
// repost the ECB
ListenForPacket (&packet->ecb);
return 1;
}

117
ipx/IPXNET.H Normal file
View File

@ -0,0 +1,117 @@
// ipxnet.h
typedef struct
{
char private[512];
} doomdata_t;
#include "DoomNet.h"
//===========================================================================
#define NUMPACKETS 10 // max outstanding packets before loss
// setupdata_t is used as doomdata_t during setup
typedef struct
{
short gameid; // so multiple games can setup at once
short drone;
short nodesfound;
short nodeswanted;
} setupdata_t;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long LONG;
typedef struct IPXPacketStructure
{
WORD PacketCheckSum; /* high-low */
WORD PacketLength; /* high-low */
BYTE PacketTransportControl;
BYTE PacketType;
BYTE dNetwork[4]; /* high-low */
BYTE dNode[6]; /* high-low */
BYTE dSocket[2]; /* high-low */
BYTE sNetwork[4]; /* high-low */
BYTE sNode[6]; /* high-low */
BYTE sSocket[2]; /* high-low */
} IPXPacket;
typedef struct
{
BYTE network[4]; /* high-low */
BYTE node[6]; /* high-low */
} localadr_t;
typedef struct
{
BYTE node[6]; /* high-low */
} nodeadr_t;
typedef struct ECBStructure
{
WORD Link[2]; /* offset-segment */
WORD ESRAddress[2]; /* offset-segment */
BYTE InUseFlag;
BYTE CompletionCode;
WORD ECBSocket; /* high-low */
BYTE IPXWorkspace[4]; /* N/A */
BYTE DriverWorkspace[12]; /* N/A */
BYTE ImmediateAddress[6]; /* high-low */
WORD FragmentCount; /* low-high */
WORD fAddress[2]; /* offset-segment */
WORD fSize; /* low-high */
WORD f2Address[2]; /* offset-segment */
WORD f2Size; /* low-high */
} ECB;
// time is used by the communication driver to sequence packets returned
// to DOOM when more than one is waiting
typedef struct
{
ECB ecb;
IPXPacket ipx;
long time;
doomdata_t data;
} packet_t;
extern doomcom_t doomcom;
extern int gameid;
extern nodeadr_t nodeadr[MAXNETNODES+1];
extern int localnodenum;
extern long localtime; // for time stamp in packets
extern long remotetime; // timestamp of last packet gotten
extern nodeadr_t remoteadr;
extern int myargc;
extern char **myargv;
void Error (char *error, ...);
void InitNetwork (void);
void ShutdownNetwork (void);
void SendPacket (int destination);
int GetPacket (void);
int CheckParm (char *check);
void PrintAddress (nodeadr_t *adr, char *str);

420
ipx/IPXSETUP.C Normal file
View File

@ -0,0 +1,420 @@
// ipxsetup.c
#define DOOM2
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <dos.h>
#include <string.h>
#include <process.h>
#include <stdarg.h>
#include <bios.h>
#include "ipxnet.h"
//#include "ipxstr.h"
#include "ipx_frch.h" // FRENCH VERSION
int gameid;
int numnetnodes;
int socketid = 0x869c; // 0x869c is the official DOOM socket
int myargc;
char **myargv;
setupdata_t nodesetup[MAXNETNODES];
/*
=================
=
= Error
=
= For abnormal program terminations
=
=================
*/
void Error (char *error, ...)
{
va_list argptr;
if (vectorishooked)
setvect (doomcom.intnum,olddoomvect);
va_start (argptr,error);
vprintf (error,argptr);
va_end (argptr);
printf ("\n");
ShutdownNetwork ();
exit (1);
}
/*
=================
=
= CheckParm
=
= Checks for the given parameter in the program's command line arguments
=
= Returns the argument number (1 to argc-1) or 0 if not present
=
=================
*/
int CheckParm(char *parm)
{
int i;
for(i = 1; i < myargc; i++)
if(stricmp(parm, myargv[i]) == 0)
return i;
return 0;
}
/*
=============
=
= NetISR
=
=============
*/
void interrupt NetISR (void)
{
if (doomcom.command == CMD_SEND)
{
localtime++;
SendPacket (doomcom.remotenode);
}
else if (doomcom.command == CMD_GET)
{
GetPacket ();
}
}
/*
===================
=
= LookForNodes
=
= Finds all the nodes for the game and works out player numbers among
them
=
= Exits with nodesetup[0..numnodes] and nodeadr[0..numnodes] filled in
===================
*/
void LookForNodes (void)
{
int i,j,k;
int netids[MAXNETNODES];
int netplayer[MAXNETNODES];
struct time time;
int oldsec;
setupdata_t *setup, *dest;
char str[80];
int total, console;
//
// wait until we get [numnetnodes] packets, then start playing
// the playernumbers are assigned by netid
//
printf(STR_ATTEMPT, numnetnodes);
printf (STR_LOOKING);
oldsec = -1;
setup = (setupdata_t *)&doomcom.data;
localtime = -1; // in setup time, not game time
//
// build local setup info
//
nodesetup[0].nodesfound = 1;
nodesetup[0].nodeswanted = numnetnodes;
doomcom.numnodes = 1;
do
{
//
// check for aborting
//
while ( bioskey(1) )
{
if ( (bioskey (0) & 0xff) == 27)
Error ("\n\n"STR_NETABORT);
}
//
// listen to the network
//
while (GetPacket ())
{
if (doomcom.remotenode == -1)
dest = &nodesetup[doomcom.numnodes];
else
dest = &nodesetup[doomcom.remotenode];
if (remotetime != -1)
{ // an early game packet, not a setup packet
if (doomcom.remotenode == -1)
Error (STR_UNKNOWN);
// if it allready started, it must have found all nodes
dest->nodesfound = dest->nodeswanted;
continue;
}
// update setup ingo
memcpy (dest, setup, sizeof(*dest) );
if (doomcom.remotenode != -1)
continue; // allready know that node address
//
// this is a new node
//
memcpy (&nodeadr[doomcom.numnodes], &remoteadr
, sizeof(nodeadr[doomcom.numnodes]) );
//
// if this node has a lower address, take all startup info
//
if ( memcmp (&remoteadr, &nodeadr[0], sizeof(&remoteadr) )
< 0 )
{
}
doomcom.numnodes++;
printf ("\n"STR_FOUND"\n");
if (doomcom.numnodes < numnetnodes)
printf (STR_LOOKING);
}
//
// we are done if all nodes have found all other nodes
//
for (i=0 ; i<doomcom.numnodes ; i++)
if (nodesetup[i].nodesfound != nodesetup[i].nodeswanted)
break;
if (i == nodesetup[0].nodeswanted)
break; // got them all
//
// send out a broadcast packet every second
//
gettime (&time);
if (time.ti_sec == oldsec)
continue;
oldsec = time.ti_sec;
printf (".");
doomcom.datalength = sizeof(*setup);
nodesetup[0].nodesfound = doomcom.numnodes;
memcpy (&doomcom.data, &nodesetup[0], sizeof(*setup));
SendPacket (MAXNETNODES); // send to all
} while (1);
//
// count players
//
total = 0;
console = 0;
for (i=0 ; i<numnetnodes ; i++)
{
if (nodesetup[i].drone)
continue;
total++;
if (total > MAXPLAYERS)
Error (STR_MORETHAN,MAXPLAYERS);
if (memcmp (&nodeadr[i], &nodeadr[0], sizeof(nodeadr[0])) < 0)
console++;
}
if (!total)
Error (STR_NONESPEC);
doomcom.consoleplayer = console;
doomcom.numplayers = total;
printf (STR_CONSOLEIS"\n", console+1, total);
}
//========================================================
//
// Find a Response File
//
//========================================================
void FindResponseFile (void)
{
int i;
#define MAXARGVS 100
for (i = 1;i < myargc;i++)
if (myargv[i][0] == '@')
{
FILE * handle;
int size;
int k;
int index;
int indexinfile;
char *infile;
char *file;
char *moreargs[20];
char *firstargv;
// READ THE RESPONSE FILE INTO MEMORY
handle = fopen (&myargv[i][1],"rb");
if (!handle)
Error (STR_NORESP);
printf(STR_FOUNDRESP" \"%s\"!\n",strupr(&myargv[i][1]));
fseek (handle,0,SEEK_END);
size = ftell(handle);
fseek (handle,0,SEEK_SET);
file = malloc (size);
fread (file,size,1,handle);
fclose (handle);
// KEEP ALL CMDLINE ARGS FOLLOWING @RESPONSEFILE ARG
for (index = 0,k = i+1; k < myargc; k++)
moreargs[index++] = myargv[k];
firstargv = myargv[0];
myargv = malloc(sizeof(char *)*MAXARGVS);
memset(myargv,0,sizeof(char *)*MAXARGVS);
myargv[0] = firstargv;
infile = file;
indexinfile = k = 0;
indexinfile++; // SKIP PAST ARGV[0] (KEEP IT)
do
{
myargv[indexinfile++] = infile+k;
while(k < size &&
((*(infile+k)>= ' '+1) && (*(infile+k)<='z')))
k++;
*(infile+k) = 0;
while(k < size &&
((*(infile+k)<= ' ') || (*(infile+k)>'z')))
k++;
} while(k < size);
for (k = 0;k < index;k++)
myargv[indexinfile++] = moreargs[k];
myargc = indexinfile;
// DISPLAY ARGS
// printf("%d command-line args:\n",myargc);
// for (k=1;k<myargc;k++)
// printf("%s\n",myargv[k]);
break;
}
}
/*
=============
=
= main
=
=============
*/
void main (void)
{
int i;
unsigned char far *vector;
//
// determine game parameters
//
gameid = 0;
numnetnodes = 2;
doomcom.ticdup = 1;
doomcom.extratics = 1;
doomcom.episode = 1;
doomcom.map = 1;
doomcom.skill = 2;
doomcom.deathmatch = 0;
printf("\n"
"-----------------------------\n"
#ifdef DOOM2
STR_DOOMNETDRV"\n"
#else
"DOOM NETWORK DEVICE DRIVER\n"
#endif
"v1.22\n"
"-----------------------------\n");
myargc = _argc;
myargv = _argv;
FindResponseFile();
if((i = CheckParm("-nodes")) != 0)
numnetnodes = atoi(myargv[i+1]);
if((i = CheckParm("-vector")) != 0)
{
doomcom.intnum = sscanf ("0x%x",myargv[i+1]);
vector = *(char far * far *)(doomcom.intnum*4);
if(vector != NULL && *vector != 0xcf)
{
printf(STR_VECTSPEC"\n", doomcom.intnum);
exit(-1);
}
}
else
{
for(doomcom.intnum = 0x60 ; doomcom.intnum <= 0x66 ;
doomcom.intnum++)
{
vector = *(char far * far *)(doomcom.intnum*4);
if(vector == NULL || *vector == 0xcf)
break;
}
if(doomcom.intnum == 0x67)
{
printf(STR_NONULL"\n");
exit(-1);
}
}
printf(STR_COMMVECT"\n",doomcom.intnum);
if((i = CheckParm("-port")) != 0)
{
socketid = atoi (myargv[i+1]);
printf (STR_USEALT"\n", socketid);
}
InitNetwork ();
LookForNodes ();
localtime = 0;
LaunchDOOM ();
ShutdownNetwork ();
if (vectorishooked)
setvect (doomcom.intnum,olddoomvect);
exit(0);
}

19
ipx/IPXSTR.H Normal file
View File

@ -0,0 +1,19 @@
#define STR_NETABORT "Network game synchronization aborted."
#define STR_UNKNOWN "Got an unknown game packet during setup"
#define STR_FOUND "Found a node!"
#define STR_LOOKING "Looking for a node"
#define STR_MORETHAN "More than %i players specified!"
#define STR_NONESPEC "No players specified for game!"
#define STR_CONSOLEIS "Console is player %i of %i"
#define STR_NORESP "No such response file!"
#define STR_FOUNDRESP "Found response file"
#define STR_DOOMNETDRV "DOOM II NETWORK DEVICE DRIVER"
#define STR_VECTSPEC "The specified vector (0x%02x) was already hooked."
#define STR_NONULL \
"Warning: no NULL or iret interrupt vectors were found in the 0x60 to 0x66\n"\
"range. You can specify a vector with the -vector 0x<num> parameter."
#define STR_COMMVECT "Communicating with interrupt vector 0x%x"
#define STR_USEALT "Using alternate port %i for network"
#define STR_RETURNED "Returned from DOOM II"
#define STR_ATTEMPT "Attempting to find all players for %i player net play. "\
"Press ESC to exit.\n"

21
ipx/IPX_FRCH.H Normal file
View File

@ -0,0 +1,21 @@
#define STR_NETABORT "Synchronisation du jeu sur rseau annule."
#define STR_UNKNOWN "Paquet de jeu inconnu durant la configuration"
#define STR_FOUND "Noeud dtect!"
#define STR_LOOKING "Recherche d'un noeud"
#define STR_MORETHAN "Plus de %i joueurs spcifis!"
#define STR_NONESPEC "Pas de joueurs spcifis pour le jeu!"
#define STR_CONSOLEIS "Console: joueur %i sur %i"
#define STR_NORESP "Ce fichier de rponse n'existe pas!"
#define STR_FOUNDRESP "Fichier de rponse trouv"
#define STR_DOOMNETDRV "GESTIONNAIRE DE RESEAU DOOM II"
#define STR_VECTSPEC "Le vecteur spcifi (0x%02x) tait dj… connect."
#define STR_NONULL \
"Attention: pas de vecteurs d'interruption NULL ou iret trouvs entre 0x60 et 0x66.\n"\
"Vous pouvez spcifier un vecteur avec le paramŠtre -vector 0x<numro>."
#define STR_COMMVECT "Communication avec le vecteur d'interruption 0x%x"
#define STR_USEALT "Utilisation du port alternatif %i pour le rseau"
#define STR_RETURNED "Retour de DOOM II"
#define STR_ATTEMPT \
"Tentatative de recherche de tous les joueurs pour le jeu en riseau `%i jouers\n" \
"Appuyez sur ECHAP pour quitter.\n"

1
ipx/README Normal file
View File

@ -0,0 +1 @@
This is the source for the DOOM ipx network driver.