
/*
 * Copyright (c) 1991    Jon Wesener 
 * Gaming Software
 *
 * Permission to use, copy, modify, and distribute this
 * software and its documentation for any purpose and without
 * fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright
 * notice and this permission notice appear in supporting
 * documentation.  No representations are made about the
 * suitability of this software for any purpose.  It is
 * provided "as is" without express or implied warranty.
 *
 */

#ident	"@(#)server.c	1.25 :/usr/key/jojow/X/src/guts/SCCS/s.server.c 3/19/91 10:16:03 "

/* server.c - tank server */


#include <stdio.h>
#include <rpc/rpc.h>
#include <sys/time.h>
#include <strings.h>

#define SERVER	1

#include "server.h"
#include "tankmsg.h"

#define MASK	0x40

struct timeval	ctv, ntv;

int Playercnt = 0;

char maze[MAZE_XL*MAZE_YL + 1];

/* Initialize and array and pass it in to initstate. */
static long state1[32]  =      {       3,       0x9a319039,
	0x32d9c024,  0x9b663182,  0x5da1f342,       0x7449e56b,
	0xbeb1dbb0,  0xab5c5918,  0x946554fd,       0x8c2e680f,
	0xeb3d799f,  0xb11ee0b7,  0x2d436b86,       0xda672e2a,
	0x1588ca88,  0xe369735d,  0x904f35f7,       0xd7158fd6,
	0x6fa6f051,  0x616e6b96,  0xac94efdc,       0xde3b81e0,
	0xdf0a6fb5,  0xf103bc02,  0x48f340fb,       0x36413f93,
	0xc622c298,  0xf5a42ab8,  0x8a88d77b,       0xf5ad9d0e,
	0x8999220b, 0x27fb47b9      };

char *initstate(), *setstate();


serverinit()
{
	unsigned seed = 1;
	int n = 128;
	int i;
	extern char *Mazefnm;


	/* load the maze */
	if( load_field(Mazefnm) ) {
		(void)fprintf(stderr,"serverinit: unable to load maze\n");
		exit( 1 );
	}

	Totenergy = 0;
	Svalid = Sfree = NULL;
	Mvalid = Mfree = NULL;
	Hvalid = Hfree = NULL;
	Evalid = Efree = NULL;
	Tvalid = Tfree = NULL;
	Pvalid = Pfree = NULL;
	Bvalid = Bfree = NULL;

	/* set up tanks */
	for( i = 0 ; i < MAXTANK ; i++ ) {
		tanks[i].t_id = i;
		tanks[i].t_msg = tanks[i].t_msgb;
		tanks[i].t_next = Tfree;
		Tfree = &tanks[i];
	}

	/* set up shells */
	for( i = 0 ; i < MAXSHELL ; i++ ) {
		shells[i].s_next = Sfree;
		Sfree = &shells[i];
	}

	/* set up mines */
	for( i = 0 ; i < MAXMINE ; i++ ) {
		mines[i].m_next = Mfree;
		Mfree = &mines[i];
	}

	/* set up heats */
	for( i = 0 ; i < MAXHEAT ; i++ ) {
		heats[i].h_next = Hfree;
		Hfree = &heats[i];
	}

	/* set up expls */
	for( i = 0 ; i < MAXEXPL ; i++ ) {
		expls[i].e_next = Efree;
		Efree = &expls[i];
	}

	/* set up pows */
	for( i = 0 ; i < MAXPOW ; i++ ) {
		pows[i].p_next = Pfree;
		Pfree = &pows[i];
	}

	/* set up bonus's */
	for( i = 0 ; i < MAXBON ; i++ ) {
		bons[i].b_next = Bfree;
		Bfree = &bons[i];
	}

	Servstate = 0;

	(void)gettimeofday(&ctv,(struct timezone *)NULL);
	nextupdtime();

	/* I am having greivous problems with this fucking random
	 * number generator... */
	(void)initstate(seed, (char *)state1, n);
	(void)setstate((char *)state1);
	(void)srandom((int)ctv.tv_sec & 0xf);
}


/* to enter, pass in username */
char **
tenter_1(msg)
	char **msg;
{
	tank_t *tp;
	static char *failres;


	/* first ever initialization */
	if( !Playercnt ) 
		serverinit();

	/* see if we can fit player into the game */
	if( !Tfree ) {
		failres = "iF";
		return &failres;
	}

	/* set up the new player */
	tp = Tfree;
	Tfree = tp->t_next;

	tp->t_state = TVALID;	
	tp->t_kills = tp->t_dead = 0;	
	tp->t_dir = 0;	
	tp->t_cmd = 0;	
	tp->t_shellf = tp->t_minef = tp->t_heatf = 0;
	tp->t_hbmiss = tp->t_hbxs = 0;
	(void)strncpy(tp->t_name,*msg,MAXNM);

	place_tank(tp);
	tank_reset(tp,0);

	/* send back the id */
	(void)sprintf(tp->t_msgb,"i%c",tp->t_id+'0');

	(void)fprintf(stdout,"%s entering game with id = %d\n",*msg,tp->t_id);
	(void)fflush(stdout);

	/* link it into the game */
	tp->t_next = Tvalid;
	Tvalid = tp;

	Servstate |= SSCUDFRC | SSTUDFRC;

	Playercnt++;

	Totenergy += Energypt + Tenergy + Tenergy;
	
	return &tp->t_msg;
}


/* ARGSUSED */
int *
getplyrcnt_1(dum)
	void *dum;
{
	return &Playercnt;
}


char **
texit_1(msg)
	char **msg;
{
	int id;
	char *mp = *msg;
	tank_t	*tp, *tr;

	id = mp[1] - '0';

	if( (id >= MAXTANK) || !(tanks[id].t_state & TVALID) ) {
		static char *fail = "Messed up!";

		(void)printf("texit_1: invalid id %d\n",id);
		return &fail;
	}

	tp = &tanks[id];

	(void)fprintf(stdout,"%s leaving game\n",tp->t_name);
	(void)fflush(stdout);

	explode(tp,(tank_t *)NULL,tp->t_damage + 1,tp->t_x,tp->t_y);

	tp->t_state = 0;

	/* remove from the valid queue */
	if( tp == Tvalid )
		Tvalid = tp->t_next;
	else {
		for( tr = Tvalid ; tr->t_next != tp ; tr = tr->t_next );
		tr->t_next = tp->t_next;
	}

	tp->t_next = Tfree;
	Tfree = tp;

	field[tp->t_x][tp->t_y] = FSPACE;
	fpts[tp->t_x][tp->t_y] = NULL;

	(void)sprintf(tp->t_msgb,"%s: died %d, kills %d\n",
		tp->t_name,tp->t_dead - 1, tp->t_kills);

	Servstate |= SSCUDFRC | SSTUDFRC;

	Playercnt--;

	Totenergy -= (Energypt + Tenergy);

	/* remove players resources */
	tank_cleanup(tp);

	return &tp->t_msg;
}


/* ARGSUSED */
char **
getmaze_1(msg)
	int **msg;
{
	static char *mazep = maze;

	return &mazep;
}


char **
getpos_1(msg)
	char **msg;
{
	int id = 0;
	char *mp = *msg;
	tank_t *tp;

	/* find out who we are talking to */
	id = mp[1] - '0';

#if DEBUG
	if( (id >= MAXTANK) || !(tanks[id].t_state & TVALID) ) {
		static char *failres;

		(void)printf("getpos_1: invalid id %d\n",id);
		failres = "T";
		return &failres;
	}
#endif /* DEBUG */

	tp = &tanks[id];

	/* save away their move */
	if( mp[2] )
		tp->t_cmd = mp[2];

	tp->t_state |= THRTBEAT;

	/* time to update the screen? */
	if( timecheck() )
		recompute_screen();

	if( Servstate & SSCUDFRC ) {
		update_screen();
		Servstate &= ~SSCUDFRC;
	}

	/* send back screen info */
	if( tp->t_state & TSCUD )
		tp->t_state &= ~TSCUD;
	else
		tp->t_msgb[0] = '\0';

	return &tp->t_msg;
}


nextupdtime()
{
	/* add TIMESTEP to ctv */
	ntv.tv_usec = ctv.tv_usec + TIMESTEP;

	ntv.tv_sec = ctv.tv_sec;

	if( ntv.tv_usec > 1000000L ) {
		ntv.tv_usec -= 1000000L;
		ntv.tv_sec++;
	}
}


timecheck()
{
	(void)gettimeofday(&ctv,(struct timezone *)NULL);

	if( ((ctv.tv_sec == ntv.tv_sec) && ctv.tv_usec > ntv.tv_usec) || 
		(ctv.tv_sec > ntv.tv_sec) ) {
		nextupdtime();	
		return 1;
	}

	return 0;
}


recompute_screen()
{
	checktanks();
	checkshells();
	checkheats();
	checkpows();
	checkexpls();
	checkbons();
}


update_screen()
{
	register char *cp;
	register tank_t *tp;
	register shell_t *sp;
	register mine_t	*mp;
	register heat_t *hp;
	register expl_t *ep;
	register pow_t *pp;
	bon_t *bp;
	char	pbuf[MAXBUF];
	int	i = 0;
	static int status = 0;


	cp = pbuf;

	/* draw tanks and explosions */
	for( tp = Tvalid ; tp ; tp = tp->t_next ) {

		/* clear the current screen message */
		tp->t_msgb[0] = '\0';

		if( tp->t_state & (TEXP | TCLOAK) ) 
			continue;

		if( !(tp->t_state & TSAFE) || (tp->t_pri & 2) ) {
				
			*cp++ = 't';
			*cp++ = tp->t_x | CSAFE;
			*cp++ = tp->t_y | CSAFE;
			*cp++ = (tp->t_id & 3) | CSAFE;
			*cp++ = tp->t_dir | CSAFE;
		}
	}

	/* draw shells */
	for( sp = Svalid ; sp ; sp = sp->s_next ) {
		*cp++ = 's';
		*cp++ = sp->s_x | CSAFE;
		*cp++ = sp->s_y | CSAFE;
		*cp++ = '-';
		*cp++ = sp->s_dir | CSAFE;
	}

	/* draw heats */
	for( hp = Hvalid ; hp ; hp = hp->h_next ) {
		*cp++ = 'h';
		*cp++ = hp->h_x | CSAFE;
		*cp++ = hp->h_y | CSAFE;
		*cp++ = '-';
		*cp++ = hp->h_dir | CSAFE;
	}

	/* draw bonus's */
	for( bp = Bvalid ; bp ; bp = bp->b_next ) {
		*cp++ = 'b';
		*cp++ = bp->b_x | CSAFE;
		*cp++ = bp->b_y | CSAFE;
		*cp++ = '-';
		*cp++ = ((Bonfrm)?1:0) | CSAFE;
	}

	/* draw expls */
	for( ep = Evalid ; ep ; ep = ep->e_next ) {
		*cp++ = 'e';
		*cp++ = ep->e_x | CSAFE;
		*cp++ = ep->e_y | CSAFE;
		*cp++ = '-';
		*cp++ = ep->e_frm | CSAFE;
	}

	/* draw power pellets */
	for( pp = Pvalid ; pp ; pp = pp->p_next ) {
		*cp++ = 'p';
		*cp++ = pp->p_x | CSAFE;
		*cp++ = pp->p_y | CSAFE;
		*cp++ = '-';
		*cp++ = pp->p_val | CSAFE;
	}

	/* display status of tanks */
	*cp = '\0';

	if( status++ > STATUPD ) {
		*cp++ = 'S';
		*cp = '\0';
		for( tp = Tvalid ; tp ; tp = tp->t_next ) {
			i = strlen(pbuf);
			(void)sprintf(&pbuf[i],"%c%s#",tp->t_id | CSAFE,tp->t_name);
			i = strlen(pbuf);
			(void)sprintf(&pbuf[i],"killed %d died %d#",tp->t_kills,tp->t_dead);
		}
		(void)strcat(pbuf,"$");
		status = 0;
	}
	
	if( strlen(pbuf) > MAXBUF ) {
		(void)fprintf(stderr,"pbuf overrun\n");
		exit( 1 );
	}
		
	/* draw players cloaked tanked and their energy */
	for( tp = Tvalid ; tp ; tp = tp->t_next ) {
		cp = tp->t_msgb;
		if( (tp->t_state & TCLOAK) && (tp->t_pri & 1) ) {
			*cp++ = 't';
			*cp++ = tp->t_x | CSAFE;
			*cp++ = tp->t_y | CSAFE;
			*cp++ = (tp->t_id & 3) | CSAFE;
			*cp++ = tp->t_dir | CSAFE;
		}
		(void)sprintf(cp,"EEnergy %d Dmg %d  #",tp->t_energy,tp->t_damage);
	}

				
	/* draw players own mines on the field */
	for( mp = Mvalid ; mp ; mp = mp->m_next ) {
		tp = mp->m_own;
		i = strlen(tp->t_msgb);
		cp = &tp->t_msgb[i];
		*cp++ = 'm';
		*cp++ = mp->m_x | CSAFE;
		*cp++ = mp->m_y | CSAFE;
		*cp++ = '-';
		*cp++ = '-';
		*cp = '\0';
	}

	/* set up individual tank buffers */
	for( tp = Tvalid ; tp ; tp = tp->t_next ) {
		(void)strcat(tp->t_msgb,pbuf);
		if( !(tp->t_msgb[0]) )
			(void)strcpy(tp->t_msgb,"FORCE");
		tp->t_state |= TSCUD;
	}
}


load_field(mazenm)
	char *mazenm;
{
	int x, y, off;
	char buf[128];
	FILE *fp;


	/* read maze */
	if( !(fp = fopen(mazenm,"r")) ) {
		(void)printf("init_field: unable to open maze\n");
		return 1;
	}

	off = 0;
	for( y = 0 ; y < MAZE_YL ; y++ ) {

		if( !fgets(buf,128,fp) ) {
			(void)printf("init_field: short maze file\n");
			return 1;
		}

		if( strlen(buf) != (MAZE_XL + 1) ) {
			(void)printf("init_field: invalid maze item\n");
			return 1;
		}

		for( x = 0 ; x < MAZE_XL ; x++ ) {
			if( buf[x] == '#' ) {
				field[x][y] = FWALL;
				maze[off] = 'w';
			}
			else {
				field[x][y] = FSPACE;
				maze[off] = ' ';
			}

			/* clear the field ptrs */
			fpts[x][y] = NULL;	

			off++;
		}

	}
	(void)fclose(fp);
	maze[off] = '\0';

	return 0;
}


load_profile(profnm)
	char *profnm;
{
	FILE *fp;
	char	pstr[64];
	int		pvar, vcnt, ln = 1;


	/* read profile */
	if( !(fp = fopen(profnm,"r")) ) {
		(void)printf("init_field: unable to open maze\n");
		return 1;
	}

	while( (vcnt = fscanf(fp,"%s %d\n",pstr,&pvar)) != EOF ) {
		if( vcnt != 2 ) {
			(void)fprintf(stderr,"load_profile: line %d invalid\n",ln);
			continue;
		}

		/* slowly walk through the list and assign values */
		if( !strcmp(pstr,"CLOAKCOST") )
			Cloakcost = pvar;
		else if( !strcmp(pstr,"SHELLCOST") )
			Shellcost = pvar;
		else if( !strcmp(pstr,"MINECOST") )
			Minecost = pvar;
		else if( !strcmp(pstr,"HEATCOST") )
			Heatcost = pvar;
		else if( !strcmp(pstr,"SHELLDMG") )
			Shelldmg = pvar;
		else if( !strcmp(pstr,"MINEDMG") )
			Minedmg = pvar;
		else if( !strcmp(pstr,"HEATDMG") )
			Heatdmg = pvar;
		else if( !strcmp(pstr,"TANKENERGY") )
			Tenergy = pvar;
		else if( !strcmp(pstr,"ENERGYPERTANK") )
			Energypt = pvar;
		else if( !strcmp(pstr,"TANKDAMAGE") )
			Tdamage = pvar;
		else if( !strcmp(pstr,"TANKMAXENERGY") )
			Tmaxenergy = pvar;
		else if( !strcmp(pstr,"DMGREGENPRI") )
			Regenpri = pvar;
		else if( !strcmp(pstr,"DMGREGENAMT") )
			Regenamt = pvar;
		else
			(void)fprintf(stderr,"load_profile: line %d invalid\n",ln);

		ln++;
	}

	(void)fclose(fp);
	return 0;
}

/* Lint Output
*/
