diff main.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.c	Sat Dec 06 05:41:29 1997 +0000
@@ -0,0 +1,865 @@
+/* $Id: main.c,v 1.1.1.1 1997/12/06 05:41:29 darius Exp $ */
+
+/*
+ * main.c
+ */
+#include "copyright.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <pwd.h>
+#ifdef hpux
+#include <time.h>
+#else
+#include <sys/time.h>
+#include <sys/wait.h>
+#endif				/* hpux */
+#include "Wlib.h"
+#include "defs.h"
+#include "struct.h"
+#include "data.h"
+#include "packets.h"
+#include "proto.h"
+#include "gameconf.h"
+#ifdef SOUND
+#include "Slib.h"
+#endif
+#include "sound.h"
+
+jmp_buf env;
+
+#ifdef AMIGA
+/* needed for metafork... implemented by running a whole new copy
+   don't honestly know why I bothered ;-) */
+char **command_line;
+int global_argc;
+#endif
+
+#ifdef GATEWAY
+#define DEFAULT_GATEWAY		"atlgw"	/* for Quar */
+
+static char *get_gw P((void));
+static unsigned long mkaddr P((char *m));
+static void getUdpPort P((void));
+#endif
+
+extern int UdpLocalPort;
+/* Prototypes */
+static void printUsage P((char *prog));
+static void show_credits ();
+
+int
+main(argc, argv)
+    int     argc;
+    char  **argv;
+{
+    int     intrupt();
+    int     team, s_type;
+    char   *dpyname = NULL;
+    int     usage = 0;
+    int     err = 0;
+    char   *name, *ptr, *cp;
+#if !defined(NeXT) && !defined(RS6K) && !defined(SVR4)
+    char   *rindex();
+#endif
+    struct passwd *pwent;
+    int     passive = 0;
+#ifdef METASERVER
+    int     usemeta = 0;
+#endif				/* METASERVER */
+/*    char *defaultsFile=NULL;*/
+
+    pseudo[0] = defpasswd[0] = '\0';
+
+#ifdef AMIGA
+    command_line = argv;
+    global_argc=argc;
+#endif
+
+    name = *argv++;
+    argc--;
+    if ((ptr = rindex(name, '/')) != NULL)
+	name = ptr + 1;
+#ifdef GATEWAY
+    netaddr = -1;		/* special NULL address */
+    serverName = get_gw();	/* default machine is gw */
+#endif
+    while (*argv) {
+	if (**argv != '-') {
+	    serverName = *argv;	/* don't abort argument processing */
+	    argv++;
+	    argc--;
+	} else {
+	    ++*argv;
+
+	    argc--;
+	    ptr = *argv++;
+	    while (*ptr) {
+		switch (*ptr) {
+		case 'C':	/* character name */
+		    (void) strncpy(pseudo, *argv, sizeof(pseudo));
+		    argv++;
+		    argc--;
+		    break;
+
+		case 'c':	/* Credits */
+		    show_credits();
+		    exit (0);
+		    break;
+
+		case 'P':	/* authorization password */
+		    (void) strncpy(defpasswd, *argv, sizeof(defpasswd));
+		    {
+			int     i;
+			for (i = 0; (*argv)[i]; i++)
+			    (*argv)[i] = 0;
+		    }
+		    argv++;
+		    argc--;
+		    break;
+
+		case 'u':
+		    usage++;
+		    break;
+		case 's':
+		    if (*argv) {
+			xtrekPort = atoi(*argv);
+			passive = 1;
+			argv++;
+			argc--;
+		    }
+		    break;
+		case 'p':
+		    if (*argv) {
+			xtrekPort = atoi(*argv);
+			argv++;
+			argc--;
+		    }
+		    break;
+		case 'd':
+		    dpyname = *argv;
+		    argc--;
+		    argv++;
+		    break;
+#ifdef METASERVER
+		case 'm':
+		    usemeta = 1;
+		    break;
+#endif				/* METASERVER */
+		case 'h':
+		    serverName = *argv;
+		    if (!serverName)
+			err++;
+#ifdef GATEWAY
+		    gw_mach = *argv;
+#endif
+		    argc--;
+		    argv++;
+		    break;
+#ifdef GATEWAY
+		case 'H':
+		    netaddr = mkaddr(*argv);
+		    argc--;
+		    argv++;
+		    break;
+#endif
+
+		case 't':
+		    title = *argv;
+		    argc--;
+		    argv++;
+		    break;
+		case 'r':
+		    defaultsFile = *argv;
+		    argv++;
+		    argc--;
+		    break;
+#ifdef AUTHORIZE
+		case 'o':
+		    RSA_Client = -1;
+		    break;
+		case 'R':
+		    RSA_Client = -2;
+		    break;
+#else
+		case 'o':
+		case 'R':
+		    printf("This client does not have binary authorization.\n");
+		    break;
+#endif
+		case 'e':
+#ifdef AUTHORIZE
+		    checkExpire(1);
+#else
+		    printf("This client does not RSA verify and will not expire.\n");
+#endif
+		    exit(0);
+		    break;
+		case 'f':	/* list ftp sites */
+		    fprintf(stderr, "\n\
+The newest version of the Paradise client can be found at:\n\
+      ftp.pnetrek.org in /pub/paradise/bin/\n\
+or    ftp.cs.umn.edu  in /users/glamm/paradise/bin/\n\
+\n\
+Quick ftp instructions:\n\
+This assumes you are bob@school.edu and are using a Sun workstation\n\
+('sparc' architecture).  Modify with your mailing address and architecture.\n\
+Type:\n\
+   ftp ftp.cs.umn.edu\n\
+   (at name prompt) anonymous\n\
+   (at password prompt) bob@school.edu\n\
+   (at ftp> prompt) cd users/glamm/paradise/bin\n\
+   (at ftp> prompt) binary\n\
+   (at ftp> prompt) dir\n\
+   (lots of files printed - pick out the latest release for your architecture.\n\
+    all the client binaries begin with 'netrek'.)\n\
+   (at ftp> prompt) get netrek.Sparc-SunOS-static\n\
+   (note: static and dynamic are functionally the same.\n\
+  (at ftp> prompt) bye\n\
+\n\
+That's it!\n");
+		    exit(0);
+		case 'G':
+		    if (*argv) {
+			ghoststart++;
+			ghost_pno = atoi(*argv);
+			printf("Emergency restart being attempted...\n");
+			argv++;
+			argc--;
+		    }
+		    break;
+		case '2':	/* force paradise */
+		    paradise = 1;
+		    break;
+#ifdef RECORDER
+		case 'F':	/* File playback */
+		    if (*argv) {
+			playFile = strdup(*argv);
+			playback = 1;
+			argv++;
+			argc--;
+		    }
+		    break;
+#endif
+		case 'U':
+		    if(*argv == NULL || (UdpLocalPort = atoi(*argv)) <= 0) {
+			fprintf(stderr, "Error: -U requires a port number\n");
+			usage++;
+			break;
+		    }
+		    argc--;
+		    argv++;
+		    break;
+		default:
+		    fprintf(stderr, "%s: unknown option '%c'\n", name, *ptr);
+		    err++;
+		    break;
+		}
+		ptr++;
+	    }
+	}
+    }
+#ifdef GATEWAY
+    if (netaddr == -1) {
+	fprintf(stderr,
+		"netrek: no remote address set (-H).  Restricted server will not work.\n");
+    }
+#endif
+
+
+
+    inittrigtables();
+
+    initStars();		/* moved from redraw.c at KAO\'s suggestion */
+
+    if (usage || err) {
+	printUsage(name);
+#ifdef AUTHORIZE
+	checkExpire(1);
+#endif
+	exit(0);
+	/* exit(err); Exits from checkExpire */
+    }
+    defaultsFile = initDefaults(defaultsFile);
+
+#ifdef AUTHORIZE
+    if (RSA_Client != -1)
+	checkExpire(0);
+#endif
+
+    /* compatability */
+    if (argc > 0)
+	serverName = argv[0];
+
+    srandom(getpid() + time((long *) 0));
+
+#ifdef RECORDER
+    if(playback || booleanDefault("playback",0)) {
+        defNickName = "playback";
+	usemeta=0;
+        serverName = "playback";
+    } else
+#endif
+    {
+        if (serverName) {
+	    char    temp[80], *s;
+	    sprintf(temp, "server.%s", serverName);
+	    if ((s = getdefault(temp))) {
+		s=strdup(s);
+		printf("Using nickname \"%s\" for server %s\n", serverName, s);
+		defNickName = serverName;
+		serverName = s;
+		defFlavor = getdefault("flavor");
+		if(defFlavor) 
+                    defFlavor=strdup(defFlavor);
+	    }
+	}
+	if (!serverName) {
+	    if(serverName = getdefault("server"))
+		serverName = strdup(serverName);
+        }
+	if (!serverName && !passive) {
+	    serverName = DEFAULT_SERVER;
+#ifdef METASERVER
+	    usemeta = 1;		/* no server specified, show the menu */
+#endif
+	}
+	if (passive)
+	    serverName = "passive";	/* newwin gets a wrong title otherwise */
+
+	if (xtrekPort < 0)
+	    xtrekPort = intDefault("port", -1);
+	if (xtrekPort < 0)
+	    xtrekPort = DEFAULT_PORT;
+#if 0
+#ifdef AUTHORIZE
+	if (RSA_Client >= 0)
+	    RSA_Client = booleanDefault("useRSA", RSA_Client);
+	else
+	    RSA_Client = (RSA_Client == -2);
+#endif
+#endif				/* 0 */
+
+    } /* playback */
+    build_default_configuration();
+
+#ifdef METASERVER
+    metaserverAddress = stringDefault("metaserver",
+				      "metaserver.ecst.csuchico.edu");
+    if (usemeta)
+	parsemeta();
+#endif				/* METASERVER */
+
+    W_Initialize(dpyname);
+#ifdef SOUND
+    S_Initialize();
+#endif
+
+
+#ifdef METASERVER
+    metaFork = booleanDefault("metaFork", metaFork);
+    /* do the metawindow thang */
+    if (usemeta) {
+	metawindow();
+	metainput();
+	if (metaFork)
+	    W_Initialize(dpyname);
+	newwin(dpyname, name);
+    } else
+#endif				/* METASERVER */
+
+	/* this creates the necessary x windows for the game */
+	newwin(dpyname, name);
+
+#ifdef TIMELORD
+    start_timelord();
+#endif
+
+    /* open memory...? */
+    openmem();
+#ifdef RECORDER
+    if (!startPlayback())
+#endif
+    {
+	if (!passive) {
+	    callServer(xtrekPort, serverName);
+	} else {
+	    connectToServer(xtrekPort);
+	}
+    }
+#ifdef FEATURE
+    sendFeature("FEATURE_PACKETS", 'S', 1, 0, 0);
+#endif
+
+    timeStart = time(NULL);
+    findslot();
+
+    /* sets all the settings from defaults file (.xtrekrc probably) */
+    resetDefaults();
+
+#ifdef UNIX_SOUND
+    init_sound();
+    play_sound(SND_PARADISE);
+#endif
+
+    mapAll();
+/*    signal(SIGINT, SIG_IGN);*/
+    signal(SIGCHLD, (void (*) ()) reaper);
+
+    /* Get login name */
+    if ((pwent = getpwuid(getuid())) != NULL)
+	(void) strncpy(login, pwent->pw_name, sizeof(login));
+    else
+	(void) strncpy(login, "Bozo", sizeof(login));
+    login[sizeof(login) - 1] = '\0';
+
+    if (pseudo[0] == '\0') {
+	if ((cp = getdefault("name")) != 0)
+	    (void) strncpy(pseudo, cp, sizeof(pseudo));
+	else
+	    (void) strncpy(pseudo, login, sizeof(pseudo));
+    }
+    pseudo[sizeof(pseudo) - 1] = '\0';
+
+    if (defpasswd[0] == '\0') {
+	char buf[100], buf2[100];  /* added password by character name -JR */
+	sprintf(buf,"password.%s",pseudo);
+        if (serverName)         /* password by server name -TH */
+            sprintf(buf2, "password.%s", serverName);
+	if((cp = getdefault(buf)) || (cp = getdefault(buf2)) ||
+ 		(cp = getdefault("password")))
+	    (void) strncpy(defpasswd, cp, sizeof(defpasswd));
+    }
+    defpasswd[sizeof(defpasswd) - 1] = '\0';
+
+    /*
+       sendLoginReq("Gray Lensman", "hh", "sfd", 0); loginAccept = -1; while
+       (loginAccept == -1) { socketPause(1,0); readFromServer(); }
+    */
+    getname(pseudo, defpasswd);
+    loggedIn = 1;
+#ifdef TIMER
+    timeBank[T_SERVER] = timeStart;
+    timeBank[T_DAY] = 0;
+#endif				/* TIMER */
+
+
+#ifdef AUTOKEY
+    /* autokey.c */
+    autoKeyDefaults();
+#endif				/* AUTOKEY */
+
+    /*
+       Set p_hostile to hostile, so if keeppeace is on, the guy starts off
+       hating everyone (like a good fighter should)
+    */
+    me->p_hostile = (1 << number_of_teams) - 1;
+
+    redrawTstats();
+
+    me->p_planets = 0;
+    me->p_genoplanets = 0;
+    me->p_armsbomb = 0;
+    me->p_genoarmsbomb = 0;
+    /* Set up a reasonable default */
+    me->p_whydead = KQUIT;
+    me->p_teami = -1;
+    s_type = defaultShip(CRUISER);	/* from rlb7h 11/15/91 TC */
+
+    if (booleanDefault("netStats", 1))
+	startPing();		/* tell the server that we support pings */
+
+#ifdef AUTOKEY
+    if (autoKey) {
+	/* XX: changes entire state of display */
+	W_AutoRepeatOff();
+    }
+#endif
+    /*
+       hack to make galaxy class ships work.  This could be more elegant, but
+       the configuration code would have to be modified quite a bit, since
+       the client doesn't know if it's on a paradise server until after it
+       connects, and it needs the configuration info before it connects.
+    */
+    init_galaxy_class();
+
+    initkeymap(-1);		/* needs to have ship types initialized -JR */
+
+    setjmp(env);		/* Reentry point of game */
+
+    if (ghoststart) {
+	int     i;
+
+	ghoststart = 0;
+
+	for (i = -1; i < 5; i++)
+	    if (teaminfo[i].letter == me->p_mapchars[0])
+		break;
+
+	me->p_teami = i;
+
+	if (me->p_damage > me->p_ship->s_maxdamage) {
+	    me->p_status = POUTFIT;
+	} else
+	    me->p_status = PALIVE;
+    } else
+	me->p_status = POUTFIT;
+
+    while (1) {
+	switch (me->p_status) {
+	case POUTFIT:
+	case PTQUEUE:
+	    /* give the player the motd and find out which team he wants */
+#if 1
+	    new_entrywindow(&team, &s_type);
+#else
+	    entrywindow(&team, &s_type);
+#endif
+	    allowPlayerlist = 1;
+	    if (W_IsMapped(playerw))
+		playerlist();
+
+#ifdef RECORDER
+	    if (!playback)
+#endif
+		if (team == -1) {
+		    W_DestroyWindow(w);
+#ifdef AUTOKEY
+		    if (autoKey)
+			W_AutoRepeatOn();
+#endif
+		    sendByeReq();
+		    sleep(1);
+		    printf("OK, bye!\n");
+		    EXIT(0);
+		}
+	    sendVersion();
+	    myship = getship(myship->s_type);
+
+	    currentship = myship->s_type;
+
+	    /*
+	       sendOptionsPacket(); /* this would totally blast any flags you
+	       had on the server
+	    */
+
+	    redrawall = 1;
+	    enter();
+	    calibrate_stats();
+	    W_ClearWindow(w);
+	    /*
+	       for (i = 0; i < NSIG; i++) { signal(i, SIG_IGN); }
+	    */
+
+	    me->p_status = PALIVE;	/* Put player in game */
+
+#ifdef UNIX_SOUND
+            kill_sound ();
+#endif
+            
+#ifdef HOCKEY
+	    hockeyInit();
+#endif /*HOCKEY*/
+
+#ifdef TIMER
+	    timeBank[T_SHIP] = time(NULL);
+#endif				/* TIMER */
+
+	    if (showStats)	/* Default showstats are on. */
+		W_MapWindow(statwin);
+
+#ifdef GATEWAY
+	    /* pick a nice set of UDP ports */
+	    getUdpPort();
+#endif
+
+#if ATM
+	    if (tryUdp && commMode != COMM_UDP) {
+		sendUdpReq(COMM_UDP);
+	    }
+#endif				/* ATM */
+#ifdef SHORT_PACKETS
+	    if (tryShort) {
+		sendShortReq(SPK_VON);
+		tryShort = 0;	/* only try it once */
+	    }
+#endif	/* SHORT_PACKETS */
+	    /* Send request for a full update */
+	    if (askforUpdate) {
+		if(recv_short)
+		    sendShortReq(SPK_SALL);
+		else
+		    sendUdpReq(COMM_UPDATE);
+	    }
+	    sendUpdatePacket(1000000 / updateSpeed);
+
+	    W_Deiconify(baseWin);
+
+	    break;
+	case PALIVE:
+	case PEXPLODE:
+	case PDEAD:
+	case POBSERVE:
+
+#ifdef TIMELORD
+	    /* reading the MOTD doesn't count against your playing time */
+	    update_timelord_notcount();
+#endif
+
+	    /* Get input until the player quits or dies */
+	    input();
+	    W_ClearWindow(mapw);
+#ifdef TIMELORD
+	    /* get any fractional minutes we missed */
+	    update_timelord(1);
+#endif
+	    break;
+	default:
+	    printf("client has p_status=%d.  how strange\n", me->p_status);
+	    me->p_status = POUTFIT;
+	}
+    }
+
+    /* NOTREACHED */
+}
+
+static void
+printUsage(prog)
+    char   *prog;
+{
+    fprintf(stderr, "Usage:\n  %s [ options ] [ ntserv-host ]\n\
+Where options are\n\
+    [-h] host          server host name\n\
+    [-p] port          server port number\n\
+    [-r] xtrekrc       defaults file to replace ~/.xtrekrc\n\
+    [-t] title         window manager title\n\
+    [-d] display       set Xwindows display\n\
+    [-C] name          netrek pseudonym\n\
+    [-P] passwd        passwd to use to attempt autologin\n\
+    [-R]               use RSA authorization (default)\n\
+    [-o]               use old (non-RSA) authorization\n\
+    [-s] port          wait for connection from ntserv on a port (debugging)\n\
+%s\
+%s\
+    [-U] port          specify base local UDP port number to use\n\
+    [-e]               check the expire time on the client\n\
+    [-f]               how to get the newest client\n\
+    [-u]               print usage\n\
+    [-c]               Paradise credits\n\
+  For emergency restart:\n\
+    [-2]               force paradise - use if you were on a paradise server\n\
+    [-G] playernum     specify player number to use\n\
+    [-s] port          specify socket number to use\n\
+Paradise Client %s\n\
+For more information on how to play Paradise, use Netscape or Internet\n\
+Explorer and connect to:\n\
+    http://www.pnetrek.org/               OR\n\
+    http://www.cs.umn.edu/users/glamm/paradise/\n\n", prog,
+#ifdef METASERVER
+	    "    [-m]               check metaserver for active servers\n",
+#else
+	    "",
+#endif				/* METASERVER */
+#ifdef RECORDER
+	    "    [-F] file          Replay from file instead of connecting\n",
+#else
+	    "",
+#endif
+	    CLIENTVERS);
+}
+
+void
+reaper()
+{
+#if defined(hpux) || defined(SVR4) || defined(AMIGA)
+    wait((int *) 0);
+#else
+    /* well, hell, just use NULL, it works for everything else anyway */
+/*    while (wait3((union wait *) 0, WNOHANG, NULL) > 0);*/
+    while(wait3(NULL, WNOHANG, NULL) > 0);
+#endif				/* hpux */
+}
+
+#ifdef GATEWAY
+static struct udpmap_t {
+    int     uid;
+    int     serv_port;
+    int     port;
+    int     local_port;
+}       udpmap[] = {
+    /* 5000, 5001, 5000 *//* generic */
+    {
+	1290, 5010, 5011, 5010
+    },				/* fadden */
+    {
+	757, 5020, 5021, 5020
+    },				/* user2 */
+};
+#define MAPSIZE (sizeof(udpmap) / sizeof(struct udpmap_t))
+
+static void
+getUdpPort()
+{
+    int     i;
+    uid_t   uid;
+    char   *gw_m, *gw_p, *gw_lp, *gw_sp, *err, *getenv();
+
+    /* should always be set prior, but in case not .. */
+    if (!gw_mach) {
+	gw_m = getenv("GW_MACH");
+	if (gw_m)
+	    gw_mach = gw_m;
+	else
+	    gw_mach = DEFAULT_GATEWAY;
+    }
+    uid = getuid();
+
+    for (i = 0; i < MAPSIZE; i++) {
+	if (uid == udpmap[i].uid) {
+	    gw_serv_port = udpmap[i].serv_port;
+	    gw_port = udpmap[i].port;
+	    gw_local_port = udpmap[i].local_port;
+	    return;
+	}
+    }
+
+    gw_p = getenv("GW_PORT");
+    gw_sp = getenv("GW_SPORT");
+    gw_lp = getenv("GW_LPORT");
+
+    if (gw_p) {
+	gw_port = strtol(gw_p, &err, 10);
+	if (err == gw_p) {
+	    fprintf(stderr, "netrek: malformed integer for GW_PORT: %s\n",
+		    gw_p);
+	    /* let something else complain about port 0 */
+	}
+    } else
+	gw_port = 5001;
+    if (gw_sp) {
+	gw_serv_port = strtol(gw_sp, &err, 10);
+	if (err == gw_sp) {
+	    fprintf(stderr, "netrek: malformed integer for GW_SPORT: %s\n",
+		    gw_sp);
+	    /* let something else complain about port 0 */
+	}
+    } else
+	gw_serv_port = 5000;
+
+    if (gw_lp) {
+	gw_local_port = strtol(gw_lp, &err, 10);
+	if (err == gw_lp) {
+	    fprintf(stderr, "netrek: malformed integer for GW_LPORT: %s\n",
+		    gw_lp);
+	    /* let something else complain about port 0 */
+	}
+    } else
+	gw_local_port = 5000;
+
+    /*
+       printf("gw_mach: \'%s\'\n", gw_mach); printf("gw_local_port: %d\n",
+       gw_local_port); printf("gw_serv_port: %d\n", gw_serv_port);
+       printf("gw_port: %d\n", gw_port);
+    */
+}
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+/*
+ * In the event of problems assiocated with the above include files the
+ * following routine can be alternately used to convert a string
+ * ("xxx.xxx.xxx.xxx") to an internet address number.
+ *
+ * (author: Andy McFadden)
+ */
+
+#ifdef notneeded
+unsigned long
+dotAddrToNetAddr(str)
+    char   *str;
+{
+    char   *t;
+    unsigned long answer = 0;
+    t = str;
+    for (i = 0; i < 4; i++) {
+	answer = (answer << 8) | atoi(t);
+	while (*t && *t != '.')
+	    t++;
+	if (*t)
+	    t++;
+    }
+    return answer;
+}
+#endif
+
+/*
+ * More network "correct" routine
+ */
+
+static unsigned long
+mkaddr(m)
+    char   *m;
+{
+    struct in_addr ad;
+    struct hostent *hp;
+
+    hp = gethostbyname(m);
+    if (!hp) {
+	ad.s_addr = inet_addr(m);
+	if (ad.s_addr == -1) {
+	    fprintf(stderr, "netrek: unknown host \'%s\'\n", m);
+	    exit(1);
+	}
+    } else
+	bcopy(hp->h_addr, (char *) &ad, hp->h_length);
+
+    return ad.s_addr;
+}
+
+static char *
+get_gw()
+{
+    char   *gw_m;
+
+    gw_m = getenv("GW_MACH");
+    if (gw_m)
+	gw_mach = gw_m;
+    else
+	gw_mach = DEFAULT_GATEWAY;
+
+    return gw_mach;
+}
+
+#endif
+
+void
+show_credits()
+{
+	printf ("Paradise Netrek\n\
+\n\
+Copyright (c) 1986	Chris Guthrie\n\
+Copyright (c) 1989	Kevin P. Smith\n\
+Copyright (c) 1993	Larry Denys, Kurt Olsen, Brandon Gillespie, and\n\
+			Robert Forsman\n\
+Copyright (c)		Eric Mehlaff, Sujal Patel, Robert Glamm, \n\
+			Lars Bernhardsson, Kurt Siegl, Nick Trown\n\
+\n\
+Paradise Developers\n\
+  Larry Deny                       Robert Forsman\n\
+  Brandon Gillespie                Kurt Olsen\n\
+\n\
+Paradise Contributors (In alphabetical order):\n\
+  Terence Chang                    Mike McGrath\n\
+  Bill Dyess                       Matthew Mead\n\
+  Jerry Frain                      Gary Parnes\n\
+  Robert Glamm                     Sujal Patel\n\
+  T. Hadley                        Joe Rumsey\n\
+  Heath A. Kehoe                   Rado Smiljanic\n\
+  Andy McFadden                    Joe Young\n\
+");
+}