[comp.sources.games] v10i002: gb3 - Galactic Bloodshed, an empire-like war game [Ver. 2.0], Part02/14

billr@saab.CNA.TEK.COM (Bill Randle) (06/02/90)

Submitted-by: VANCLEEF@mps.ohio-state.edu
Posting-number: Volume 10, Issue 2
Archive-name: gb3/Part02
Supersedes: GB2: Volume 7, Issue 44-51



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 2 (of 14)."
# Contents:  Docs/zoom.doc server/GB_server.c server/doship.c
# Wrapped by billr@saab on Fri Jun  1 11:53:31 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Docs/zoom.doc' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Docs/zoom.doc'\"
else
echo shar: Extracting \"'Docs/zoom.doc'\" \(1194 characters\)
sed "s/^X//" >'Docs/zoom.doc' <<'END_OF_FILE'
XZOOM			Galactic Bloodshed		ZOOM
X
X
XNAME
X  [0] zoom -- declare zoom values
X 
XSYNTAX
X      zoom (amount) <x,y>
X
XDESCRIPTION
X
X  This command allows users to alter the scale used in an orbit display.
XThe lower the number, the larger the display will be.
X
X  ``Amount'' can be specified in one of two ways: a floating-point format,
Xin which case the amount will be the amount given, or an i/j format, in
Xwhich case the amount will be the numerator (i) divided by the denominator (j).
X
X  The optional argument changes the ``lastx,lasty'' coordinates to the specified
Xcoordinates, in case the player desires a closeup of an area he has not explored
Xyet.
X
X  At a zoom scale of 1.0, the display will be equal to the screen size.  At
Xa scale of greater than 1.0, the display will be smaller than the screen;
Xsmaller than 1.0, and the screen will zoom in to the displayed map.
X
X  Display is centered around the current ``lastx,lasty'' coordinates (see
Xorbit).
X
X  At game start, the zoom value is declared as 1.0.
X
X   There are two zoom factors, one for 'star' level, and one for 'universe' level. You can
Xspecify the 'lastx, lasty' for the universe level with the 'center <star>' command.
X
XSEE ALSO
X  orbit
END_OF_FILE
if test 1194 -ne `wc -c <'Docs/zoom.doc'`; then
    echo shar: \"'Docs/zoom.doc'\" unpacked with wrong size!
fi
# end of 'Docs/zoom.doc'
fi
if test -f 'server/GB_server.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server/GB_server.c'\"
else
echo shar: Extracting \"'server/GB_server.c'\" \(33670 characters\)
sed "s/^X//" >'server/GB_server.c' <<'END_OF_FILE'
X/*
X * Galactic Bloodshed, copyright (c) 1989 1990 by Robert P. Chansky, 
X * smq@ucscb.ucsc.edu, Univ of Ca Santa Cruz.
X *  You may copy, alter and distribute this game as you please as
X *    long as these notices remain intact.  No duplication for
X *    commercial purposes without permission of the author.
X *
X * Version 1.1 mods by:
X *		Garrett Van Cleef, Ph.D
X *		   Dept. of Physics
X *		 Ohio State University
X * V1.1 playtesting by:
X *		     Hanan Baddar
X *		      Ken Bloch
X *		     John Davis
X *		     Robert Jones
X *		 Menelaos Kafkaladis
X *		     Brett Lowry
X *		     Paul Murphy
X *		  Garrett van Cleef
X *		   Wolfgang Wenzel
X *                       and
X *		   tons of people
X *	  	  at U.C. Santa Cruz
X *
X *
X *	GB_server.c --
X *	  main loop
X */
X
X#include "TinyMUD_copyright.h" 
X/* Copyright for the original TinyMUD interface which was used for the networking */
X
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/file.h>
X#include <sys/time.h>
X#include <signal.h>
X#include <sys/ioctl.h>
X#include <sys/wait.h>
X#include <fcntl.h>
X#include <sys/errno.h>
X#include <ctype.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X#include <netdb.h>
X
X/*#include <time.h>	/* included by <sys/time.h> with bsd */
X#include <sys/timeb.h>
X
X#include <curses.h>
X#include <sys/stat.h>
Xstruct stat sbuf;
X#include <signal.h>
X#include <strings.h>
X#include <pwd.h>
Xstruct passwd *passwd;
Xint i;
X
X/* GB headers */
X#define EXTERN
X#include "vars.h"
X#include "ships.h"
X#include "races.h"
X#include "power.h"
X#include "doturn.h"
X
X#include "config.h"
X#include "interface.h"
X#include "buffers.h"
X
X/* For BSD 4.2 systems. */
X#ifndef FD_ZERO
X#define OLD_BSD_FDSETS
X#include "ultrix_cpt.h"
X#endif
X
Xextern int	errno;
Xint	shutdown_flag = 0;
X
Xstruct tm *update_tm; /* keeps track of the last update */
Xstruct tm *current_tm;/* for watching for next update */
Xlong clk;
Xchar start_buf[128];
Xchar update_buf[128];
X
Xstatic const char *connect_fail = "Connection refused.\n";
Xstatic const char *create_fail = "Connection refused.\n";
Xstatic const char *flushed_message = "<Output Flushed>\n";
Xstatic const char *shutdown_message = "Shutdown ordered by deity - Bye\n";
Xstatic const char *already_on = "Connection refused.\n";
X
Xint errno;
X
Xstruct text_block {
X	int			nchars;
X	struct text_block	*nxt;
X	char			*start;
X	char			*buf;
X};
X
Xstruct text_queue {
X    struct text_block *head;
X    struct text_block **tail;
X};
X
Xstruct descriptor_data {
X         int descriptor;
X	int connected;
X	int Playernum;
X	char *output_prefix;
X	char *output_suffix;
X	int output_size;
X	struct text_queue output;
X	struct text_queue input;
X	char *raw_input;
X	char *raw_input_at;
X	long last_time;
X	int quota;
X	struct descriptor_data *next;
X	struct descriptor_data **prev;
X} *descriptor_list = 0;
X
Xstatic int sock;
Xstatic int ndescriptors = 0;
X
Xvoid panic();
Xvoid process_commands();
Xvoid shovechars();
Xvoid shutdownsock();
Xstruct descriptor_data *initializesock();
Xvoid make_nonblocking();
Xvoid freeqs();
Xvoid welcome_user();
Xvoid check_connect();
Xvoid close_sockets();
Xconst char *addrout ();
Xvoid dump_users();
Xvoid set_signals();
Xstruct descriptor_data *new_connection();
Xvoid parse_connect ();
Xvoid set_userstring ();
Xint do_command ();
Xchar *strsave ();
Xint make_socket();
Xint queue_string();
Xint queue_write();
Xint process_output();
Xint process_input();
Xint bailout();
Xstruct timeval update_quotas();
X
X#define MALLOC(result, type, number) do {			\
X	if (!((result) = (type *) malloc ((number) * sizeof (type))))	\
X		panic("Out of memory");				\
X	} while (0)
X
X#define FREE(x) (free(x))
X
Xchar *Desnames[] = {
X	"ocean",
X	"land",
X	"mountainous",
X	"gaseous",
X	"ice",
X	"plated",
X	"error in des type!",	/* (illegal values) */
X	"err in des type!"
X};
X
Xint server_racedata;
X#ifdef BSD4_2
Xint min_west;
Xextern char *timezone();
X#endif
X
Xvoid main(argc, argv)
Xint argc;
Xchar **argv;
X{
Xint maim_stardata, s; 
Xint i, j, dummy;
X#ifdef BSD4_2
Xchar zone[16];
Xstruct timeval tp;
Xstruct timezone tzp;
X#endif
X
X    /* go do it */
Xclk = time(0);
Xcurrent_tm = localtime(&clk);
X#ifdef BSD4_2
X/* all this because BSD 4.2 derived systems don't have
X * tm_zone in the tm struct
X */
Xgettimeofday(&tp, &tzp);
Xmin_west = tzp.tz_minuteswest;
Xstrcpy(zone, timezone(min_west, current_tm->tm_isdst));
X#else
Xstrcpy(zone, current_tm->tm_zone);
X#endif
X
Xsprintf(start_buf, "Server started: %2d/%2d/%d %02d:%02d:%02d %s\n",
X    current_tm->tm_mon+1, current_tm->tm_mday,
X	current_tm->tm_year, current_tm->tm_hour, current_tm->tm_min,
X    current_tm->tm_sec, zone);
X
X	srandom(getpid());
X	printf("***   Galactic Bloodshed ver %s ***\n\n", VERS);
X        printf("      The update password is '%s'.\n", DAEMON_PASSWORD);
X/* compute powers of 2 for bit operations */
X	Two[0]=1;
X	for(i=1;i<32;i++)
X		Two[i]=2*Two[i-1];
X
X	reload_star_data_base(); /* get star data */
X	Getpower(Power); /* get power report from disk */
X	Getblock(Blocks); /* get alliance block data */
Xfor(i=1; i<=MAXPLAYERS; i++) {
X	setbit(Blocks[i-1].invite, i);
X	setbit(Blocks[i-1].pledge, i);
X	}
X	Putblock(Blocks);
X
XNum_races = Numraces();
X/* compute alliance block power */
Xsprintf(Power_blocks.time, "%2d/%2d/%d %02d:%02d:%02d %s", 
X	current_tm->tm_mon+1, current_tm->tm_mday,
X	current_tm->tm_year, current_tm->tm_hour,
X	current_tm->tm_min, current_tm->tm_sec, zone);
X for (i=1; i<=Num_races; i++) {
X	dummy=(Blocks[i-1].invite & Blocks[i-1].pledge);
X				Power_blocks.members[i-1] = 0;
X				Power_blocks.sectors_owned[i-1] = 0;
X				Power_blocks.popn[i-1] = 0;
X				Power_blocks.ships_owned[i-1] = 0;
X				Power_blocks.planets_owned[i-1] = 0;
X				Power_blocks.resource[i-1] = 0;
X				Power_blocks.fuel[i-1] = 0;
X				Power_blocks.destruct[i-1] = 0;
X				Power_blocks.VPs[i-1] = 0;
X	for(j=1; j<=Num_races; j++) 
X			if(isset(dummy, j)){
X				Power_blocks.members[i-1] += 1;
X				Power_blocks.sectors_owned[i-1] += Power[j-1].sectors_owned;
X				Power_blocks.popn[i-1] += Power[j-1].popn;
X				Power_blocks.ships_owned[i-1] += Power[j-1].ships_owned;
X				Power_blocks.planets_owned[i-1] += Power[j-1].planets_owned;
X				Power_blocks.resource[i-1] += Power[j-1].resource;
X				Power_blocks.fuel[i-1] += Power[j-1].fuel;
X				Power_blocks.destruct[i-1] += Power[j-1].destruct;
X				Power_blocks.VPs[i-1] += Blocks[j-1].VPs;
X			}
X	}
X
X
X
X    shovechars (argc==1 ? GB_PORT : atoi (argv[1]) );
X    close_sockets ();
Xprintf("Going down.\n");
X    exit (0);
X}
X
X
Xint notify(Playernum, msg)
Xint Playernum;
Xchar *msg;
X{
X    struct descriptor_data *d;
X
X    for (d = descriptor_list; d; d = d->next) {
X	if (d->connected && d->Playernum == Playernum) {
X	    queue_string (d, msg);
X	return(1);
X	}
X    }
Xreturn(0);
X}
X
Xstruct timeval timeval_sub(now, then)
Xstruct timeval now;
Xstruct timeval then;
X{
X    now.tv_sec -= then.tv_sec;
X    now.tv_usec -= then.tv_usec;
X    if (now.tv_usec < 0) {
X	now.tv_usec += 1000000;
X	now.tv_sec--;
X    }
X    return now;
X}
X
Xint msec_diff(now,  then)
Xstruct timeval now;
Xstruct timeval then;
X{
X    return ((now.tv_sec - then.tv_sec) * 1000
X	    + (now.tv_usec - then.tv_usec) / 1000);
X}
X
Xstruct timeval msec_add(t, x)
Xstruct timeval t;
Xint x;
X{
X    t.tv_sec += x / 1000;
X    t.tv_usec += (x % 1000) * 1000;
X    if (t.tv_usec >= 1000000) {
X	t.tv_sec += t.tv_usec / 1000000;
X	t.tv_usec = t.tv_usec % 1000000;
X    }
X    return t;
X}
X
Xvoid shovechars(port)
Xint port;
X{
X    fd_set input_set, output_set;
X    long now;
X    struct timeval last_slice, current_time;
X    struct timeval next_slice;
X    struct timeval timeout, slice_timeout;
X    int maxd;
X    struct descriptor_data *d, *dnext;
X    struct descriptor_data *newd;
X    int avail_descriptors;
X
X    sock = make_socket (port);
X    maxd = sock+1;
X    gettimeofday(&last_slice, (struct timezone *) 0);
X
X    avail_descriptors = getdtablesize() - 4;
X    
X    while (shutdown_flag == 0) {
X	gettimeofday(&current_time, (struct timezone *) 0);
X	last_slice = update_quotas(last_slice, current_time);
X
X	process_commands();
X
X	if (shutdown_flag)
X	    break;
X	timeout.tv_sec = 1000;
X	timeout.tv_usec = 0;
X	next_slice = msec_add (last_slice, COMMAND_TIME_MSEC);
X	slice_timeout = timeval_sub (next_slice, current_time);
X	
X	FD_ZERO (&input_set);
X	FD_ZERO (&output_set);
X	if (ndescriptors < avail_descriptors)
X	    FD_SET (sock, &input_set);
X	for (d = descriptor_list; d; d=d->next) {
X	    if (d->input.head)
X		timeout = slice_timeout;
X	    else
X		FD_SET (d->descriptor, &input_set);
X	    if (d->output.head)
X		FD_SET (d->descriptor, &output_set);
X	}
X
X	if (select (maxd, &input_set, &output_set,
X		    (fd_set *) 0, &timeout) < 0) {
X	    if (errno != EINTR) {
X		perror ("select");
X		return;
X	    }
X	} else {
X	    (void) time (&now);
X	    if (FD_ISSET (sock, &input_set)) {
X		if (!(newd = new_connection (sock))) {
X		    if (errno != EINTR && errno != EMFILE) {
X			perror ("new_connection");
X			return;
X		    }
X		} else {
X		if (newd->descriptor >= maxd)
X		    maxd = newd->descriptor + 1;
X		}
X	    }
X	    for (d = descriptor_list; d; d = dnext) {
X		dnext = d->next;
X		if (FD_ISSET (d->descriptor, &input_set)) {
X			d->last_time = now;
X			if (!process_input (d)) {
X			    shutdownsock (d);
X			    continue;
X			}
X		}
X		if (FD_ISSET (d->descriptor, &output_set)) {
X		    if (!process_output (d)) {
X			shutdownsock (d);
X		    }
X		}
X	    }
X	}
X    }
X}
X
Xint make_socket(port)
Xint port;
X{
X    int s;
X    struct sockaddr_in server;
X    int opt;
X
X    s = socket (AF_INET, SOCK_STREAM, 0);
X    if (s < 0) {
X	perror ("creating stream socket");
X	exit (3);
X    }
X    opt = 1;
X    if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR,
X		    (char *) &opt, sizeof (opt)) < 0) {
X	perror ("setsockopt");
X	exit (1);
X    }
X    server.sin_family = AF_INET;
X    server.sin_addr.s_addr = INADDR_ANY;
X    server.sin_port = htons (port);
X    if (bind (s, (struct sockaddr *) & server, sizeof (server))) {
X	perror ("binding stream socket");
X	close (s);
X	exit (4);
X    }
X    listen (s, 5);
X    return s;
X}
X
Xstruct timeval update_quotas(last, current)
Xstruct timeval last;
Xstruct timeval current;
X{
X    int nslices;
X    struct descriptor_data *d;
X
X    nslices = msec_diff (current, last) / COMMAND_TIME_MSEC;
X
X    if (nslices > 0) {
X	for (d = descriptor_list; d; d = d -> next) {
X	    d -> quota += COMMANDS_PER_TIME * nslices;
X	    if (d -> quota > COMMAND_BURST_SIZE)
X		d -> quota = COMMAND_BURST_SIZE;
X	}
X    }
X    return msec_add (last, nslices * COMMAND_TIME_MSEC);
X}
X
Xstruct descriptor_data *new_connection(sock)
Xint sock;
X{
X    int newsock;
X    struct sockaddr_in addr;
X    int addr_len;
X
X    addr_len = sizeof (addr);
X    newsock = accept (sock, (struct sockaddr *) & addr, &addr_len);
X    if (newsock <= 0) {
X	return 0;
X    } else {
X	fprintf (stderr, "ACCEPT from %s(%d) on descriptor %d\n", addrout (ntohl (addr.sin_addr.s_addr)), ntohs (addr.sin_port), newsock);
X	return initializesock (newsock);
X    }
X}
X
Xconst char *addrout(a)
Xlong a;
X{
X    static char outbuf[1024];
X
X    sprintf (outbuf, "%d.%d.%d.%d", (a >> 24) & 0xff, (a >> 16) & 0xff,
X	     (a >> 8) & 0xff, a & 0xff);
X    return outbuf;
X}
X
Xvoid clearstrings(d)
Xstruct descriptor_data *d;
X{
X    if (d->output_prefix) {
X	free(d->output_prefix);
X	d->output_prefix = 0;
X    }
X    if (d->output_suffix) {
X	free(d->output_suffix);
X	d->output_suffix = 0;
X    }
X}
X
Xvoid shutdownsock(d)
Xstruct descriptor_data *d;
X{
X    if (d->connected) {
X	fprintf (stderr, "DISCONNECT descriptor %d Playernum(%d)\n",
X		d->descriptor, d->Playernum);
X    } else {
X	fprintf (stderr, "DISCONNECT descriptor %d never connected\n",
X		d->descriptor);
X    }
X    clearstrings (d);
X    shutdown (d->descriptor, 2);
X    close (d->descriptor);
X    freeqs (d);
X    *d->prev = d->next;
X    if (d->next)
X        d->next->prev = d->prev;
X    free(d);
X    ndescriptors--;
X}
X
Xstruct descriptor_data *initializesock(s)
Xint s;
X{
X    struct descriptor_data *d;
X
X    ndescriptors++;
X    MALLOC(d, struct descriptor_data, 1);
X    d->descriptor = s;
X    d->connected = 0;
X    make_nonblocking (s);
X    d->output_prefix = 0;
X    d->output_suffix = 0;
X    d->output_size = 0;
X    d->output.head = 0;
X    d->output.tail = &d->output.head;
X    d->input.head = 0;
X    d->input.tail = &d->input.head;
X    d->raw_input = 0;
X    d->raw_input_at = 0;
X    d->quota = COMMAND_BURST_SIZE;
X    d->last_time = 0;
X    if (descriptor_list)
X        descriptor_list->prev = &d->next;
X    d->next = descriptor_list;
X    d->prev = &descriptor_list;
X    descriptor_list = d;
X    
X    welcome_user (d);
X    return d;
X}
X
Xstruct text_block *make_text_block(s, n)
Xconst char *s;
Xint n;
X{
X	struct text_block *p;
X
X	MALLOC(p, struct text_block, 1);
X	MALLOC(p->buf, char, n);
X	bcopy (s, p->buf, n);
X	p->nchars = n;
X	p->start = p->buf;
X	p->nxt = 0;
X	return p;
X}
X
Xvoid free_text_block (t)
Xstruct text_block *t;
X{
X		free(t->buf);
X		free((char *) t);
X}
X
Xvoid add_to_queue(q, b, n)
Xstruct text_queue *q;
Xconst char *b;
Xint n;
X{
X    struct text_block *p;
X
X    if (n == 0) return;
X
X    p = make_text_block (b, n);
X    p->nxt = 0;
X    *q->tail = p;
X    q->tail = &p->nxt;
X}
X
Xint flush_queue(q, n)
Xstruct text_queue *q;
Xint n;
X{
X        struct text_block *p;
X	int really_flushed = 0;
X	
X	n += strlen(flushed_message);
X
X	while (n > 0 && (p = q->head)) {
X	    n -= p->nchars;
X	    really_flushed += p->nchars;
X	    q->head = p->nxt;
X	    free_text_block (p);
X	}
X	p = make_text_block(flushed_message, strlen(flushed_message));
X	p->nxt = q->head;
X	q->head = p;
X	if (!p->nxt)
X	    q->tail = &p->nxt;
X	really_flushed -= p->nchars;
X	return really_flushed;
X}
X
Xint queue_write(d, b, n)
Xstruct descriptor_data *d;
Xconst char *b;
Xint n;
X{
X    int space;
X
X    space = MAX_OUTPUT - d->output_size - n;
X    if (space < 0)
X        d->output_size -= flush_queue(&d->output, -space);
X    add_to_queue (&d->output, b, n);
X    d->output_size += n;
X    return n;
X}
X
Xint queue_string(d, s)
Xstruct descriptor_data *d;
Xconst char *s;
X{
X    return queue_write (d, s, strlen (s));
X}
X
Xint process_output(d)
Xstruct descriptor_data *d;
X{
X    struct text_block **qp, *cur;
X    int cnt;
X
X    for (qp = &d->output.head; cur = *qp;) {
X	cnt = write (d->descriptor, cur -> start, cur -> nchars);
X	if (cnt < 0) {
X	    if (errno == EWOULDBLOCK)
X		return 1;
X	    return 0;
X	}
X	d->output_size -= cnt;
X	if (cnt == cur -> nchars) {
X	    if (!cur -> nxt)
X		d->output.tail = qp;
X	    *qp = cur -> nxt;
X	    free_text_block (cur);
X	    continue;		/* do not adv ptr */
X	}
X	cur -> nchars -= cnt;
X	cur -> start += cnt;
X	break;
X    }
X    return 1;
X}
X
Xvoid make_nonblocking(s)
Xint s;
X{
X    if (fcntl (s, F_SETFL, FNDELAY) == -1) {
X	perror ("make_nonblocking: fcntl");
X	panic ("FNDELAY fcntl failed");
X    }
X}
X
Xvoid freeqs(d)
Xstruct descriptor_data *d;
X{
X    struct text_block *cur, *next;
X
X    cur = d->output.head;
X    while (cur) {
X	next = cur -> nxt;
X	free_text_block (cur);
X	cur = next;
X    }
X    d->output.head = 0;
X    d->output.tail = &d->output.head;
X
X    cur = d->input.head;
X    while (cur) {
X	next = cur -> nxt;
X	free_text_block (cur);
X	cur = next;
X    }
X    d->input.head = 0;
X    d->input.tail = &d->input.head;
X
X    if (d->raw_input)
X        free(d->raw_input);
X    d->raw_input = 0;
X    d->raw_input_at = 0;
X}
X
Xvoid welcome_user(d)
Xstruct descriptor_data *d;
X{
X    FILE *f;
X    char buf[BUFFER_LEN];
X    char *p;
X    
X	sprintf(buf, "***   Welcome to Galactic Bloodshed ver %s ***\n", VERS);
X	queue_string(d, buf);
X
X    if((f = fopen(WELCOME_FILE, "r")) != NULL) {
X	while(fgets(buf, sizeof buf, f)) {
X	    for(p = buf; *p; p++) if(*p == '\n') {
X		*p = '\0';
X		break;
X	    }
X	    queue_string(d, buf);
X	    queue_string(d, "\n");
X	}
X	fclose(f);
X    }
X
X/*    if((f = fopen(NEWS_FILE, "r")) != NULL) {
X	while(fgets(buf, sizeof buf, f)) {
X	    for(p = buf; *p; p++) if(*p == '\n') {
X		*p = '\0';
X		break;
X	    }
X	    queue_string(d, buf);
X	    queue_string(d, "\n");
X	}
X	fclose(f);
X    } */
X
X}
X
Xvoid goodbye_user(d)
Xstruct descriptor_data *d;
X{
X    write (d->descriptor, LEAVE_MESSAGE, strlen (LEAVE_MESSAGE));
X}
X
Xchar *strsave (s)
Xconst char *s;
X{
X    char *p;
X
X    MALLOC (p, char, strlen(s) + 1);
X
X    if (p)
X	strcpy (p, s);
X    return p;
X}
X
Xvoid save_command (d, command)
Xstruct descriptor_data *d;
Xconst char *command;
X
X{
X    add_to_queue (&d->input, command, strlen(command)+1);
X}
X
Xint process_input (d)
Xstruct descriptor_data *d;
X{
X    int got;
X    char *p, *pend, *q, *qend;
X
X    got = read (d->descriptor, buf, sizeof buf);
X    if (got <= 0)
X	return 0;
X    if (!d->raw_input) {
X	MALLOC(d->raw_input,char,MAX_COMMAND_LEN);
X	d->raw_input_at = d->raw_input;
X    }
X    p = d->raw_input_at;
X    pend = d->raw_input + MAX_COMMAND_LEN - 1;
X    for (q=buf, qend = buf + got; q < qend; q++) {
X	if (*q == '\n') {
X	    *p = '\0';
X	    if (p > d->raw_input)
X		save_command (d, d->raw_input);
X	    p = d->raw_input;
X	} else if (p < pend && isascii (*q) && isprint (*q)) {
X	    *p++ = *q;
X	}
X    }
X    if (p > d->raw_input) {
X	d->raw_input_at = p;
X    } else {
X	free(d->raw_input);
X	d->raw_input = 0;
X	d->raw_input_at = 0;
X    }
X    return 1;
X}
X
Xvoid set_userstring (userstring, command)
Xchar **userstring;
Xconst char *command;
X{
X    if (*userstring) {
X	free(*userstring);
X	*userstring = 0;
X    }
X    while (*command && isascii (*command) && isspace (*command))
X	command++;
X    if (*command)
X	*userstring = strsave (command);
X}
X
X#ifdef __STDC__
Xvoid process_commands(void)
X#else
Xvoid process_commands()
X#endif
X{
X    int nprocessed;
X    struct descriptor_data *d, *dnext;
X    struct text_block *t;
X
X    do {
X	nprocessed = 0;
X	for (d = descriptor_list; d; d = dnext) {
X	    dnext = d->next;
X	    if (d -> quota > 0 && (t = d -> input.head)) {
X		d -> quota--;
X		nprocessed++;
X
X		if (!do_command (d, t -> start)) {
X		    shutdownsock (d);
X		} else {
X		    d -> input.head = t -> nxt;
X		    if (!d -> input.head)
X			d -> input.tail = &d -> input.head;
X		    free_text_block (t);
X		}
X
X	    }
X	}
X    } while (nprocessed > 0);
X
X}
X
Xint do_command (d, command)
Xstruct descriptor_data *d;
Xchar *command;
X{
Xracetype *r;
Xchar *string;
Xint parse_exit=0, argn=0, i;
Xchar args[MAXARGS][COMMANDSIZE];
X
X/* Main processing loop. When command strings are sent from the client,
X	they are processed here. Responses are sent back to the client via notify.
X	The client will then process the strings in whatever manner is expected. */
X
X/* check to see if there are a few words typed out, usually for the help command */
X	string=command;
X	while (!parse_exit) {
X	    i=0;
X	    while ( !isspace(*string) && (*string!='\0') && (i<COMMANDSIZE) )
X		args[argn][i++]=(*string++);
X	    args[argn][i]='\0';
X	    /*printf("arg %d |%s|\n",argn,args[argn]);*/
X	    while ((*string)==' ') string++;
X	    if ( (*string=='\0') || (argn>=MAXARGS)) parse_exit=1;
X	    argn++;
X	}
X	for (i=argn; i<MAXARGS; i++)
X		args[i][0]='\0';
X
X   if (!strcmp (args[0], QUIT_COMMAND)) {
X	if(d->connected) {
X
X	openracedata(&server_racedata);
X		  getrace(server_racedata, &r, d->Playernum);
X	close_file(server_racedata);
X
X     	sprintf(buf, "%s (%d) logged out.\n", r->name, d->Playernum);
X   	 for(i=1; i<=Numraces(); i++)
X		if(!Dir[i-1].gag)
X              		notify(i, buf);
X			}
X	goodbye_user (d);
X	return 0;
X    } else if (!strcmp (args[0], WHO_COMMAND)) {
X	dump_users (d);
X    } else if (!strcmp (args[0], HELP_COMMAND)) { 
X	help(d, argn, args);
X    } else {
X	if (d->connected) {
X	    process_command (d->Playernum, command);  /* GB command parser */
X	} else {
X	    check_connect (d, command); /* Logs player into the game, connects
X								if the password given by *command is a player's */
X	    if(!d->connected) {
X			goodbye_user(d);
X		    } 
X		else {
X	    check_for_telegrams(d->Playernum);
X		process_command (d->Playernum, "cs");  /* set the scope to home upon login */
X			}	
X	}
X    }
X    return 1;
X}
X
Xvoid check_connect (d, msg)
Xstruct descriptor_data *d;
Xconst char *msg;
X{
X    char password[MAX_COMMAND_LEN];
X    reg int i;
X    int Playernum, Num_races;
X    racetype *r;
X    struct descriptor_data *d0, *dnext;
X#ifdef BSD4_2
X    char zone[16];
X#endif
X
X    parse_connect (msg,  password);
X
XNum_races = Numraces();
X/* daemon wants an update */
Xif(!strcmp(password, DAEMON_PASSWORD)) { 
X
Xfor (i=1; i<=Num_races; i++)
X	notify(i, "DOING UPDATE...\n");
X
X
X    clk = time(0);
X    update_tm=localtime(&clk);
X#ifdef BSD4_2
X    strcpy(zone, timezone(min_west, update_tm->tm_isdst));
X#else
X    strcpy(zone, update_tm->tm_zone);
X#endif
Xsprintf(Power_blocks.time, "%2d/%2d/%d %02d:%02d:%02d %s", 
X	update_tm->tm_mon+1, update_tm->tm_mday,
X	update_tm->tm_year, update_tm->tm_hour,
X	update_tm->tm_min, update_tm->tm_sec, zone);
Xsprintf(update_buf, "Last update   : %2d/%2d/%d %02d:%02d:%02d %s\n",
X	update_tm->tm_mon+1, update_tm->tm_mday,
X	update_tm->tm_year, update_tm->tm_hour,
X	update_tm->tm_min, update_tm->tm_sec, zone);
X    do_turn();
X	return;
X	}
X
X
X    i = Getracenum(password);
X
X	if (!i) {
X	    queue_string (d, connect_fail);
X	    fprintf (stderr, "FAILED CONNECT %s on descriptor %d\n",
X		     password, d->descriptor);
X	} else {
X
X	openracedata(&server_racedata);
X		  getrace(server_racedata, &r, i);
X	close_file(server_racedata);
X
X		  Playernum = r->Playernum;
X
X/* check to see if this player is already connect, if so, nuke the descriptor */
X	for (d0 = descriptor_list; d0; d0 = dnext) {
X	    dnext = d0->next;	
X		if(d0->connected && d0->Playernum == Playernum) {
X			queue_string (d, already_on);
X			return;
X		}
X	}
X
X	    fprintf (stderr, "CONNECTED %s(%d) on descriptor %d\n",
X		     r->name, Playernum, d->descriptor);
X	    d->connected = 1;
X	    d->Playernum = Playernum;
X
X		sprintf(buf,"\nLogged in as %s (%d).\n",r->name,Playernum);
X		notify(Playernum, buf);
X     
X		sprintf(buf, "%s (%d) logged on.\n", r->name, Playernum);
X		for(i=1; i<=Numraces(); i++)
X	          	if(i != Playernum && !Dir[i-1].gag) notify(i, buf);
X
X	GB_time(Playernum);
X	if (r->Gov_ship==0) {
X		sprintf(buf,"You have no Governmental Center.  No action points will be produced\nuntil you build one and designate a capital.\n");
X		notify(Playernum, buf);
X		} else {
X		sprintf(buf,"Government Center #%d is active.\n", r->Gov_ship);
X		notify(Playernum, buf);
X		}
X	}
X}
X
Xvoid parse_connect (msg, pass)
Xconst char *msg;
Xchar *pass;
X{
X    char *p;
X
X    while (*msg && isascii(*msg) && isspace (*msg))
X	msg++;
X    p = pass;
X    while (*msg && isascii(*msg) && !isspace (*msg))
X	*p++ = *msg++;
X    *p = '\0';
X}
X
X#ifdef __STDC__
Xvoid close_sockets(void)
X#else
Xvoid close_sockets()
X#endif
X{
X    struct descriptor_data *d, *dnext;
X
X    for (d = descriptor_list; d; d = dnext) {
X	dnext = d->next;
X	write (d->descriptor, shutdown_message, strlen (shutdown_message));
X	if (shutdown (d->descriptor, 2) < 0)
X	    perror ("shutdown");
X	close (d->descriptor);
X    }
X    close (sock);
X}
X
X#ifdef __STDC__
Xvoid emergency_shutdown(void)
X#else
Xvoid emergency_shutdown()
X#endif
X{
X	close_sockets();
X}
X
X#ifdef __STDC__
Xint bailout(int sig, int code, struct sigcontext *scp)
X#else
Xint bailout(sig, code, scp)
Xint sig, code;
Xstruct sigcontext *scp;
X#endif
X{
X    char message[1024];
X    
X    sprintf (message, "BAILOUT: caught signal %d code %d", sig, code);
X    panic(message);
X    _exit (7);
X    return 0;
X}
X
X#ifdef __STDC__
Xint dump_status(void)
X#else
Xint dump_status()
X#endif
X{
X    struct descriptor_data *d;
X    long now;
X    racetype *r;
X
X    (void) time (&now);
X    fprintf (stderr, "STATUS REPORT:\n");
Xopenracedata(&server_racedata);
X    for (d = descriptor_list; d; d = d->next) {
X	if (d->connected) {
X	    getrace(server_racedata, &r, d->Playernum);
X	    fprintf (stderr, "PLAYING descriptor %d Playernum %s(%d)",
X		     d->descriptor, r->name, d->Playernum);
X
X	    if (d->last_time)
X		fprintf (stderr, " idle %d seconds\n",
X			 now - d->last_time);
X	    else
X		fprintf (stderr, " never used\n");
X	} else {
X	    fprintf (stderr, "CONNECTING descriptor %d", d->descriptor);
X	    if (d->last_time)
X		fprintf (stderr, " idle %d seconds\n",
X			 now - d->last_time);
X	    else
X		fprintf (stderr, " never used\n");
X	}
X    }
Xclose_file(server_racedata); 
X   return 0;
X}
X
Xvoid dump_users(e)
Xstruct descriptor_data *e;
X{
X    struct descriptor_data *d;
X    long now;
X    racetype *r;
X
X    (void) time (&now);
X    queue_string (e, "Current Players:\n");
Xopenracedata(&server_racedata);
X    for (d = descriptor_list; d; d = d->next) {
X	if (d->connected) {
X	    getrace(server_racedata, &r, d->Playernum);
X
X	    if (d->last_time)
X		sprintf (buf, "%20s (%3d)     seconds idle %d\n", r->name, 
X			d->Playernum, now - d->last_time);
X	    else
X		sprintf (buf, "%20s (%3d)     idle forever\n", r->name, d->Playernum);
X	    queue_string (e, buf);
X	}
X    }
Xclose_file(server_racedata);
X}
X
Xvoid process_command(Playernum, command) 
X/* locate and parse the command for processing */
Xint Playernum;
Xchar *command;
X{
Xint i,argn=0;
Xboolean parse_exit=0;
Xchar args[MAXARGS][COMMANDSIZE];
Xchar *string, *announcement, *dummy;
X
Xopenracedata(&server_racedata);
Xfree(Race);
Xgetrace(server_racedata, &Race, Playernum);
Xclose_file(server_racedata);
X
X	string=command;	/* make pointers the same */
X
X	while (!parse_exit) {
X	    i=0;
X	    while ( !isspace(*string) && (*string!='\0') && (i<COMMANDSIZE) )
X		args[argn][i++]=(*string++);
X	    args[argn][i]='\0';
X	    /*printf("arg %d |%s|\n",argn,args[argn]);*/
X	    while ((*string)==' ') string++;
X	    if ( (*string=='\0') || (argn>=MAXARGS)) parse_exit=1;
X	    argn++;
X	}
X	for (i=argn; i<MAXARGS; i++)
X		args[i][0]='\0';
X
X	if (args[0][0]=='\0')   /* just pressed return */
X		return;	/* go back and wait again */
X	i=strlen(args[0]);
X
X/*determine which routine to go to and what action to take */
X/* target routine is specified by the first substring, other options 
X	are the substrings which follow */
X
X        if (!strncmp(args[0],"announce",i))
X			announce(Playernum,0,argn,args, 0);
X         else if (!strncmp(args[0],"allocate",i)) allocateAPs(Playernum,0, argn, args);
X         else if (!strncmp(args[0],"assault",i)) land(Playernum,1,argn,args,1);
X	else if (!strncmp(args[0], "autoreport",i)) autoreport(Playernum, 0, argn, args);
X	else if (!strncmp(args[0],"build",i)) build(Playernum,1,argn,args);
X	else if (!strncmp(args[0], "broadcast", i)) announce(Playernum, 5*(!Race->God), argn, args, 1);
X	else if (!strncmp(args[0], "block", i)) block(Playernum, 0, argn, args);
X         else if (!strncmp(args[0],"capitol",i)) capitol(Playernum,50,argn,args);
X         else if (!strncmp(args[0],"capture",i)) capture(Playernum,1,argn,args);
X	else if (!strncmp(args[0], "center", i)) center(Playernum, 0, argn, args);
X	else if (!strncmp(args[0],"cs",i)) cs(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"declare",i)) declare(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"dock",i)) land(Playernum,0,argn,args,0);
X	else if (!strncmp(args[0],"enslave",i)) enslave(Playernum,2,argn,args);
X	else if (!strncmp(args[0],"examine",i)) examine(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"explore",i)) exploration(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"fire",i)) fire(Playernum,1,argn,args);
X	else if (!strncmp(args[0], "gag", i)) Dir[Playernum-1].gag = !Dir[Playernum-1].gag;
X	else if (!strncmp(args[0],"give",i)) give(Playernum,5,argn,args);
X	else if (!strncmp(args[0], "identify", i)) whois(Playernum, 0, argn, args);
X	else if (!strncmp(args[0], "invite", i)) invite(Playernum, 0, argn, args, 1);
X	else if (!strncmp(args[0],"land",i)) land(Playernum,1,argn,args,0);
X	else if (!strncmp(args[0],"launch",i)) launch(Playernum,1,argn,args);
X	else if (!strncmp(args[0], "list", i) && Race->God) list(Playernum);
X	else if (!strncmp(args[0],"load",i)) load(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"map",i)) map(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"mobilize",i)) mobilize(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"move",i)) move_popn(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"make", i)) make_mod(Playernum, 0, argn, args, 0);
X	else if (!strncmp(args[0],"modify", i)) make_mod(Playernum, 0, argn, args, 1);
X	else if (!strncmp(args[0],"name",i)) name(Playernum,1*(!Race->God),argn,args);
X	else if (!strncmp(args[0],"object",i)) rst(Playernum,0,argn,args,4);
X	else if (!strncmp(args[0],"orbit",i)) orbit(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"order",i)) order(Playernum,1,argn,args); 
X	else if (!strncmp(args[0],"page",i)) page(Playernum, 1*(!Race->God), argn, args);
X         else if (!strncmp(args[0],"colonies",i)) colonies(Playernum,0,argn,args);
X	else if (!strncmp(args[0], "pledge", i)) pledge(Playernum, 0, argn, args, 1);
X	else if (!strncmp(args[0],"power",i)) power(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"profile",i)) profile(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"relation",i)) relation(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"read",i)) read_messages(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"reset", i) && Race->God) reload_star_data_base();
X	else if (!strncmp(args[0],"report",i)) rst(Playernum,0,argn,args,0);
X	else if (!strncmp(args[0],"@@shutdown",i) && Race->God) {
X		shutdown_flag = 1;
X		notify(Playernum, "Doing shutdown.\n");
X	} else if (!strncmp(args[0],"stock",i)) rst(Playernum,0,argn,args,1);
X	else if (!strncmp(args[0],"ship",i)) rst(Playernum,0,argn,args,3);
X	else if (!strncmp(args[0],"survey",i)) survey(Playernum,0,argn,args);
X	else if (!strncmp(args[0], "send", i)) send_message(Playernum, 1*(!Race->God), argn, args);
X	else if (!strncmp(args[0],"scrap",i)) scrap(Playernum,1,argn,args);
X	else if(!strncmp(args[0],"tactical",i)) rst(Playernum,0,argn,args,2);
X/*	else if (!strncmp(args[0],"telegram",i)) telegram(Playernum,0,argn,args); */
X	else if(!strncmp(args[0],"technology",i)) technology(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"toggle",i)) toggle(Playernum,0,argn,args);
X	else if(!strncmp(args[0],"toxicity",i)) toxicity(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"transfer",i)) transfer(Playernum,1,argn,args);
X	else if (!strncmp(args[0],"unload",i)) load(Playernum,0,argn,args);
X	else if (!strncmp(args[0],"undock",i)) launch(Playernum,0,argn,args);
X	else if (!strncmp(args[0], "uninvite", i)) invite(Playernum, 0, argn, args, 0); 
X	else if (!strncmp(args[0], "unpledge", i)) pledge(Playernum, 0, argn, args, 0); 
X        else if (!strncmp(args[0],"time",i)) GB_time(Playernum);
X	else if (!strncmp(args[0],"zoom",i)) zoom(Playernum,0,argn,args);
X			/* only owning player can use fix */
X	 else {
X	       sprintf(buf,"'%s':illegal command error(%d).\n",args[0],*args[0]);
X		notify(Playernum, buf);
X		}
X
X/* send the prompt to the player */
X	sprintf(buf, "%s", Dir[Playernum-1].prompt);
X		notify(Playernum, buf);
X
X}
X
Xvoid panic(message)
Xconst char *message;
X{
X    FILE *f;
X    int i;
X
X    fprintf(stderr, "PANIC: %s\n", message);
X
X    /* turn off signals */
X    for(i = 0; i < NSIG; i++) {
X	signal(i, SIG_IGN);
X    }
X
X    /* shut down interface */
X    emergency_shutdown();
X
X    /* dump panic file */
X}
X
Xreload_star_data_base()
X{
Xint maim_stardata;
Xint s, t;
X
X/* get star database */
X	openstardata(&maim_stardata);
X	  getsdata(maim_stardata,&Sdata);
X	for (s=0; s<Sdata.numstars; s++) {
X		getstar(maim_stardata,&(Stars[s]),s);
X		}
X	close_file(maim_stardata);
X/* initialize zoom factors */	
X	for(i=1; i<=Numraces(); i++) {
X	Dir[i-1].zoom[0] = 1.0;
X	Dir[i-1].zoom[1] = 0.5;
X	Dir[i-1].lastx[0] = Dir[i-1].lastx[1] = 0.0;
X	Dir[i-1].lasty[0] = Dir[i-1].lasty[1] = 0.0;
X	}
X}
X
X
Xstr_cat(s1, s2)
Xchar *s1,*s2;
X{
X	strcat(s1, s2);
X}
X
XGB_time(Playernum) /* report back the update status */
Xint Playernum;
X{
X#ifdef BSD4_2
X    char zone[16];
X#endif
X
X    clk = time(0);
X    current_tm=localtime(&clk);
X#ifdef BSD4_2
X    strcpy(zone, timezone(min_west, current_tm->tm_isdst));
X#else
X    strcpy(zone, current_tm->tm_zone);
X#endif
Xsprintf(buf,"\nCurrent time  : %2d/%2d/%d %02d:%02d:%02d %s\n",
X	current_tm->tm_mon+1, current_tm->tm_mday,
X        current_tm->tm_year, current_tm->tm_hour,
X	current_tm->tm_min, current_tm->tm_sec, zone);
Xnotify(Playernum, buf);
Xif(update_tm != NULL)
X   notify(Playernum, update_buf);
Xelse
X   notify(Playernum, "No updates since the server was started.\n");
X    /* can happen if you have just started the game up */   
Xnotify(Playernum, start_buf);
X}
X
Xhelp(e, argn,args)
Xstruct descriptor_data *e;
Xint argn;
Xchar args[MAXARGS][COMMANDSIZE];
X{
X char s[MAXCOMMSTRSIZE];
X
X if (argn==1) {
X	sprintf(buf,"usage: help [topic]\n");
X		queue_string(e, buf);
X	sprintf(buf,"    valid topics are:\n  CONCEPTS:\n%s",
X		"help     scope    actionpoints       explore    colony\n" );
X		queue_string(e, buf);
X	sprintf(buf,"daemon   races     blocks     quit  	     info\n");
X		queue_string(e, buf);
X	sprintf(buf,"\n  COMMANDS:\n");
X		queue_string(e, buf);
X	sprintf(buf,"cs       map      survey  orbit      zoom     autoreport\n");
X		queue_string(e, buf);
X	sprintf(buf,"toggle   gag	  capitol  allocate\n\n");
X		queue_string(e, buf);
X	sprintf(buf, "announce page    who    time    quit\n");
X		queue_string(e, buf);
X	sprintf(buf,"build    ship     stock   report     tactical  order     examine\n");
X		queue_string(e, buf);
X	sprintf(buf,"land     launch   dock    undock     load      assault   scrap\n\n");
X		queue_string(e, buf);
X	sprintf(buf,"assault  capture  fire    give       move       enslave\n\n");
X		queue_string(e, buf);
X	sprintf(buf,"declare  profile  relation    power   explore\n");
X		queue_string(e, buf);
X	sprintf(buf,"colonies name     mobilize technology toxicity   transfer\n");
X		queue_string(e, buf);
X	sprintf(buf, "make   modify\n");
X		queue_string(e, buf); 
X
X } else {
X
X    FILE *f;
X    char file[1024];
X    char *p;
X
X    sprintf(file,"%s/%s.doc", DOCS, args[1] );
X    if((f = fopen(file, "r")) != 0) {
X	while(fgets(buf, sizeof buf, f)) {
X	    for(p = buf; *p; p++) if(*p == '\n') {
X		*p = '\0';
X		break;
X	    }
X	strcat(buf, "\n");
X		queue_string(e, buf);
X	}
X	fclose(f);
X    } else
X	queue_string(e, "Help on that subject unavailable.\n");
X
X  }
X
X}
X
Xcheck_for_telegrams(Playernum)
Xint Playernum;
X{
Xsprintf(buf, "%s.%d", TELEGRAMFL, Playernum);
Xstat(buf, &sbuf);
Xif(sbuf.st_size)
Xnotify(Playernum, "You have telegram(s) waiting. Use 'read' to read them.\n");
X}
END_OF_FILE
if test 33670 -ne `wc -c <'server/GB_server.c'`; then
    echo shar: \"'server/GB_server.c'\" unpacked with wrong size!
fi
# end of 'server/GB_server.c'
fi
if test -f 'server/doship.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'server/doship.c'\"
else
echo shar: Extracting \"'server/doship.c'\" \(16262 characters\)
sed "s/^X//" >'server/doship.c' <<'END_OF_FILE'
X/*
X * Galactic Bloodshed, copyright (c) 1989 by Robert P. Chansky, 
X * smq@ucscb.ucsc.edu, mods by people in GB_copyright.h.
X * Restrictions in GB_copyright.h.
X * doship -- do one ship turn.
X */
X
X#include "GB_copyright.h"
X#define EXTERN extern
X#include "vars.h"
X#include "ships.h"
X#include "races.h"
X#include "doturn.h"
X#include "power.h"
X#include "buffers.h"
X#include <math.h>
X#include <strings.h>
X
X
Xdoship(shipno,ship)
Xint shipno;
Xshiptype *ship;
X{
X int sh,sh2,j,shfdata;
X boolean trigger;
X
X/*ship is active */
X	ship->active = 1;
X
X if (ship->is_alive) {
X
X/* for debugging */
X	if(ship->popn > Max_crew(ship)) 
X			ship->popn = Max_crew(ship);
X	if(ship->destruct > Max_destruct(ship))
X			ship->destruct = Max_destruct(ship);
X	if(ship->fuel > (float)Max_fuel(ship))
X			ship->fuel = (float)Max_fuel(ship);
X
X/* compute the mass of the ship (there is a wierd bug that changes
X   mass the wrong way) */
Xship->mass = ship->popn*races[ship->owner-1]->mass + ship->resource*MASS_RESOURCE
X  + ship->fuel*MASS_FUEL + ship->destruct*MASS_DESTRUCT
X  + Mass(ship);
X
X		/* repair radiation */
X      if (ship->rad) {
X	ship->active = 1;
X			/* irradiated ships are immobile.. */
X			/* kill off some people */
X		/* check to see if ship is active */
X		if(int_rand(1,100) <= ship->rad)
X			ship->active = 0;
X		ship->popn = round_rand(ship->popn * .80);
X		if (ship->rad >= (int)REPAIR_RATE)
X			ship->rad -= int_rand(0,(int)REPAIR_RATE);
X		else
X			ship->rad -= int_rand(0,ship->rad);
X      } else
X	   ship->active = 1;
X
X      if(!ship->popn && Max_crew(ship) > 0
X	 && !ship->is_docked) {
X	ship->whatdest = LEVEL_UNIV;
X      }
X
X      if (ship->whatorbits>LEVEL_UNIV && Stars[ship->storbits]->nova_stage>0) {
X		/* damage ships from supernovae */
X	ship->damage += 50.0/Armor(ship);
X	if (ship->damage >= 100) {
X		kill_ship(ship);
X		return;
X	}
X      }
X
X   if(ship->active)
X	Moveship(shipno, ship);
X
X
X
X	if(ship->whatorbits != LEVEL_UNIV) {
X/* printf("checking #%d\n",shipno); */
X		StarsInhab[ship->storbits] = 1;
X		setbit(Stars[ship->storbits]->inhabited, ship->owner);
X		setbit(Stars[ship->storbits]->explored, ship->owner);
X		if(ship->whatorbits == LEVEL_PLAN) {
X			planets[ship->storbits][ship->pnumorbits]->info[ship->owner-1].explored = 1;
X					}
X		}
X/* just making sure */	
X
X
X		/* add ships, popn to total count to add AP's */
X	Power[ship->owner-1].ships_owned++;
X	Power[ship->owner-1].resource += ship->resource;
X	Power[ship->owner-1].fuel += ship->fuel;
X	Power[ship->owner-1].destruct += ship->destruct;
X	Power[ship->owner-1].popn += ship->popn;
X
X	if (ship->whatorbits==LEVEL_UNIV) {
X		 Sdatanumships[ship->owner-1]++;
X		 Sdatapopns[ship->owner] += ship->popn;
X	} else {
X		starnumships[ship->storbits][ship->owner-1]++; 
X	         /* add popn of ships to popn */
X	        starpopns[ship->storbits][ship->owner-1] += ship->popn;
X		 /* set inhabited for ship */
X		StarsInhab[ship->storbits] = 1;
X		setbit(Stars[ship->storbits]->inhabited, ship->owner);
X		setbit(Stars[ship->storbits]->explored, ship->owner);
X	}
X
X
X
X
X	if (ship->active) {
X
X		/* bombard the planet */
X	   if (can_bombard(ship) && ship->bombard
X			&& ship->whatorbits==LEVEL_PLAN
X			&& ship->whatdest==LEVEL_PLAN
X			&& ship->deststar== ship->storbits
X			&& ship->destpnum== ship->pnumorbits) {
X				/* ship bombards planet */
X		Stinfo[ship->storbits][ship->pnumorbits].inhab = 1;
X	   }
X
X
X
X	       /* repair ship by the amount of crew it has */
X	       /* industrial complexes can repair (robot ships can't repair) */
X	if (ship->damage && (ship->popn || ship->type==OTYPE_FACTORY)) {
X             reg int drep,cost;
X             reg float maxrep;
X             maxrep = REPAIR_RATE;
X	       /* stations repair for free, and ships docked with them */
X	     if ((ship->type==STYPE_STATION || !Max_resource(ship)) || 
X		(ship->is_docked && ship->whatdest==LEVEL_SHIP && 
X		 ships[ship->destshipno]->type==STYPE_STATION))
X	       {
X		  cost = 0.0;
X	     } else {
X             maxrep *= (float)ship->popn / (float)Max_crew(ship);
X             cost = 0.005 * maxrep * Cost(ship);
X		}
X
X             if (cost > ship->resource) 
X              { 
X	     drep = (int)maxrep * ship->resource / cost;
X                ship->resource = 0; 
X		} else { 
X	      	ship->resource -= cost; 
X		drep = (int)maxrep;
X	      }
X
X	     ship->mass -= cost * MASS_RESOURCE;
X
X	     if (drep > ship->damage) ship->damage = 0;
X                else 
X		  ship->damage -= drep;
X/*	     printf("rep = %d\n",drep); */
X	}
X
X
X     switch (ship->type) {
X
X      case OTYPE_CANIST:
X	   if (ship->whatorbits == LEVEL_PLAN && !ship->is_docked) { short *t;
X	      if (--ship->object.number) {
X		if ( Stinfo[ship->storbits][ship->pnumorbits].temp_add < -90 )
X		  Stinfo[ship->storbits][ship->pnumorbits].temp_add = -100;
X		else  
X		  Stinfo[ship->storbits][ship->pnumorbits].temp_add -= 10;
X	      } else {	/* timer expired; destroy canister */
X		   reg int j=0;
X
X		  kill_ship(ship);
X		  sprintf(telegram_buf,"Notice from /%s/%s\n\n", 
X			   Stars[ship->storbits]->name, 
X			   Stars[ship->storbits]->pnames[ship->pnumorbits]);
X		  sprintf(buf, "Canister of dust previously covering this planet has dissipated.\n");
X			str_cat(telegram_buf, buf);
X		  for (j=1; j<=Num_races; j++)
X		       if (planets[ship->storbits][ship->pnumorbits]->info[j-1].numsectsowned) 
X				push_message(TELEG_PLAYER_AUTO, j, telegram_buf);
X	      }
X	   }
X	   break;
X
X      case STYPE_MINE:
X		/* check around and see if we should explode. */
X	   if (ship->on) {
X		int rad=0; int dam=0; double xd,yd,range; int p;
X	     if (ship->whatorbits==LEVEL_STAR)
X	     	sh = Stars[ship->storbits]->ships;
X	     else if (ship->whatorbits==LEVEL_PLAN)
X		sh = planets[ship->storbits][ship->pnumorbits]->ships;
X	     else
X		sh = Sdata.ships;
X	     sh2 = sh;
X	      /* traverse the list, look for ships that 
X			are closer than the trigger radius... */
X/*printf("found mine  sh = %d rad = %d\n",sh,rad);*/
X	       while (sh && !rad) {
X		xd = ships[sh]->xpos - ship->xpos;
X		yd = ships[sh]->ypos - ship->ypos;
X		range = sqrt(xd*xd + yd*yd);
X		if ( !isset(races[ship->owner-1]->allied, ships[sh]->owner) && 
X		   (ships[sh]->owner != ship->owner) && 
X		   ( range <= (float)ship->object.number) )
X			 rad = 1;
X		else {
X			 sh = ships[sh]->nextship;
X		       }
X	     }
X
X/*printf("rad = %d\n",rad);*/
X	     if (rad) {
X		  char telegram_not[1000];
X		kill_ship(ship);
X		sprintf(telegram_buf, "BULLETIN!\n mine #%d triggered at %s\n",
X				shipno,prin_ship_orbits(ship));
X
X		/* I have made the blast radius equal to the trigger radius.*/
X		/* -R. */
X
X		sh = sh2 ;   /* Make sh start from beginning of the list */
X		while (sh) {
X
X			xd = ships[sh]->xpos - ship->xpos;
X			yd = ships[sh]->ypos - ship->ypos;
X			range = sqrt(xd*xd + yd*yd);
X			trigger = (int_rand(1,100) 
X				<= 2 * Size(ships[sh]));
X
X		   if (range <= ship->object.number && trigger) {
X
X		     if (!ship->mine.mode) {
X		        int totalrad;
X			 /* radiation mine */
X
X		        rad = round_rand(ship->destruct * 
X			  (1./(float)Size(ships[sh])) * 
X			  (800/(range + 1.)) );
X
X			rad = MIN(int_rand(0,rad),100);
X
X			totalrad = ships[sh]->rad + rad;
X			if (totalrad > 100 ) totalrad = 100;
X			        ships[sh]->rad = totalrad;
X
X			if (rad) {
X			     sprintf(telegram_not, "BULLETIN!\n %s #%d irradiated by mine #%d\n", Shipnames[ships[sh]->type], sh, shipno);
X			     sprintf(buf," at %s - dosage %d%%",prin_ship_orbits(ships[sh]), rad);
X			str_cat(telegram_not, buf);
X	push_message(TELEG_PLAYER_AUTO, ships[sh]->owner, telegram_not);
X			     sprintf(buf,"%s #%d [%d] received %d%% dosage\n",
X				Shipnames[ships[sh]->type], sh, 
X					ships[sh]->owner, rad);
X		str_cat(telegram_buf, buf);
X			}
X
X		      } else {
X			int totaldam;	
X			 /* explosive mine */
X		        rad = round_rand(ship->destruct * 
X			  (1./(float)Size(ships[sh])) * 
X			  (800.0/(range + 1.)) );
X
X			dam = MIN(100,int_rand(0,rad));
X			totaldam = ships[sh]->damage+dam;
X			if (totaldam > 100 ) totaldam = 100;
X			if (dam>0) {
X			   ships[sh]->damage = totaldam;
X			   sprintf(telegram_not, "BULLETIN!\n %s #%d damaged by mine #%d\n",
X					 Shipnames[ships[sh]->type], sh, shipno);
X			   sprintf(buf," at %s - %d %% damage", prin_ship_orbits(ship), dam);
X					str_cat(telegram_not, buf);
X			   sprintf(buf,"%s #%d [%d] received %d%% damage\n",
X				Shipnames[ships[sh]->type], sh, 
X				ships[sh]->owner, rad);
X				str_cat(telegram_buf, buf);
X			   if (ships[sh]->damage >= 100) {
X				kill_ship(ships[sh]);
X				sprintf(buf, " %s #%d DESTROYED",Shipnames[ships[sh]->type],sh);
X					str_cat(telegram_not, buf);
X				sprintf(buf,"\t--DESTROYED\n");
X					str_cat(telegram_buf, buf);
X			   }
X	push_message(TELEG_PLAYER_AUTO, ships[sh]->owner, telegram_not);
X			}
X		       }
X
X		     }
X
X		     sh = ships[sh]->nextship;
X		}
X	     }
X	push_message(TELEG_PLAYER_AUTO, ship->owner, telegram_buf); 
X	   }
X	   break;
X
X      case STYPE_MIRROR:
X	  switch (ship->aimed_at.level) {
X	   case LEVEL_SHIP: /* ship aimed at is a legal ship now */
X			  /* if in the same system */
X	    if ( (ship->whatorbits==LEVEL_STAR || ship->whatorbits==LEVEL_PLAN)
X		   && (ships[ship->aimed_at.shipno]!=NULL)
X		   && (ships[ship->aimed_at.shipno]->whatorbits==LEVEL_STAR ||
X			ships[ship->aimed_at.shipno]->whatorbits==LEVEL_PLAN)
X		   && ship->storbits == ships[ship->aimed_at.shipno]->storbits 
X		   && ships[ship->aimed_at.shipno]->is_alive ) {
X			    shiptype *s;
X			      reg int i;
X			      float range;
X				s = ships[ship->aimed_at.shipno];
X		  range = sqrt(Distsq(ship->xpos, ship->ypos,s->xpos,s->ypos));
X		  i = int_rand(0,round_rand((2./((float)Size(s)))
X		    *(float)ship->aimed_at.intensity/(range/PLORBITSIZE+1.0)));
X	  sprintf(telegram_buf, "Space Mirror #%d %s [owner %d] aimed at ",
X		  shipno, ship->name, ship->owner);
X		str_cat(telegram_buf, buf);
X	  sprintf(buf, "%s #%d %s [owner %d] !\n",Shipnames[s->type],
X		  ship->aimed_at.shipno, s->name, s->owner);
X		str_cat(telegram_buf, buf);
X				s->damage += i;
X			    if(i) {
X	  sprintf(buf, "\n%d%% damage done.\n",i);
X		str_cat(telegram_buf, buf); 
X			    }
X				if (s->damage >= 100) {
X	  sprintf(buf, "%s #%d DESTROYED!!!\n",Shipnames[s->type],
X		  ship->aimed_at.shipno);
X					kill_ship(s);
X				      }
X
X push_message(TELEG_PLAYER_AUTO, s->owner, telegram_buf);
X push_message(TELEG_PLAYER_AUTO, ship->owner, telegram_buf);
X			}
X		break;
X	   case LEVEL_PLAN: { reg short *t; 
X			      reg int i;
X			      float range;
X		  range = sqrt(Distsq(ship->xpos, ship->ypos,
X			Stars[ship->storbits]->xpos
X		       +planets[ship->storbits][ship->pnumorbits]->xpos,
X			Stars[ship->storbits]->ypos
X		       +planets[ship->storbits][ship->pnumorbits]->ypos));
X
X		  if ( range > PLORBITSIZE ) 
X			  i = PLORBITSIZE * ship->aimed_at.intensity/range;
X		  else
X			  i = ship->aimed_at.intensity;
X
X		i = round_rand(.01*(100.0-(float)ship->damage)*(float)i);
X		  Stinfo[ship->storbits][ship->aimed_at.pnum].temp_add += i;
X
X		} break;
X
X	   case LEVEL_STAR: { float range;
X		  /* have to be in the same system as the star; otherwise
X		      it's not too fair.. */
X		if (ship->aimed_at.snum>0 && 
X			ship->aimed_at.snum < Sdata.numstars &&
X			ship->whatorbits > LEVEL_UNIV &&
X			ship->aimed_at.snum == ship->storbits)
X		    Stars[ship->aimed_at.snum]->stability += random()&01;
X		} break;
X	   case LEVEL_UNIV:
X		break;
X	}
X	break;
X     case STYPE_GOD:
X		/* gods have infinite power.... heh heh heh */
X	ship->fuel = Max_fuel(ship);
X	ship->popn = Max_crew(ship);
X	ship->destruct = Max_destruct(ship);
X	ship->resource = Max_resource(ship);
X	break;
X
X     case OTYPE_AP:	/* atmospheric processor */
X		/* if landed on planet, change conditions to be like race */
X	if (ship->is_docked && ship->whatdest==LEVEL_PLAN && ship->on) {
X		int j,d,a;planettype *p;
X		p = planets[ship->storbits][ship->pnumorbits];
X		if (ship->fuel >= 3.0) {
X			ship->fuel -= 3.0;
X			for (j=RTEMP+1; j<=OTHER; j++) {
X				if ( (d = races[ship->owner-1]->conditions[j] - 
X				      p->conditions[j]) != 0) {
X	   
X				  a = sgn(d)*int_rand(-1,
X           round_rand(MIN(3,d*sgn(d))
X	   *(float)ship->popn/(float)Shipdata[OTYPE_AP][ABIL_MAXCREW]));
X				  if (p->conditions[j] + a < 0)
X					p->conditions[j] = 0;
X				  else if (p->conditions[j] + a > 100)
X					p->conditions[j] = 100;
X				  else p->conditions[j] += a;
X				}
X			}
X		} else if (!ship->notified) {
X			ship->notified = 1;
X			msg_OOF(ship, shipno, telegram_buf);
X		}
X	}
X	break;
X
X     case OTYPE_VN:	/* Von Neumann machine */
X	do_VN(ship,shipno);
X	break;
X
X     case OTYPE_BERS:	/* Berserker */
X		/* (turn done in doplanet() ) */
X	break;
X
X     case STYPE_ASS:
X	 /* "indimidate" the planet below, for enslavement purposes. */
X	if (ship->whatorbits==LEVEL_PLAN)
X		Stinfo[ship->storbits][ship->pnumorbits].intimidated = 1;
X	break;
X
X     case OTYPE_OMCL:
X	 /* orbital mind control laser */
X	if (ship->aimed_at.level==LEVEL_PLAN && ship->on &&
X	    ship->speed==1) {
X		planets[ship->aimed_at.snum][ship->aimed_at.pnum]
X			->is_sheep = 1;
X	}
X	break;
X
X     case STYPE_HABITAT:{ reg int add;
X	 /* habitats multiply some resources inside them. */
X	add = ship->resource *
X		((float)ship->popn / Shipdata[STYPE_HABITAT][ABIL_MAXCREW]) 
X	         * (100 - ship->damage) * 0.0005;
X	if (ship->resource+add > Shipdata[STYPE_HABITAT][ABIL_CARGO])
X		add = Shipdata[STYPE_HABITAT][ABIL_CARGO] - ship->resource;
X	ship->resource += add;
X	ship->mass += add * MASS_RESOURCE;
X	add = ship->popn * races[ship->owner-1]->birthrate * 
X		(100 - ship->damage) * 0.002;
X	if (ship->popn+add > Shipdata[STYPE_HABITAT][ABIL_MAXCREW])
X		add = Shipdata[STYPE_HABITAT][ABIL_MAXCREW] - ship->popn;
X	ship->popn += add;
X	ship->mass += add * races[ship->owner-1]->mass;
X	} break;
X
X     case STYPE_POD:
X      if (ship->notified) {
X    	/* we just arrived at this system -- explode */
X    	/* or, we are floating in space with no fuel -- just die */
X    	reg int i,f;
X
X	f = -1;
X    	kill_ship(ship);
X    	if (ship->whatorbits==LEVEL_STAR) {
X
X		  i = int_rand(0,Stars[ship->storbits]->numplanets - 1);
X
X		     if(int_rand(1,4)==1)
X    			f = i;
X
X    	  sprintf(telegram_buf, "Bulletin\n\nSpore pod #%d has warmed and exploded.\n",shipno);
X     	  if (f != -1) {
X    		sprintf(buf,"A spore has landed on planet %s.\n",Stars[ship->storbits]->pnames[f]);
X    		Stinfo[ship->storbits][f].Thing_add = ship->owner;
X    			/* so doplanet does not pass over it */
X		StarsInhab[ship->storbits] = 1;
X    		setbit(Stars[ship->storbits]->inhabited,ship->owner);
X    		setbit(Stars[ship->storbits]->explored, ship->owner);
X    		planets[ship->storbits][f]->info[ship->owner-1].explored = 1;
X    	  } else {
X    		sprintf(buf,"No spores have survived.\n");
X    	  }
X			str_cat(telegram_buf, buf);
X	push_message(TELEG_PLAYER_AUTO, ship->owner, telegram_buf); 
X    	  sprintf(telegram_buf,"BULLETIN!\n\n A spore pod has exploded in system /%s.\n",
X			Stars[ship->storbits]->name);
X    	  sprintf(buf, "Spores may have drifted to planets here.\n");
X			str_cat(telegram_buf, buf);
X    	  for (i=1; i<=Num_races; i++)
X    		if (i!=ship->owner && isset(Stars[ship->storbits]->inhabited,i))
X	push_message(TELEG_PLAYER_AUTO, i, telegram_buf);
X
X   	}
X     }
X     break;
X
X     default:
X	break;
X    }
X
X   }
X
X } else if (!ship->is_alive && !ship->notified) {
X	 /* ship is dead -- add to shipfree file, remove from all lists. */
X	 /* if notified, this means it's already been deleted and written. */
X/*	printf("destroyed ship #%d\n",shipno);*/
X	if (ship->type == OTYPE_VN || ship->type==OTYPE_BERS) {
X
X		 /* add ship to VN shit list */
X
X		if (ship->object.number2>0 && ship->object.number2<=Num_races 
X		    && ship->object.number2 != ship->owner) {
X		 Sdata.VN_hitlist[ship->object.number2-1] ++;
X
X		  /* keep track of where these VN's were shot up */
X
X		 if (Sdata.VN_index1[ship->object.number2]== 255)
X			 /* there's no star in the first index */
X			Sdata.VN_index1[ship->object.number2] = ship->storbits;
X		 else if (Sdata.VN_index2[ship->object.number2]== 255)
X			 /* there's no star in the second index */
X			Sdata.VN_index2[ship->object.number2] = ship->storbits;
X		 else {
X			 /* pick an index to supplant */
X		    if (random()&01)
X			Sdata.VN_index1[ship->object.number2] = ship->storbits;
X		    else
X			Sdata.VN_index2[ship->object.number2] = ship->storbits;
X		 }
X		 printf("\t-- added %d ships, player %d\n",
X				ship->object.number, ship->object.number2);
X		}
X	}
X	ship->notified = 1;
X	makeshipdead(shipno);
X }
X
X}
END_OF_FILE
if test 16262 -ne `wc -c <'server/doship.c'`; then
    echo shar: \"'server/doship.c'\" unpacked with wrong size!
fi
# end of 'server/doship.c'
fi
echo shar: End of archive 2 \(of 14\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 14 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0