commit 73424b6129f1c3ca9fc22aedcfe1f5330db137a9
parent 4eb368a960647c8cc82d721d0183629ae10759d1
Author: Travis Bradshaw <travis.bradshaw@idsoftware.com>
Date:   Tue, 31 Jan 2012 15:32:25 -0600
Adding the release of the DOOM IPX driver.
Diffstat:
| A | ipx/DOOMNET.C |  |  | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | ipx/DOOMNET.H |  |  | 58 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | ipx/IPXNET.C |  |  | 294 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | ipx/IPXNET.H |  |  | 117 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | ipx/IPXSETUP.C |  |  | 420 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ | 
| A | ipx/IPXSTR.H |  |  | 19 | +++++++++++++++++++ | 
| A | ipx/IPX_FRCH.H |  |  | 21 | +++++++++++++++++++++ | 
| A | ipx/README |  |  | 1 | + | 
8 files changed, 1003 insertions(+), 0 deletions(-)
diff --git a/ipx/DOOMNET.C b/ipx/DOOMNET.C
@@ -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
+}
diff --git a/ipx/DOOMNET.H b/ipx/DOOMNET.H
@@ -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);
+
diff --git a/ipx/IPXNET.C b/ipx/IPXNET.C
@@ -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;
+}
+
diff --git a/ipx/IPXNET.H b/ipx/IPXNET.H
@@ -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);
+
diff --git a/ipx/IPXSETUP.C b/ipx/IPXSETUP.C
@@ -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);
+	 }
+
+
diff --git a/ipx/IPXSTR.H b/ipx/IPXSTR.H
@@ -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"
diff --git a/ipx/IPX_FRCH.H b/ipx/IPX_FRCH.H
@@ -0,0 +1,21 @@
+#define STR_NETABORT	"Synchronisation du jeu sur r‚seau annul‚e."
+#define STR_UNKNOWN	"Paquet de jeu inconnu durant la configuration"
+#define STR_FOUND		"Noeud d‚tect‚!"
+#define STR_LOOKING		"Recherche d'un noeud"
+#define STR_MORETHAN	"Plus de %i joueurs sp‚cifi‚s!"
+#define STR_NONESPEC	"Pas de joueurs sp‚cifi‚s pour le jeu!"
+#define STR_CONSOLEIS	"Console: joueur %i sur %i"
+#define STR_NORESP		"Ce fichier de r‚ponse n'existe pas!"
+#define STR_FOUNDRESP   "Fichier de r‚ponse trouv‚"
+#define STR_DOOMNETDRV	"GESTIONNAIRE DE RESEAU DOOM II"
+#define STR_VECTSPEC	"Le vecteur sp‚cifi‚ (0x%02x) ‚tait d‚j… connect‚."
+#define STR_NONULL	\
+"Attention: pas de vecteurs d'interruption NULL ou iret trouv‚s entre 0x60 et 0x66.\n"\
+"Vous pouvez sp‚cifier un vecteur avec le paramŠtre -vector 0x<num‚ro>."
+#define STR_COMMVECT	"Communication avec le vecteur d'interruption 0x%x"
+#define STR_USEALT		"Utilisation du port alternatif %i pour le r‚seau"
+#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"
+
diff --git a/ipx/README b/ipx/README
@@ -0,0 +1 @@
+This is the source for the DOOM ipx network driver.