/*
 * GenSPkt.c 
 *
 * Kevin O'Connor 10/3/97
 *
 * Provides the means to generate server packets.
 *
 * Code to establish connection, maintain connection, and to send
 * packets remains in socket.c.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <signal.h>
#include "defs.h"
#include INC_UNISTD
#include INC_STRINGS
#include INC_SYS_SELECT
#include "struct.h"
#include "data.h"
#include "packets.h"
#include "proto.h"

#define FALSE 0
#define TRUE 1

/* file scope prototypes */
static void updateVPlayer(struct player_spacket *p);
static void sendVPlayers(void);
void sendVPlanets(void);
void sendVKills(void);


int sizes[TOTAL_SPACKETS] = {
    0,	/* record 0 */
    sizeof(struct mesg_spacket),		/* SP_MESSAGE */
    sizeof(struct plyr_info_spacket), 		/* SP_PLAYER_INFO */
    sizeof(struct kills_spacket),		/* SP_KILLS */
    sizeof(struct player_spacket),		/* SP_PLAYER */
    sizeof(struct torp_info_spacket),		/* SP_TORP_INFO */
    sizeof(struct torp_spacket), 		/* SP_TORP */
    sizeof(struct phaser_spacket),		/* SP_PHASER */
    sizeof(struct plasma_info_spacket),		/* SP_PLASMA_INFO */
    sizeof(struct plasma_spacket),		/* SP_PLASMA */
    sizeof(struct warning_spacket),		/* SP_WARNING */
    sizeof(struct motd_spacket),		/* SP_MOTD */
    sizeof(struct you_spacket),			/* SP_YOU */
    sizeof(struct queue_spacket),		/* SP_QUEUE */
    sizeof(struct status_spacket),		/* SP_STATUS */
    sizeof(struct planet_spacket),		/* SP_PLANET */
    sizeof(struct pickok_spacket),		/* SP_PICKOK */
    sizeof(struct login_spacket),		/* SP_LOGIN */
    sizeof(struct flags_spacket),		/* SP_FLAGS */
    sizeof(struct mask_spacket),		/* SP_MASK */
    sizeof(struct pstatus_spacket),		/* SP_PSTATUS */
    sizeof(struct badversion_spacket),		/* SP_BADVERSION */
    sizeof(struct hostile_spacket),		/* SP_HOSTILE */
    sizeof(struct stats_spacket),		/* SP_STATS */
    sizeof(struct plyr_login_spacket),		/* SP_PL_LOGIN */
    sizeof(struct reserved_spacket), 		/* SP_RESERVED */
    sizeof(struct planet_loc_spacket),		/* SP_PLANET_LOC */
    sizeof(struct scan_spacket),		/* SP_SCAN (ATM) */
    sizeof(struct udp_reply_spacket),		/* SP_UDP_REPLY */
    sizeof(struct sequence_spacket),		/* SP_SEQUENCE */
    sizeof(struct sc_sequence_spacket),		/* SP_SC_SEQUENCE */
#ifdef RSA
    sizeof(struct rsa_key_spacket),		/* SP_RSA_KEY */
#else
    0,						/* 31 */
#endif
    0,						/* 32 */
    0,						/* 33 */
    0,						/* 34 */
    0,						/* 35 */
    0,						/* 36 */
    0,						/* 37 */
    0,						/* 38 */
    sizeof(struct ship_cap_spacket),		/* SP_SHIP_CAP */
    sizeof(struct shortreply_spacket),          /* SP_S_REPLY */
    -1,                                         /* SP_S_MESSAGE */
    sizeof(struct warning_s_spacket),           /* SP_S_WARNING */
    sizeof(struct you_short_spacket),		/* SP_S_YOU */
    sizeof(struct youss_spacket),               /* SP_S_YOU_SS */
    -1, /* variable */                          /* SP_S_PLAYER */
#ifdef PING
    sizeof(struct ping_spacket),                /* SP_PING */
#else
    0,						/* SP_PING */
#endif
    -1, /* variable */                          /* SP_S_TORP  */
    -1, /* variable */				/* SP_S_TORP_INFO */
    20,                                         /* SP_S_8_TORP */
    -1, /* variable */                          /* SP_S_PLANET */
    0,						/* 51 */
    0,						/* 52 */
    0,						/* 53 */
    0,						/* 54 */
    0,						/* 55 */
    0,						/* 56 */
    -1, /* variable  S_P2 */			/* SP_S_PHASER */
    -1, /* variable */				/* SP_S_KILLS */
    sizeof (struct stats_s_spacket),           /* SP_S_STATS */
#ifdef FEATURE_PACKETS
    sizeof(struct feature_spacket),		/* SP_FEATURE */
#else
    0,						/* 60 */
#endif
    0,						/* 61 */
};

struct plyr_info_spacket clientPlayersInfo[MAXPLAYER];
struct plyr_login_spacket clientLogin[MAXPLAYER];
struct hostile_spacket clientHostile[MAXPLAYER];
struct stats_spacket clientStats[MAXPLAYER];
struct player_spacket clientPlayers[MAXPLAYER];
struct kills_spacket clientKills[MAXPLAYER];
struct flags_spacket clientFlags[MAXPLAYER];
struct pstatus_spacket clientPStatus[MAXPLAYER];
int msgCurrent;
struct torp_info_spacket clientTorpsInfo[MAXPLAYER*MAXTORP];
struct torp_spacket clientTorps[MAXPLAYER*MAXTORP];
struct phaser_spacket clientPhasers[MAXPLAYER];
struct phaser_s_spacket client_s_Phasers[MAXPLAYER];
struct you_spacket clientSelf;
struct status_spacket clientStatus;
struct planet_spacket clientPlanets[MAXPLANETS];
struct planet_loc_spacket clientPlanetLocs[MAXPLANETS];
struct plasma_info_spacket clientPlasmasInfo[MAXPLAYER*MAXPLASMA];
struct plasma_spacket clientPlasmas[MAXPLAYER*MAXPLASMA];
int mustUpdate[MAXPLAYER];


struct youss_spacket		clientSelfShip;
struct you_short_spacket	clientSelfShort;

/* HW */
u_char clientVPlanets[MAXPLANETS*sizeof(struct planet_s_spacket)+2 +6];
int    clientVPlanetCount;
static int	vtsize[9] ={ 4,8,8,12,12,16,20,20,24 }; /* How big is the
							 * SP_S_TORP packet */
static int	vtdata[9] ={0,3,5,7,9,12,14,16,18 }; /* How big is Torpdata */
static int	mustsend;    /* Flag to remind me that i must send SP_S_TORP */

static u_char	clientVTorps[40];

static u_char	clientVTorpsInfo[16];

static u_char    clientVPlayers[MAXPLAYER*VPLAYER_SIZE + 16];

/* S_P2 */
u_char clientVKills[MAXPLAYER*2+2 +4];
int clientVKillsCount;
struct stats_s_spacket singleStats;
unsigned char n_flags[MAXPLAYER]; 
int highest_active_player;

#if MAXPLAYER > 32
static u_char	clientVXPlayers[33*4];
#endif
static int	clientVPlayerCount;
static int	clientVXPlayerCount;
static int	big;

extern int ignored[];

/* Variables referenced from Socket.c */
extern int sizes[];
extern int use_newyou;
extern int f_many_self;
typedef void * PTR;			/* adjust this if you lack (void *) */
typedef struct fat_node_t {
    PTR packet;
    int pkt_size;
    struct fat_node_t *prev;
    struct fat_node_t *next;
} FAT_NODE;


/*****  Low level checks for packets *****/

#define UPDT_ALL 0
#define UPDT_MOST 1
#define UPDT_MANY 2
#define UPDT_LITTLE 3
#define UPDT_LEAST 4

int sndLogin( struct plyr_login_spacket* login, struct player* pl)
{
    if ( strcmp(pl->p_name, login->name)!=0 ||
	 pl->p_stats.st_rank != login->rank ||
	 strcmp(pl->p_monitor, login->monitor)!=0) {
	STRNCPY(login->name,pl->p_name,NAME_LEN);
	STRNCPY(login->monitor,pl->p_monitor,NAME_LEN);
	STRNCPY(login->login,pl->p_login,NAME_LEN);
	login->name[NAME_LEN-1]=0;
	login->monitor[NAME_LEN-1]=0;
	login->login[NAME_LEN-1]=0;
	login->type=SP_PL_LOGIN;
	login->pnum=pl->p_no;
	login->rank=pl->p_stats.st_rank;
	sendClientPacket(login);
	return (TRUE);
    }
    return (FALSE);
}

inline static int
sndHostile( struct hostile_spacket *hostile, struct player *pl, int howmuch)
{
    if (howmuch == UPDT_ALL) {
	if ( (pl->p_swar != hostile->war)
	     || (pl->p_hostile != hostile->hostile)) {
	    hostile->type=SP_HOSTILE;
	    hostile->war=pl->p_swar;
	    hostile->hostile=pl->p_hostile;
	    hostile->pnum=pl->p_no;
	    sendClientPacket(hostile);
	    return (TRUE);
	}
    } else {
	if ( (pl->p_swar & me->p_team)!=hostile->war
	     || (pl->p_hostile & me->p_team)!=hostile->hostile) {
	    hostile->type=SP_HOSTILE;
	    hostile->war=(pl->p_swar & me->p_team);
	    hostile->hostile=(pl->p_hostile & me->p_team);
	    hostile->pnum=pl->p_no;
	    sendClientPacket(hostile);
	    return (TRUE);
	}
    }
    return (FALSE);
}

int sndPlayerInfo( struct plyr_info_spacket *cpli, struct player *pl)
{
    if (pl->p_ship.s_type != cpli->shiptype ||
	pl->p_team != cpli->team) {
	cpli->type=SP_PLAYER_INFO;
	cpli->pnum=pl->p_no;
	cpli->shiptype=pl->p_ship.s_type;
	cpli->team=pl->p_team;
	sendClientPacket(cpli);
	return (TRUE);
    }
    return (FALSE);
}

inline static int updtKills( struct kills_spacket *kills, struct player *pl)
{
    if ( kills->kills != htonl((int) (pl->p_kills*100))) {
	kills->type=SP_KILLS;
	kills->pnum=pl->p_no;
	kills->kills=htonl((int) (pl->p_kills*100));
	return (TRUE);
    }
    return (FALSE);
}

inline static void addVKills( struct player *pl)
{
    /* S_P2 */
    static unsigned char *vkills;
    unsigned short shiftkills;

    if (!clientVKillsCount)
	vkills = &clientVKills[2];

    clientVKillsCount++;
    shiftkills = pl->p_kills * 100;
    shiftkills |= (pl->p_no << 10);
    *vkills++ = (unsigned char) shiftkills & 0xff;
    *vkills++ = (shiftkills >> 8) & 0xff; 		
}

int sndKills( struct kills_spacket *kills, struct player *pl)
{
    if (updtKills(kills, pl)) {
	/* S_P2 */
	if (send_short > 1 && (pl->p_kills*100 < 1001) && pl->p_no < 64)
	    addVKills(pl);
	else
	    sendClientPacket(kills);
	return (TRUE);
    }
    return (FALSE);
}

void sendVKills(void)
{
    if ( clientVKillsCount) {
	clientVKills[0] = SP_S_KILLS;
	clientVKills[1] = (unsigned char) clientVKillsCount;
	clientVKillsCount = 2+ (clientVKillsCount *2);
	if((clientVKillsCount % 4) != 0)
	    clientVKillsCount += (4 - (clientVKillsCount % 4));

	sizes[SP_S_KILLS] = clientVKillsCount;
	sendClientPacket((struct kills_spacket *) clientVKills);
    }

}

inline static int
sndFlags( struct flags_spacket *flags, struct player *pl, int howmuch)
{
/*#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) atm mask */

/* #define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFBEAMUP|PFBEAMDOWN|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK) aieee, too much.  7/27/91 TC */ 

#define FLAGMASK (PFSHIELD|PFBOMB|PFORBIT|PFCLOAK|PFROBOT|PFPRACTR|PFDOCK|PFTRACT|PFPRESS|PFDOCKOK)
#define INVISOMASK (PFCLOAK|PFROBOT|PFPRACTR|PFDOCKOK)

    int mask;

    if (howmuch == UPDT_ALL)
	mask = FLAGMASK;
    else
	mask = INVISOMASK;

    if (flags->flags != htonl(mask & pl->p_flags)) {
	flags->type=SP_FLAGS;
	flags->pnum=pl->p_no;
	flags->flags=htonl(mask & pl->p_flags);

	/* ATM - visible tractor */
	/* flags->tractor = (char) pl->p_tractor |0x40; */

	/* S_P2 */
	if(send_short < 2 || pl->p_ship.s_type == STARBASE
	   || pl->p_no > 31 || (pl->p_flags & PFROBOT))
	    sendClientPacket(flags);
	return (TRUE);
    }
    return (FALSE);
}

int sndPStatus( struct pstatus_spacket *pstatus, struct player *pl)
{
    if (pstatus->status != pl->p_status) {
	/* We update the location of people whose status has changed.
	 * (like if they just re-entered...)
	 */
#ifdef OBSERVERS
	int pobserv = 0;
#endif
	pstatus->type=SP_PSTATUS;
	pstatus->pnum=pl->p_no;
	pstatus->status=pl->p_status;
#ifdef OBSERVERS
	/* Some clients do not know about POBSERV, so we mask it into a
	   known status ... for observers we tell them they are alive,
	   but for everybody else we say they are outfitting.  Quozl */
	if (pl->p_status == POBSERV) {
	    if (pl == me) 
		pstatus->status = PALIVE;
	    else
		pstatus->status = POUTFIT;
	    pobserv = 1;
	}
#endif
	/* S_P2 */
	if ( send_short < 2
#ifdef OBSERVERS
	     || pobserv
#endif
	     || pl->p_no > 31
	     || pl->p_flags & PFROBOT
	     || pstatus->status != PALIVE
	     || pstatus->status != PEXPLODE
	     || pstatus->status != PDEAD)

/* WTF?  This if always tests true??? */

	    sendClientPacket(pstatus);
	if (dead_warp) dead_warp = 1;
#ifdef OBSERVERS
	if (pobserv)
	    pstatus->status = POBSERV;
#endif
	return(TRUE);
    }
    return (FALSE);
}

int updtPlayer( struct player_spacket *cpl, struct player *pl, int howmuch)
/* UPDT_ALL   : If needed send accurate position; accurate speed. (normal)
 * UPDT_MOST  : If needed send accurate position; speed = 15      (cloaking)
 * UPDT_MANY  : If needed send inacurate position; speed = 15     (cloaked)
 * UPDT_LITTLE: If needed send outdated packet              (cloaked; no update)
 * UPDT_LEAST : If needed send bogus position (-10000);     (player hidden)
 */
{
    if ( howmuch == UPDT_LEAST ) {
	if (ntohl(cpl->x) == -10000 && ntohl(cpl->y) == -10000)
	    return (FALSE);

	/* Make player disappear */
	cpl->type = SP_PLAYER;
	cpl->x = cpl->y = htonl(-10000);
	cpl->pnum = pl->p_no;

	/* FEATURE: dead_warp */
	if ( (pl->p_status == PDEAD || pl->p_status == PEXPLODE) && 
	     dead_warp) {
	    cpl->dir = dead_warp++;
	    cpl->speed = 0xe;                   /* 14 = dead */
	} else {
	    cpl->dir = 0;
	    cpl->speed = 0;
	}
	return (TRUE);
    }

    if ( pl->p_x != ntohl(cpl->x) || pl->p_y != ntohl(cpl->y)
	 || pl->p_dir != cpl->dir || pl->p_speed != cpl->speed) {

	/* FEATURE: dead_warp */
	if ( (pl->p_status == PDEAD || pl->p_status == PEXPLODE)
	     && dead_warp) {
	    cpl->type=SP_PLAYER;
	    cpl->pnum=pl->p_no;
	    cpl->dir = dead_warp++;
	    cpl->speed = 0xe;                   /* 14 = dead */
	    cpl->x = cpl->y = htonl(-10000);
	    return (TRUE);
	}

	if (howmuch == UPDT_LITTLE) {
	    /* NEW: Send old position again */
	    return(TRUE);
	}

	cpl->type=SP_PLAYER;
	cpl->pnum=pl->p_no;

	if (howmuch == UPDT_MANY) {
	    cpl->speed = 0xf;   /* NEW: Joe Rumsey, 15 == cloaked */
#ifdef AS_CLOAK
	    if (pl->p_ship.s_type == ASSAULT) {
		cpl->x=htonl(pl->p_x+(random() % 3000)-1500);
		cpl->y=htonl(pl->p_y+(random() % 3000)-1500);
	    } else
#endif
	    {
		cpl->x=htonl(pl->p_x+(random() % 2000)-1000);
		cpl->y=htonl(pl->p_y+(random() % 2000)-1000);
	    }
	} else {
	    cpl->dir = pl->p_dir;
	    cpl->x = htonl(pl->p_x);
	    cpl->y = htonl(pl->p_y);
	    if (howmuch == UPDT_ALL)
		cpl->speed = pl->p_speed;
	    else
		/* Feature: CLOAK_MAXWARP */
		cpl->speed = 0xf;   /* NEW: Joe Rumsey, 15 == cloaked */
	}

	return (TRUE);
    }
    return(FALSE);
}

inline static int
sndPlayer( struct player_spacket *cpl, struct player *pl, int howmuch)
{
    if (updtPlayer(cpl, pl, howmuch)) {
	if (send_short)
	    updateVPlayer(cpl);
	else
	    sendClientPacket(cpl);
	return (TRUE);
    }
    return (FALSE);
}

int sndSelfShip(struct youss_spacket *self, struct player *pl)
{
    if(ntohs(self->damage) != pl->p_damage ||
       ntohs(self->shield) != pl->p_shield ||
       ntohs(self->fuel) != pl->p_fuel ||
       ntohs(self->etemp) != pl->p_etemp ||
       ntohs(self->wtemp) != pl->p_wtemp) {

	self->type = SP_S_YOU_SS;

	if (f_many_self)
	    self->pad1 = pl->p_no;
	else
	    /* FEATURE SELF_8FLAGS */
	    self->pad1 = pl->p_flags & 255; /* For future use */

	self->damage=htons(pl->p_damage);
	self->shield=htons(pl->p_shield);
	self->fuel=htons(pl->p_fuel);
	self->etemp=htons(pl->p_etemp);
	self->wtemp=htons(pl->p_wtemp);
	sendClientPacket((CVOID) self);
	return (TRUE);
    }
    return (FALSE);
}

int sndTorp(struct torp_info_spacket *tpi, struct torp_spacket *tp,
	    struct torp *t, int i, int howmuch)
{
    /*
     * If it was free before, and is still, do nothing.   */
    if ((t->t_status == TFREE) && (tpi->status == TFREE))
	return (FALSE);

    if (howmuch == UPDT_ALL) {
	if ((t->t_war != tpi->war) || (t->t_status != tpi->status)) {
	    tpi->type   = SP_TORP_INFO;
	    tpi->war    = t->t_war;
	    tpi->status = t->t_status;
	    tpi->tnum   = htons(i);
	    sendClientPacket(tpi);
/*	    return (TRUE);*/
	}
	if ((tp->x != htonl(t->t_x)) || (tp->y != htonl(t->t_y))) {
	    tp->type = SP_TORP;
	    tp->x    = htonl(t->t_x);
	    tp->y    = htonl(t->t_y);
	    tp->dir  = t->t_dir;
	    tp->tnum = htons(i);
	    sendClientPacket(tp);
	    return (TRUE);
	}
    } else if (howmuch == UPDT_MOST) {
	tp->type = SP_TORP;
	tp->x    = htonl(t->t_x);
	tp->y    = htonl(t->t_y);
	tp->tnum = htons(i);
	sendClientPacket(tp);
	if ( (t->t_status != tpi->status)
	     || ((t->t_war & me->p_team) != tpi->war)) {
	    tpi->type   = SP_TORP_INFO;
	    tpi->war    = t->t_war & me->p_team;
	    tpi->tnum   = htons(i);
	    tpi->status = t->t_status;
	    sendClientPacket(tpi);
	}
	return (TRUE);
    } else {
	if ((t->t_status == TFREE) && (tpi->status == TEXPLODE)) {
	    tpi->status = TFREE;
	    return (FALSE);
	}
	if (tpi->status != TFREE) {
	    tpi->type   = SP_TORP_INFO;
	    tpi->status = TFREE;
	    tpi->tnum   = htons(i);
	    sendClientPacket(tpi);
	    return (TRUE);
	}
    }
    return (FALSE);
}

int sndPlasma(struct plasma_info_spacket *tpi, struct plasma_spacket *tp,
	      struct torp *t, int i, int howmuch)
{
    /*
     * If it was free before, and is still, do nothing.   */
    if ((t->t_status == TFREE) && (tpi->status == TFREE))
	return (FALSE);

    if (howmuch == UPDT_ALL) {
	if ((t->t_war != tpi->war) || (t->t_status != tpi->status)) {
	    tpi->type   = SP_PLASMA_INFO;
	    tpi->war    = t->t_war;
	    tpi->status = t->t_status;
	    tpi->pnum   = htons(i);
	    sendClientPacket(tpi);
/*	    return (TRUE);*/
	}
	if ((tp->x != htonl(t->t_x)) || (tp->y != htonl(t->t_y))) {
	    tp->type = SP_PLASMA;
	    tp->x    = htonl(t->t_x);
	    tp->y    = htonl(t->t_y);
	    tp->pnum = htons(i);
	    sendClientPacket(tp);
	    return (TRUE);
	}
    } else if (howmuch == UPDT_MOST) {
	tp->type = SP_PLASMA;
	tp->x    = htonl(t->t_x);
	tp->y    = htonl(t->t_y);
	tp->pnum = htons(i);
	sendClientPacket(tp);
	if ( (t->t_status != tpi->status)
	     || ((t->t_war & me->p_team) != tpi->war)) {
	    tpi->type   = SP_PLASMA_INFO;
	    tpi->war    = t->t_war & me->p_team;
	    tpi->pnum   = htons(i);
	    tpi->status = t->t_status;
	    sendClientPacket(tpi);
	}
	return (TRUE);
    } else {
	if ((t->t_status == TFREE) && (tpi->status == TEXPLODE)) {
	    tpi->status = TFREE;
	    return (FALSE);
	}
	if (tpi->status != TFREE) {
	    tpi->type   = SP_PLASMA_INFO;
	    tpi->status = TFREE;
	    tpi->pnum   = htons(i);
	    sendClientPacket(tpi);
	    return (TRUE);
	}
    }
    return (FALSE);
}

inline static int
updtPhaser(struct phaser_spacket *ph, struct phaser *phase,
	   int i, int howmuch)
{
    if (howmuch == UPDT_ALL) {
	if ( ph->status!=phase->ph_status
	     || ph->dir!=phase->ph_dir
	     || ph->target!=htonl(phase->ph_target)) { 
	    ph->pnum=i;
	    ph->type=SP_PHASER;
	    ph->status=phase->ph_status;
	    ph->dir=phase->ph_dir;
	    ph->x=htonl(phase->ph_x);
	    ph->y=htonl(phase->ph_y);
	    ph->target=htonl(phase->ph_target);
	    return (TRUE);
	}
    } else {
	if (ph->status!=PHFREE) {
	    ph->pnum=i;
	    ph->type=SP_PHASER;
	    ph->status=PHFREE;
	    return (TRUE);
	}
    }
    return (FALSE);
}

inline static int
addVPhaser(struct phaser_spacket *ph, struct phaser_s_spacket *phs,
	   struct phaser *phase, int i, int howmuch)
{
    unsigned char damage;

    /* get rid of annoying compiler message */
    if (howmuch) ;

    switch(ph->status)
    {
    case PHFREE:
	phs->pnum = i;
	phs->type = SP_S_PHASER;
	phs->status = PHFREE;
	sizes[SP_S_PHASER] = 4;
	sendClientPacket (phs);
	break;
    case PHHIT:
	if(phase->ph_damage > 255)
	    damage = 255; /* Could be used as flag */
	else
	    damage = phase->ph_damage;
	phs->pnum = (i & 0x3f)| (damage & 0x30) << 2 ;
	phs->type = SP_S_PHASER;
	phs->status = (unsigned char)ph->status |(damage & 0x0f) << 4;
	phs->target = (phase->ph_target & 0x3f)|(damage & 192); 
	sizes[SP_S_PHASER] = 4;
	sendClientPacket (phs);
	break;
    case PHMISS:
	phs->pnum = i;
	phs->type = SP_S_PHASER;
	phs->status = ph->status;
	phs->target = ph->dir; /* Do not get confused */ 
	sizes[SP_S_PHASER] = 4;
	sendClientPacket (phs);
	break;
    case PHHIT2:
	phs->pnum = i;
	phs->type = SP_S_PHASER;
	phs->status = ph->status;
	phs->x = htons ((phase->ph_x+SCALE/2) / SCALE);
	phs->y = htons ((phase->ph_y+SCALE/2) / SCALE);
	phs->target = phase->ph_target; 
	sizes[SP_S_PHASER]= 8;
	sendClientPacket (phs);
	break;
    default:
	phs->pnum = i;
	phs->type = SP_S_PHASER;
	phs->status = ph->status;
	phs->dir = ph->dir;
	phs->x = htons ((phase->ph_x+SCALE/2) / SCALE);
	phs->y = htons ((phase->ph_y+SCALE/2) / SCALE);
	phs->target = phase->ph_target; 
	sizes[SP_S_PHASER]= sizeof(struct phaser_s_spacket);
	sendClientPacket (phs);
	break;
    }
    return (TRUE);
}

int sndPhaser(struct phaser_spacket *ph, struct phaser_s_spacket *phs,
	      struct phaser *phase, int i, int howmuch)
{
    if (updtPhaser(ph, phase, i, howmuch)) {
	if ( send_short > 1 && (!(ph->status & 0xf0))
#if MAXPLAYER >= 65
	     && i < 64
#endif
	    )
	    addVPhaser(ph, phs, phase, i, howmuch);
	else
	    sendClientPacket(ph);
	return (TRUE);
    }
    return (FALSE);
}

inline static int
updtPlanet(struct planet_spacket *pl, struct planet *plan, int howmuch)
{

#define PLFLAGMASK (PLREPAIR|PLFUEL|PLAGRI|PLHOME|PLCOUP)

    if (howmuch == UPDT_ALL) {
	if ( pl->info != plan->pl_info
	     || pl->armies != htonl(plan->pl_armies)
	     || pl->owner != plan->pl_owner
	     || pl->flags != htons((short) (plan->pl_flags & PLFLAGMASK))) {
	    pl->type=SP_PLANET;
	    pl->pnum=plan->pl_no;
	    pl->info=plan->pl_info;
	    pl->flags=htons((short) (plan->pl_flags & PLFLAGMASK));
	    pl->armies=htonl(plan->pl_armies);
	    pl->owner=plan->pl_owner;
	    return (TRUE);
	} 
    } else {
	if (pl->info & me->p_team) {
	    pl->type=SP_PLANET;
	    pl->pnum=plan->pl_no;
	    pl->info=0;
	    pl->flags=0;
	    pl->armies=0;
	    pl->owner=0;
	    return (TRUE);
	}
    }
    return (FALSE);
}

inline static int
addVPlanet(struct planet_spacket *pl)
{
    static struct planet_s_spacket *npl;

    if (!clientVPlanetCount)
	npl = (struct planet_s_spacket *) &clientVPlanets[2];
    npl->pnum=pl->pnum;
    npl->info=pl->info;
    npl->flags=pl->flags;
    npl->armies=(u_char) pl->armies;
    npl->owner=pl->owner;
    npl++;
    clientVPlanetCount++;
    return (TRUE);
}

int sndPlanet(struct planet_spacket *pl, struct planet *plan, int howmuch)
{
    if (updtPlanet(pl, plan, howmuch)) {
	if ( send_short  && pl->armies < 256 )
	    addVPlanet(pl);
	else
	    sendClientPacket(pl);
	return (TRUE);
    }
    return (FALSE);
}

void
sendVPlanets(void)
{
    if (clientVPlanetCount != 0) {
	clientVPlanets[0] = SP_S_PLANET; /* The type */
	clientVPlanets[1] = clientVPlanetCount;
	clientVPlanetCount = 2 +(clientVPlanetCount * 6);
	/* make sure on machine word boundary (assuming 4 bytes per word) */
	if((clientVPlanetCount % 4) != 0)
	    clientVPlanetCount += (4 - (clientVPlanetCount % 4));

	sizes[SP_S_PLANET] = clientVPlanetCount;
	sendClientPacket((struct planet_spacket *) clientVPlanets);
    }
}

int sndPlanetLoc(struct planet_loc_spacket *pll, struct planet *plan)
{
    if ((pll->x != htonl(plan->pl_x)) || (pll->y != htonl(plan->pl_y))) {
	pll->x=htonl(plan->pl_x);
	pll->y=htonl(plan->pl_y);
	pll->pnum=plan->pl_no;
	strcpy(pll->name, plan->pl_name);
	pll->type=SP_PLANET_LOC;
	sendClientPacket(pll);
	return (TRUE);
    }
    return (FALSE);
}

int updtMessageSMessage(struct message *cur)
{
    switch(cur->args[0]) {
    case DMKILL:
	if ( cur->args[3] < 32000 && cur->args[4] < 32
	     && cur->args[1] < 64 && cur->args[2] < 64 ) {
	    u_short tmp;

	    tmp= cur->args[3] | 
		((cur->args[4] & 16) << 11);
	    swarning(KILLARGS,(u_char)(tmp & 0xff),
		     (u_char)((tmp >> 8) & 0xff));
#ifdef CHAIN_REACTION
	    if (why_dead) {
		swarning(KILLARGS2,(u_char)cur->args[5],0);
	    }
#endif
	    tmp= (u_char)(cur->args[2] |
			  ((cur->args[4] & 12)<< 4));
	    swarning(DMKILL,(u_char)(cur->args[1]
				     | ((cur->args[4] & 3)<< 6)), tmp);
	    return(TRUE);
	}
	break;
    case KILLARGS: /* Only to help the compiler */
	break;
    case KILLARGS2: /* Only to help the compiler */
	break;
    case DMKILLP:
#ifdef CHAIN_REACTION
	if (why_dead) {
	    swarning(KILLARGS2,(u_char)cur->args[5],0);
	}
#endif
	swarning(DMKILLP, (u_char)cur->args[1], (u_char)cur->args[2]);
	return(TRUE);
    case DMBOMB:
	swarning(ARGUMENTS, (u_char)cur->args[2],0); /* Damage */
	swarning(DMBOMB, (u_char)cur->args[1], (u_char)cur->args[3]); /* To get the vital info in one packet */
	return(TRUE);
    case DMDEST:
	swarning(DMDEST, (u_char)cur->args[1], (u_char)cur->args[2]);
	return(TRUE);
    case DMTAKE:
	swarning(DMTAKE, (u_char)cur->args[1], (u_char)cur->args[2]);
	return(TRUE);
    case DGHOSTKILL:
	if(cur->args[2] < 64000){
	    swarning(KILLARGS,(u_char)(cur->args[2] & 0xff), (u_char)((cur->args[2] >> 8) & 0xff));
#ifdef CHAIN_REACTION
	    if (why_dead) {
		swarning(KILLARGS2,(u_char)cur->args[5],0);
	    }
#endif
	    swarning(DGHOSTKILL, (u_char)cur->args[1], 0);
	    return(TRUE);
	}
	break;
    case SVALID:      /* We can send it over SP_S_MESSAGE HW */
	break;
    case SINVALID:    /* Can't be send over SP_S_MESSAGE */
	break;

    default:
	/* I must test if the message from GOD has a real header (== "GOD->") */
	/* This tests gets all messages from tools */
	if (strstr(cur->m_data,"GOD->") != NULL)
	    cur->args[0] = SVALID; /* It has a real header */
	break;
    }
    return(FALSE);
}

void updtMessage(struct mesg_spacket *msg, struct message *cur)
{
    if ( send_short && (cur->m_from < MAXPLAYER || cur->args[0] == SVALID)
	 && (!(cur->m_flags & MLEAVE)) ) {
	/* This is the SAFE version.(All playermessages must have an header.)
	 * It's nicer without MLEAVE */

	struct mesg_s_spacket *shortmsg = (struct mesg_s_spacket *) msg;
	int size;

	shortmsg->type = SP_S_MESSAGE;
	shortmsg->m_flags=cur->m_flags;
	shortmsg->m_recpt=cur->m_recpt;
	shortmsg->m_from=cur->m_from;
	cur->m_data[MSG_LEN-1]='\0'; /* Is this all right ? */
	strcpy(&shortmsg->mesg,&cur->m_data[9]); /* 9 because of GOD messages */
	/* Now the size */
	size = strlen(&shortmsg->mesg);
	size += 6; /* 1 for '\0', 5 packetheader */
	if((size % 4) != 0)
	    size += (4 - (size % 4));
	shortmsg->length = size;
	sizes[SP_S_MESSAGE] = size;
    }
    else {
	msg->type=SP_MESSAGE;
	STRNCPY(msg->mesg, cur->m_data, MSG_LEN);
	msg->mesg[MSG_LEN-1]='\0';
	msg->m_flags=cur->m_flags;
	msg->m_recpt=cur->m_recpt;
	msg->m_from=cur->m_from;

#ifdef RCD
	/* kludge for clients that can't handle RCD's */
	/* if I understood heiko's short_packet code I would put this in
	   the above ... but I dont - jmn */

	if ((cur->m_recpt == me->p_team) && !me->gen_distress && 
	    (cur->m_flags == (MTEAM | MDISTR | MVALID))) {

	    struct distress dist;
	    char buf[MSG_LEN];

	    buf[0] = '\0';
	    msg->m_flags ^= MDISTR; /* get rid of MDISTR flag so client
				      isn't confused */
	    HandleGenDistr(cur->m_data,cur->m_from,cur->m_recpt,&dist);
	    makedistress(&dist,buf,distmacro[dist.distype].macro);
	    /* note that we do NOT send the F0->FED part 
	       so strncat is fine */
	    strcpy(msg->mesg, buf);
	}
#endif

    }
    if (cur->m_from==DOOSHMSG) msg->m_from=255;	/* god */
    sendClientPacket((CVOID) msg);
}

/* End of low level packet update routines */

void
updateStatus(int force)
/* if force is false, packet only sent when status->tourn changes */
{
/* Update status every 10 seconds? */
    if (repCount % efticks(50) == 0)
	if ( clientStatus.tourn != status->tourn
	     || (force && (ntohl(clientStatus.timeprod) != timeprod_int()))) {

	    clientStatus.type=SP_STATUS;
	    clientStatus.tourn=status->tourn;
	    clientStatus.armsbomb=htonl(status->armsbomb/10);
	    clientStatus.planets=htonl(status->planets/10);
	    clientStatus.kills=htonl(status->kills/10);
	    clientStatus.losses=htonl(status->losses/10);
	    clientStatus.time=htonl(status->time/10);
	    clientStatus.timeprod=htonl(timeprod_int());
	    sendClientPacket((CVOID) &clientStatus);
	}
}

int sndSSelf(struct you_short_spacket *youp, struct player* pl, int howmuch)
{
    if ( howmuch == UPDT_ALL
	 || youp->pnum != pl->p_no
	 || youp->hostile != pl->p_hostile
	 || youp->swar != pl->p_swar
	 || youp->armies != pl->p_armies
	 || youp->whydead != pl->p_whydead
	 || youp->whodead != pl->p_whodead
	 || ntohl(youp->flags) != pl->p_flags ) {
	youp->type = SP_S_YOU;
	youp->pnum = pl->p_no;
	youp->hostile = pl->p_hostile;
	youp->swar = pl->p_swar;
	youp->armies = pl->p_armies;
	youp->whydead = pl->p_whydead;
	youp->whodead = pl->p_whodead;
	youp->flags = htonl(pl->p_flags);
	sendClientPacket((CVOID) youp);
	return (TRUE);
    }
    return (FALSE);
}

inline static int
sndSelf(struct you_spacket* youp, struct player* pl, int howmuch)
{
    if ( howmuch == UPDT_ALL
	 || ntohl(youp->fuel) != pl->p_fuel
	 || ntohl(youp->shield) != pl->p_shield
	 || ntohl(youp->damage) != pl->p_damage
	 || ntohs(youp->etemp) != pl->p_etemp
	 || ntohs(youp->wtemp) != pl->p_wtemp
	 || ntohl(youp->flags) != pl->p_flags
	 || youp->armies != pl->p_armies
	 || youp->swar != pl->p_swar
	 || ntohs(youp->whydead) != pl->p_whydead
	 || ntohs(youp->whodead) != pl->p_whodead
	 || youp->pnum != pl->p_no) {

	/* we want to send it, but how? */
	youp->type = SP_YOU;

	if (commMode == COMM_UDP) {
	    if (    ntohl(youp->flags) != pl->p_flags ||
		    youp->armies != pl->p_armies ||
		    youp->swar != pl->p_swar) {
		youp->type=SP_YOU | 0x40;	/* mark as semi-critical */
	    }
	    if (    ntohs(youp->whydead) != pl->p_whydead ||
		    ntohs(youp->whodead) != pl->p_whodead ||
		    youp->pnum != pl->p_no) {
		youp->type=SP_YOU | 0x80;	/* mark as critical */
	    }
	}

	youp->pnum=pl->p_no;
	youp->flags=htonl(pl->p_flags);
	youp->swar=pl->p_swar;
	youp->hostile=pl->p_hostile;
	youp->armies=pl->p_armies;
	youp->shield=htonl(pl->p_shield);
	youp->fuel=htonl(pl->p_fuel);
	youp->etemp=htons(pl->p_etemp);
	youp->wtemp=htons(pl->p_wtemp);
	youp->whydead=htons(pl->p_whydead);
	youp->whodead=htons(pl->p_whodead);
	youp->damage=htonl(pl->p_damage);
	/* youp->tractor=(char)pl->p_tractor |0x40;		 ATM - visible tractor */
	sendClientPacket((CVOID) youp);
	return (TRUE);
    }
    return (FALSE);
}

void
updateSelf(int force)
/* If force is true, a packet will be guarenteed to be sent.
 */
{
    static int again = 0; /* Flag, SP_S_YOU is always (almost) send two times. *
			   * Because SP_S_YOU is now send via UDP  HW 27.06.93 */

    if(send_short &&  me->p_fuel < 61000  ) { /* A little margin ... */

	sndSelfShip(&clientSelfShip, me);

	{
	    /* Send Self using short packets */

	    if (!sndSSelf(&clientSelfShort, me, UPDT_MOST))
		if (again || force) {
		    sndSSelf(&clientSelfShort, me, UPDT_ALL);
		    if (!force)
			/* again - sortof boolean HW,sent SP_S_YOU again */
			again ^= 1;
		}
	}

    } else
	/* Send Self using normal packets */
	sndSelf(&clientSelf, me, force ? UPDT_ALL : UPDT_MOST);
}

void
updateShips(void)
{
    int i;
    struct player *pl;
    struct plyr_info_spacket *cpli;
    struct player_spacket *cpl;
    struct kills_spacket *kills;
    struct flags_spacket *flags;
    struct pstatus_spacket *pstatus;
    struct plyr_login_spacket *login;
    struct hostile_spacket *hostile;
    struct stats_spacket *stats;
    int update;

    clientVKillsCount = 0;
    highest_active_player = 0;
    /* S_P2 end */

    clientVPlayerCount = 12;
    clientVXPlayerCount = 4;
    clientVPlayers[1]   = 0; /* How many packets are in the Big... */
#if MAXPLAYER > 32
    clientVXPlayers[1] = 0;
#endif
    big=0;

    /* Please excuse the ugliness of this loop declaration */
    for (i=0, pl=players, cpli=clientPlayersInfo, cpl=clientPlayers,
	     kills=clientKills, flags=clientFlags, pstatus=clientPStatus,
	     login=clientLogin, hostile=clientHostile, stats=clientStats;
	 i<MAXPLAYER; 
	 i++, pl++, cpli++, cpl++, kills++, flags++, pstatus++, login++,
	     hostile++, stats++) {

	update=0;

	sndLogin(login, pl);

	if (pl==me)
	    sndHostile(hostile, pl, UPDT_ALL);
	else
	    sndHostile(hostile, pl, UPDT_MOST);

	sndPlayerInfo(cpli, pl);
	sndKills(kills, pl);

#ifdef OBSERVERS
	if(pl->p_status != POBSERV){
#endif
	    /* S_P2 new flag sampling */
	    if(!(pl->p_flags & PFROBOT)) { /* No robos please */
		switch(pl->p_status){
		case PALIVE: /* huh, we must work */
		    highest_active_player = i;
		    if(pl->p_flags & PFCLOAK){
			n_flags[i] = 1;
			break;
		    }
		    else if(pl->p_flags & PFSHIELD){
			n_flags[i] = 2;
		    }
		    else
			n_flags[i] = 3;
		    break;

		case PEXPLODE:
		case PDEAD:
		    highest_active_player = i;
		    n_flags[i] = 0;
		    break; 
		default: 
		    n_flags[i] = 0; 
		    /* Is it ok to send the old value ? */
		    break;
		}
	    } /* robos out */ 
#ifdef OBSERVERS
	}
#endif

	if (sndPStatus(pstatus, pl)) {
	    update=1;
	    if (pl->p_status == PFREE) { /* I think this will turn off ignores
					    for players that leave. 7/24/91 TC */
		extern int ignored[];
		ignored[i] = 0;
	    }
	}

	/* Used to send flags here, see below 8/7/91 TC */

	/* hidden enemies?  -- note OBSERVer is always inviso to everyone
	   else */

	if ( (hiddenenemy && pl->p_team != me->p_team
	      && !(pl->p_flags & PFSEEN) && status->tourn)
#ifdef OBSERVERS
	     || (pl->p_status == POBSERV && pl != me)
#endif
	    ) {

	    /* Player is invisible, send limited flags information,
	     * and bogus player position.
	     */

	    if (me!=pl)
		sndFlags(flags, pl, UPDT_MOST);

	    sndPlayer(cpl, pl, UPDT_LEAST);
	    continue;
	}

	if (me!=pl)
	    sndFlags(flags, pl, UPDT_ALL);

	/* We update the player if:
	 * 1) haven't updated him for 9 intervals.
	 * 2) he is on the screen
	 * 3) he was on the screen recently.
	 */
	if (!update && repCount % efticks(9) != 0 && 
	    (ntohl(cpl->x) < me->p_x - SCALE*WINSIDE/2 ||
	     ntohl(cpl->x) > me->p_x + SCALE*WINSIDE/2 ||
	     ntohl(cpl->y) > me->p_y + SCALE*WINSIDE/2 ||
	     ntohl(cpl->y) < me->p_y - SCALE*WINSIDE/2) &&
	    (pl->p_y > me->p_y + SCALE*WINSIDE/2 ||
	     pl->p_x > me->p_x + SCALE*WINSIDE/2 ||
	     pl->p_x < me->p_x - SCALE*WINSIDE/2 ||
	     pl->p_y < me->p_y - SCALE*WINSIDE/2)) continue;

	/* If the guy is cloaked, give information only occasionally,
	 *  and make it slightly inaccurate.
	 * Also, we don't give a direction.  The client has no reason
	 *  to know.
	 */
	if ( (pl->p_flags & PFCLOAK) && 
	     (pl->p_cloakphase == (CLOAK_PHASES - 1)) && 
	     (me != pl) && !mustUpdate[i]) {
	    if (repCount % efticks(9) != 0) {
		/* Player is cloaked on users screen,
		 * but is not ready for another update.
		 * Resend old packet.
		 */
		sndPlayer(cpl, pl, UPDT_LITTLE);
		continue;
	    }

	    /* Player is cloaked on users screen,
	     * update his position with innacurate location
	     */
	    sndPlayer(cpl, pl, UPDT_MANY);
	    continue;
	}
	if (pl != me && (pl->p_flags & PFCLOAK))
	    /* Player is cloaking on user screen */
	    sndPlayer(cpl, pl, UPDT_MOST);
	else
	    /* Send normal postion for player */
	    sndPlayer(cpl, pl, UPDT_ALL);
    }
    if(send_short && (clientVPlayerCount > 12 ||        clientVXPlayerCount > 4
		      || big != 0 || send_short > 1 /* S_P2 fl;agsampling */))
	sendVPlayers();

    /* S_P2 */
    if(send_short > 1)
	sendVKills();
}

void
updateTorps(void)
{
    struct torp *t;
    int i;
    struct torp_info_spacket *tpi;
    struct torp_spacket *tp;

    for (i=0, t=firstTorp, tpi=clientTorpsInfo, tp=clientTorps; 
	 t<=lastTorp; i++, t++, tpi++, tp++) {

	/*
	 * If it's my torp, send info on it regardless of position;
	 * my client needs the info to accurately display number of torps. */
	if (myTorp(t)) {
	    sndTorp(tpi, tp, t, i, UPDT_ALL);
	    continue;
	}

	/* 
	 * Not my torp.
	 * If not in view, only send limited information   */
	if ((t->t_y > me->p_y + SCALE*WINSIDE/2) ||
	    (t->t_y < me->p_y - SCALE*WINSIDE/2) ||
	    (t->t_x > me->p_x + SCALE*WINSIDE/2) ||
	    (t->t_x < me->p_x - SCALE*WINSIDE/2) ||
	    (t->t_status == TFREE)) {
	    sndTorp(tpi, tp, t, i, UPDT_LITTLE);
	    continue;
	} 

	/* 
	 * Not my torp, and in view.
	 * Send torp info (we assume it moved) */
	sndTorp(tpi, tp, t, i, UPDT_MOST);
    }
}

void
updatePlasmas(void)
{
    struct torp *t;
    int i;
    struct plasma_info_spacket *tpi;
    struct plasma_spacket *tp;

    for (i=0, t=firstPlasma, tpi=clientPlasmasInfo, tp=clientPlasmas; 
	 t<=lastPlasma; i++, t++, tpi++, tp++) {
	/*
	 * If it's my torp, send info on it regardless of position;
	 * my client needs the info to accurately display number of torps. */
	if (myTorp(t)) {
	    sndPlasma(tpi, tp, t, i, UPDT_ALL);
	    continue;
	}

	/* 
	 * Not my torp.
	 * If not in view, only send limited information   */
	if ((t->t_y > me->p_y + SCALE*WINSIDE/2) ||
	    (t->t_y < me->p_y - SCALE*WINSIDE/2) ||
	    (t->t_x > me->p_x + SCALE*WINSIDE/2) ||
	    (t->t_x < me->p_x - SCALE*WINSIDE/2) ||
	    (t->t_status == TFREE)) {
	    sndPlasma(tpi, tp, t, i, UPDT_LITTLE);
	    continue;
	} 

	/* 
	 * Not my torp, and in view.
	 * Send torp info (we assume it moved) */
	sndPlasma(tpi, tp, t, i, UPDT_MOST);
    }
}

void
updatePhasers(void)
{
    int i;
    struct phaser_spacket *ph;
    struct phaser *phase;
    struct player *pl;
    struct phaser_s_spacket *phs;

    /* Clear old mustUpdate values */
    for (i=0; i<MAXPLAYER; i++) {
	mustUpdate[i]=0;
    }

    for (i = 0, ph = clientPhasers,phs = client_s_Phasers,
	     phase = phasers, pl = players; 
	 i < MAXPLAYER; i++, ph++, phs++, phase++, pl++) { 
	if (pl->p_y > me->p_y + SCALE*WINSIDE/2 ||
	    pl->p_x > me->p_x + SCALE*WINSIDE/2 ||
	    pl->p_x < me->p_x - SCALE*WINSIDE/2 ||
	    pl->p_y < me->p_y - SCALE*WINSIDE/2) {
	    sndPhaser(ph, phs, phase, i, UPDT_LITTLE);
	} else {
	    if (phase->ph_status==PHHIT) {
		mustUpdate[phase->ph_target]=1;
	    }
	    sndPhaser(ph, phs, phase, i, UPDT_ALL);
	}
    }
}

void updatePlanets(void)
{
    int i;
    struct planet_spacket *pl;
    struct planet *plan;
    struct planet_loc_spacket *pll;

    clientVPlanetCount = 0;

    for (i=0, pl=clientPlanets, plan=planets, pll=clientPlanetLocs; 
	 i<MAXPLANETS;
	 i++, pl++, plan++, pll++) {
	/* Send him info about him not having info if he doesn't but thinks
	 *  he does.
	 * Also send him info on every fifth cycle if the planet needs to
	 *  be redrawn.
	 */
	if ((plan->pl_info & me->p_team)==0) {
	    sndPlanet(pl, plan, UPDT_LITTLE);
	} else if ( plan->pl_info & me->p_team ) {
	    sndPlanet(pl, plan, UPDT_ALL);
	}
	/* Assume that the planet only needs to be updated once... */

	/* Odd, changes in pl_y not supported.  5/31/92 TC */

	sndPlanetLoc(pll, plan);
    }

    /* Now we can send our Planet Packet */
    sendVPlanets();
}


/* give session stats if you send yourself a '?' 2/27/92 TC */
/* return true if you should eat message */

static int parseQuery(struct message *msg)
{
    /* 0-8 for address, 9 is space */
    char *cchar = &msg->m_data[10];

    if (*cchar == '?' && *(cchar+1) == '\0')
	return bounceSessionStats(msg->m_from);
#ifdef PING
    if (*cchar == '!' && *(cchar+1) == '\0')
	return bouncePingStats(msg->m_from);
#endif
#ifdef RSA
    if (*cchar == '#' && *(cchar+1) == '\0')
	return bounceRSAClientType(msg->m_from);
#endif
    if (*cchar == '^' && *(cchar+1) == '\0')
	return bounceSBStats(msg->m_from);


    /* DEBUG */
    if (strcmp(cchar, "debug")==0){
	char	  buf[80];
	sprintf(buf, "dumpshmem > %s.dump.%d", login, getpid());
	if(fork() == 0){
	    SIGNAL(SIGALRM, SIG_DFL);
	    execl("/bin/sh", "sh", "-c", buf, NULL);
	    perror("execl");
	    ERROR(1,("Another socket exit"));
	    _exit(1);
	}
    }
    return FALSE;
}

void updateMessages(void)
{
    struct message *cur;
    struct mesg_spacket msg;
    int reset_flags = 0;
    int send_msg;

    for (; msgCurrent!=(mctl->mc_current+1) % MAXMESSAGE;
	 msgCurrent=(msgCurrent+1) % MAXMESSAGE) {
	if (msgCurrent>=MAXMESSAGE)
	    msgCurrent=0;
	cur = &messages[msgCurrent];

	if ((macroignore && cur->m_flags & MMACRO) 
	    || (dooshignore && cur->m_from == DOOSHMSG)) {
	    continue;
	}

	if (cur->m_flags & MVALID &&
	    (cur->m_flags & MALL ||
	     (cur->m_flags & MTEAM && cur->m_recpt & me->p_team) ||
	     (cur->m_flags & MINDIV && cur->m_recpt == me->p_no) 
		)) {	     

/* hack for displaying MINDIV && MCONQ messages to stdout on the clients.  
   Clients only show MALL && MCONQ.  but we don't want to send to all.
   So at this point, MINDIV has already directed it to the right guy.
   Now, cancel MINDIV and set MALL, for the client's benefit.
   ATH, 11/5/95 */

	    if ((cur->m_flags & MINDIV) && (cur->m_flags & MCONQ)) {
		cur->m_flags &= ~MINDIV;
		cur->m_flags |= MALL;
		reset_flags = 1;
	    }

            if(send_short && (cur->m_from == 255)) {
		/* Test if possible to send with SP_S_WARNING */
		if (updtMessageSMessage(cur)) {
		    continue;
		}
            }

	    send_msg = FALSE;

	    if ((cur->m_from < 0) || (cur->m_from > MAXPLAYER))
		send_msg = TRUE;
	    else if (cur->m_flags & MALL && !(ignored[cur->m_from] & MALL))
		send_msg = TRUE;
	    else if (cur->m_flags & MTEAM && !(ignored[cur->m_from] & MTEAM)){
		send_msg = TRUE;
	    }
	    else if (cur->m_flags & MINDIV) {
		int query = 0;

		/* session stats now parsed here.  parseQuery == true */
		/* means eat message 4/17/92 TC */
		query = parseQuery(cur);
		if (!query) {
		    if (ignored[cur->m_from] & MINDIV)
			bounce(cur->m_from,
			       "That player is currently ignoring you.");
		    else  {
			send_msg = TRUE;
		    }
                }
	    }
	    if (send_msg)
		updtMessage(&msg, cur);
	}
/* Put eject message back as MINDIV, so everyone doesn't get it later */
	if (reset_flags) {
	    cur->m_flags &= ~MALL;
	    cur->m_flags |= MINDIV;
	    reset_flags = 0;
	}
    }
}

static void
updateVPlayer(struct player_spacket *p)
{
    int		i = clientVPlayerCount; 
#if MAXPLAYER > 32
    int		j = clientVXPlayerCount;
#endif
    U_LONG	x = ntohl(p->x), y = ntohl(p->y);
    int 	dir,dx,dy;
    int     		view = SCALE * WINSIDE / 2;

    if (p->pnum == me->p_no){
	if ( send_short > 1) { /* S_P2 */
	    struct player_s2_spacket  *pl = (struct player_s2_spacket  *) &clientVPlayers[0];
	    pl->x = (short) htons((x+SCALE/2)/SCALE) /* p->x*/ ;
	    pl->y = (short) htons((y+SCALE/2)/SCALE) /*p->y*/;
	    pl->speed = p->speed;
	    pl->dir = p->dir;
	    big = 1; /* Flag to remind me that we must send big header */
	}
	else {
	    struct player_s_spacket  *pl = (struct player_s_spacket  *) &clientVPlayers[0];
	    pl->x = (long) htonl(x)/* p->x*/ ;
	    pl->y = (long) htonl(y) /*p->y*/;
	    pl->speed = p->speed;
	    pl->dir = p->dir;
	    big = 1; /* Flag to remind me that we must send big header */
	}
    }
    else
#if (MAXPLAYER > 32)
	if ( p->pnum < 32)
#endif
	{
	    clientVPlayers[1] += 1; /* Another packet... */
	    /* Where is the ship? On local or galactic map. */
	    dx = (int) x - me->p_x;
	    dy = (int) y - me->p_y;
	    if (dx > view || dx < -view || dy > view || dy < -view) { /* Galactic */
		dx = (int) x * WINSIDE / GWIDTH; /* Orig. */
		dy = (int) y * WINSIDE / GWIDTH;
		if ( dx < 0 || dy < 0 || dx >= WINSIDE || dy >= WINSIDE) {
		    dx = 501; /* clipped */
		    dy = 501;
		}
		dir = rosette (p->dir);
		clientVPlayers[i++] = (u_char) ((p->pnum)|((dx  & 256) >> 2)|((dy & 256)>>1) | 32);
		clientVPlayers[i++] = ( u_char)(( p->speed & 0x0f)|(dir << 4));
		clientVPlayers[i++] = (u_char) (dx & 0xff);
		clientVPlayers[i++] = (u_char) ( dy & 0xff);
		clientVPlayerCount = i;		    
	    }
	    else {   /* Local */
		/*
		  dx = dx / SCALE + WINSIDE / 2;
		  dy = dy / SCALE + WINSIDE / 2;
		  */

		/* NEW -- fix precision loss -tsh */
		dx = (int) x/SCALE - me->p_x/SCALE + WINSIDE/2;
		dy = (int) y/SCALE - me->p_y/SCALE + WINSIDE/2;

		dir = rosette (p->dir);
		clientVPlayers[i++] = (u_char) ((p->pnum)|((dx  & 256) >> 2)|((dy & 256)>>1) );
		clientVPlayers[i++] = ( u_char)(( p->speed & 0x0f)|(dir << 4));
		clientVPlayers[i++] = (u_char) (dx & 0xff);
		clientVPlayers[i++] = (u_char) ( dy & 0xff);
		clientVPlayerCount = i;		
	    }
	}
#if (MAXPLAYER > 32)
	else
#if (MAXPLAYER > 64)
	    if ( p->pnum < 64)
#endif
	    {
		clientVXPlayers[1] += 1;
		/* Where is the ship? On local or galactic map. */
		dx = x - me->p_x;
		dy = y - me->p_y;
		if (dx > view || dx < -view || dy > view || dy < -view) { /* Galactic */
		    dx = x * WINSIDE / GWIDTH; /* Orig. */
		    dy = y * WINSIDE / GWIDTH;
		    if ( dx < 0 || dy < 0 || dx >= WINSIDE || dy >= WINSIDE) {
			dx = 501; /* clipped */
			dy = 501;
		    }
		    dir = rosette (p->dir);
		    clientVXPlayers[j++] = (u_char) ((p->pnum - 32)|((dx  & 256) >> 2)|((dy & 256)>>1) | 32);
		    clientVXPlayers[j++] = (u_char)(( p->speed & 0x0f)|(dir << 4));
		    clientVXPlayers[j++] = (u_char) (dx & 0xff);
		    clientVXPlayers[j++] = (u_char) ( dy & 0xff);
		    clientVXPlayerCount = j;		    
		}
		else {   /* Local */
		    dx = dx / SCALE + WINSIDE / 2;
		    dy = dy / SCALE + WINSIDE / 2;
		    dir = rosette (p->dir);
		    clientVXPlayers[j++] = (u_char) ((p->pnum-32)|((dx  & 256) >> 2)|((dy & 256)>>1) );
		    clientVXPlayers[j++] = (u_char)(( p->speed & 0x0f)|(dir << 4));
		    clientVXPlayers[j++] = (u_char) (dx & 0xff);
		    clientVXPlayers[j++] = (u_char) ( dy & 0xff);
		    clientVXPlayerCount = j;
		}
	    }
#if (MAXPLAYER > 64)
	    else  sendClientPacket((struct player_spacket *) p);
#endif

#endif /* MAXPLAYER > 32 */
}

static void sendVPlayers(void)
{
    unsigned int size,i,j,new;
    /* initialize type & length fields */
    clientVPlayers[0] = (u_char) SP_S_PLAYER;
#if MAXPLAYER > 32
    clientVXPlayers[0] = (u_char) SP_S_PLAYER;
#endif


    if ( big != 0) {	/* Big Packet */
	if ( send_short > 1) { /* S_P2 */
	    struct player_s2_spacket  *pa = (struct player_s2_spacket  *) &clientVPlayers[0];
	    pa->flags = 0;
            new = 0;

	    for(i=0,j=0; i < 16 && i < MAXPLAYER;i++ , j += 2) {
		new = new | ((unsigned int)n_flags[i] << j); 	
	    } /* for */
	    pa->flags = (long) htonl(new);
	    size = 12+(clientVPlayers[1]*4);
	    sizes[SP_S_PLAYER] = size;
	    sendClientPacket((struct player_spacket *) clientVPlayers);	
	    if(highest_active_player > 15 && highest_active_player < 32) {
		struct top_flags *ptr = (struct top_flags *) &clientVPlayers[4];
		new = 0;
		for(i=16,j=0; i < 32 && i < MAXPLAYER; i++, j +=2) {
		    new = new | ((unsigned int)n_flags[i] << j);
		} /* for */
		ptr->tflags = htonl(new);
		ptr->type   = (u_char) SP_S_PLAYER;
		ptr->packets = (unsigned char) 64;
		ptr->numflags = 1;
		ptr->index    = 1;
		size = 8; 
		sizes[SP_S_PLAYER] = size;
		sendClientPacket((struct player_spacket *) &clientVPlayers[4]);
	    }
	} /* if */
	else {
	    size = 12+( clientVPlayers[1]*4);
	    sizes[SP_S_PLAYER] = size;
	    sendClientPacket((struct player_spacket *) clientVPlayers);
	}
    }
    else if ( clientVPlayerCount > 12){ /* Small packet */

	if (send_short > 1) { /* S_P2 */
	    if(highest_active_player > 15 && highest_active_player < 32) {
		struct top_flags *ptr = (struct top_flags *) &clientVPlayers[0];
		new = 0;
		size = 12 + ( clientVPlayers[1]*4);
		for(i=16,j=0; i < 32 && i < MAXPLAYER; i++, j +=2) {
		    new = new | ((unsigned int)n_flags[i] << j);
		} /* for */
		ptr->tflags = htonl(new);
		new=0;
		for(i=0,j=0; i < 16 && i < MAXPLAYER;i++ , j += 2) {
		    new = new | ((unsigned int)n_flags[i] << j);
		} /* for */
		ptr->tflags2 = htonl(new);
		ptr->type   = (u_char) SP_S_PLAYER;
		ptr->packets = (unsigned char) clientVPlayers[1] | 64;
		ptr->numflags = 2;
		ptr->index    = 1;
		sizes[SP_S_PLAYER] = size;
		sendClientPacket((struct player_spacket *) &clientVPlayers[0]);
	    }
	    else { /* No players > 15 */
		struct top_flags *ptr = (struct top_flags *) &clientVPlayers[4];
		new = 0;
		size = 8 + ( clientVPlayers[1]*4);
		for(i=0,j=0; i < 16 && i < MAXPLAYER; i++, j +=2) {
		    new = new | ((unsigned int)n_flags[i] << j);
		} /* for */
		ptr->tflags = htonl(new);
		ptr->type   = (u_char) SP_S_PLAYER;
		ptr->packets = (unsigned char) clientVPlayers[1] | 64;
		ptr->numflags = 1;
		ptr->index    = 0;
		sizes[SP_S_PLAYER] = size;
		sendClientPacket((struct player_spacket *) &clientVPlayers[4]);
	    } /* active player if */ 
	} /* S_P2 */
	else { 
	    size = 4 + ( clientVPlayers[1]*4);
	    sizes[SP_S_PLAYER] = size;
	    clientVPlayers[8] = (u_char) SP_S_PLAYER;
	    clientVPlayers[9] = clientVPlayers[1] | 64;
	    clientVPlayers[10]=0;
	    clientVPlayers[11]=0;
	    sendClientPacket((struct player_spacket *) &clientVPlayers[8]);
	} 
    }

#if MAXPLAYER > 32
    if ( clientVXPlayerCount > 4) { /* Small + extended Packet */
	sizes[SP_S_PLAYER] = (clientVXPlayers[1]*4)+4;
	clientVXPlayers[1] |= 128; /* To mark it as a short header + Extended */
	sendClientPacket((struct player_spacket *) clientVXPlayers);
    }
#endif
}

/* New Torp Routine */
void SupdateTorps(void)
{
    struct torp *torp;
    int i,j;
    struct torp_info_spacket *tpi;
    struct torp_spacket *tp;
    u_char  *tinfo; 	/* TorpInfo data   */
    u_char  *torp_xy; /* The torp coord. */
    u_char  infobitset, torpbitset;
    int numtorps ; /* How many torps ? */

    int shift; /* Shift for 9 bit xy coordinate */
    int dx,dy; 
    int     view = SCALE * WINSIDE / 2;
    mustsend = 0;

    for (   j=0, torp=torps, tpi=clientTorpsInfo, tp=clientTorps; 
#if ((MAXPLAYER*MAXTORP) % 8 == 0)
	    j<	(MAXPLAYER * MAXTORP)/8;
#else
/* This normally wont test true..  But this will make the code more flexible,
 * in case someone starts messing with the defaults.. */
	    j<  (MAXPLAYER*MAXTORP + 7)/8;
#endif
	    j++) {

	shift = 0;
	numtorps = 0;
	infobitset 	= 0;
	torpbitset = 0;
	torp_xy = &clientVTorps[4];
	*torp_xy = 0; /* Clear first data byte */
	tinfo = & clientVTorpsInfo[0];

	for (i=0;  i<8;  i++, torp++, tpi++, tp++) {

#if ((MAXPLAYER*MAXTORP) % 8 != 0)
/* This normally wont test true..  But this will make the code more flexible,
 * in case someone starts messing with the defaults.. */
	    if (j*8+i >= (MAXPLAYER * MAXTORP))
		break;
#endif

	    if (torp->t_owner==me->p_no) {
		if (torp->t_war!=tpi->war ||
		    torp->t_status!=tpi->status) {
		    if (torp->t_war == tpi->war){ 
			/* Don't send TMOVE/TFREE . It's encoded in
			   the SP_S_TORP bitset. */
			switch(torp->t_status){
			case TFREE: 	
			    if (tpi->status == TEXPLODE){
				/* Send real TFREE if torp exploded */

				/* set bit for torp */
				infobitset = infobitset | ( 01  << i);
				*tinfo++ = ((u_char)tpi->war & 0x0f)
				    | ((u_char) torp->t_status << 4);
			    }
			    else
				mustsend = 1;
			    tpi->status=torp->t_status;
			    /* Don't forget... */
			    tp->x=htonl(torp->t_x);
			    tp->y=htonl(torp->t_y);
			    tp->dir=torp->t_dir;

			    continue; /* We continue , because server sends
					 obsolete data otherwise */
			case TMOVE:
			    tpi->status=torp->t_status;
			    break;				
			default:
			    tpi->status=torp->t_status; 
			    /* set bit for torp */
			    infobitset = infobitset | ( 01  << i);
			    *tinfo++ = ((u_char)tpi->war & 0x0f)
				|((u_char) tpi->status << 4);
			    break;
			}
		    }
		    else {
			tpi->war=torp->t_war;
			/* set bit for torp */
			tpi->status=torp->t_status; 
			infobitset = infobitset | ( 01  << i);
			*tinfo++ = ((u_char)tpi->war & 0x0f)
			    |((u_char) tpi->status << 4);
		    }
		}
		if ( tp->x!=htonl(torp->t_x)
		     || tp->y!=htonl(torp->t_y)
		     || ( (torp->t_gspeed == 0)
			  && (torp->t_status != TFREE))) { /* Hadley */
		    tp->type=SP_TORP;
		    tp->x=htonl(torp->t_x);
		    tp->y=htonl(torp->t_y);
		    tp->dir=torp->t_dir;
		    /* Now the fun begins .. */

		    /* set bit for torp */
		    torpbitset = torpbitset | ( 01  << i);
		    numtorps++;
		    /* Now the Coordi. */
		    dx = torp->t_x - me->p_x;
		    dy = torp->t_y - me->p_y;
		    if (dx > view || dx < -view || dy > view || dy < -view) {
			/* any torps off screen appear at 501 = clipped */
			dx = dy = 501;
			dx <<= shift;
			*torp_xy++  |= ( dx & 255);
			*torp_xy = (((u_int) dx >> 8) & 255);
			shift++;
			dy <<= shift;
			*torp_xy++  |= (dy & 255);
			*torp_xy = (((u_int) dy >> 8) & 255);
			shift++;
			if ( shift == 8){ 
			    shift = 0;
			    torp_xy++;
			    *torp_xy = 0;
			}	     	
			continue;
		    }
		    /*
		      dx = dx / SCALE + WINSIDE / 2;
		      dy = dy / SCALE + WINSIDE / 2;
		      */
		    /* NEW: fix precision loss -tsh */
		    dx = torp->t_x/SCALE - me->p_x/SCALE + WINSIDE/2;
		    dy = torp->t_y/SCALE - me->p_y/SCALE + WINSIDE/2;

		    dx <<= shift;
		    *torp_xy++  |= (dx & 0xff );
		    *torp_xy = (((u_int) dx >> 8) & 255);
		    shift++;
		    dy <<= shift;
		    *torp_xy++  |= (dy & 255);
		    *torp_xy = (((u_int) dy >> 8) & 255);
		    shift++;
		    if ( shift == 8){
			shift = 0;	     	
			torp_xy++;
			*torp_xy = 0;
		    }
		}
	    } else {	/* Someone else's torp... */
		if (torp->t_y > me->p_y + SCALE*WINSIDE/2 ||
		    torp->t_x > me->p_x + SCALE*WINSIDE/2 ||
		    torp->t_x < me->p_x - SCALE*WINSIDE/2 ||
		    torp->t_y < me->p_y - SCALE*WINSIDE/2 ||
		    torp->t_status==TFREE) {
		    if (torp->t_status==TFREE && tpi->status==TEXPLODE) {
			tpi->status=TFREE;
			continue;
		    }
		    if (tpi->status!=TFREE) {
			tpi->status=TFREE;
			mustsend = 1;
		    }
		} else {	/* in view */
		    if (torp->t_status!=tpi->status ||
			(torp->t_war & me->p_team)!=tpi->war) {
			if ( (torp->t_war & me->p_team) == tpi->war){
			    /* Don't send TMOVE/TFREE . It's encoded
			       in the SP_S_TORP bitset. */
			    switch(torp->t_status){
			    case TFREE:
				/* We continue , because server sends
				   obsolete data otherwise */
				tpi->status=torp->t_status;
				mustsend = 1;
				/* Don't forget... */
				tp->x=htonl(torp->t_x);
				tp->y=htonl(torp->t_y);
				tp->dir=torp->t_dir;
				continue;
			    case TMOVE:
				tpi->status=torp->t_status;
				break;				
			    default:
				tpi->status=torp->t_status; 
				infobitset = infobitset | ( 01  << i);   /* set bit for torp */
				*tinfo++ = ((u_char)tpi->war & 0x0f)|((u_char) tpi->status << 4);
				break;
			    }
			}
			else {
			    /* Let the client fade away the explosion on its own */
			    tpi->war=torp->t_war & me->p_team;
			    tpi->status=torp->t_status;
			    infobitset = infobitset | ( 01  << i);   /* set bit for torp */
			    *tinfo++ = ((u_char)tpi->war & 0x0f)|((u_char) tpi->status << 4);
			}
		    }
		    if (tp->x!=htonl(torp->t_x) ||
			tp->y!=htonl(torp->t_y) ||
			(torp->t_gspeed == 0 && torp->t_status != TFREE)) {/*Hadley*/
			tp->x=htonl(torp->t_x);
			tp->y=htonl(torp->t_y);
			tp->dir=torp->t_dir;
			/* Now the fun begins .. */
			torpbitset = torpbitset | ( 01  << i);   /* set bit for torp */
			numtorps++;
			/* Now the Coordi. */
			/*
			  dx = torp->t_x - me->p_x;
			  dx = dx / SCALE + WINSIDE / 2;
			  dy = torp->t_y - me->p_y;
			  dy = dy / SCALE + WINSIDE / 2;
			  */
			/* NEW: fix precision loss -tsh */
			dx = torp->t_x/SCALE - me->p_x/SCALE + WINSIDE/2;
			dy = torp->t_y/SCALE - me->p_y/SCALE + WINSIDE/2;

			dx <<= shift;
			*torp_xy++  |= (dx & 255);
			*torp_xy = (((u_int) dx >> 8) & 255);
			shift++;
			dy <<= shift;
			*torp_xy++  |= (dy & 255);
			*torp_xy = (((u_int) dy >> 8) & 255);
			shift++;
			if ( shift == 8){ 
			    shift = 0;
			    torp_xy++;
			    *torp_xy = 0;
			}	     		     	     
		    } /* second if */
		} 
	    } 
	}	/* 2. for */

/* Is there something to send ? */
	if ( infobitset != 0) {
	    int size = tinfo -clientVTorpsInfo;
	    u_char *dest = &clientVTorps[4+ vtdata[numtorps]];
	    u_char *source  =  &clientVTorpsInfo[0];

	    /* I must copy the Torpinfo behind the Torpdata */
	    while ( --size >= 0) { /* size doubly used */
		*dest++ = *source++;
	    }
	    size = 4 +  vtdata[numtorps]+ (tinfo -clientVTorpsInfo);
	    if((size % 4) != 0)
		size += (4 - (size % 4));
		
	    sizes[SP_S_TORP_INFO] = size;
	    clientVTorps[0] = SP_S_TORP_INFO; /* The type */
	    clientVTorps[1] = (u_char) torpbitset;
	    clientVTorps[2] = (u_char) j; /* which torps */
	    clientVTorps[3] = (u_char) infobitset;
	    sendClientPacket((struct torp_spacket *) &clientVTorps[0]);
	    mustsend = 0;
	}	
	else if ( torpbitset != 0){ /* NO TorpInfo */
	    mustsend = 0; 
	    if ( numtorps == 8) { /* we do not need bitset */
		clientVTorps[2] = SP_S_8_TORP; /* The type */
		clientVTorps[3] = (u_char) j; /* which torps */
		sendClientPacket((struct torp_spacket *) &clientVTorps[2]);
	    }
	    else {
		sizes[SP_S_TORP] = vtsize[numtorps];
		clientVTorps[1] = SP_S_TORP; /* The type */
		clientVTorps[2] = (u_char) torpbitset;
		clientVTorps[3] = (u_char) j; /* which torps */
		sendClientPacket((struct torp_spacket *) &clientVTorps[1]);
	    }
	}
	else if (mustsend != 0){ /* TFREE's */
	    mustsend = 0; 
	    sizes[SP_S_TORP] = 4;
	    clientVTorps[1] = SP_S_TORP; /* The type */
	    clientVTorps[2] = (u_char)torpbitset; 
	    clientVTorps[3] = (u_char) j; /* which torps */
	    sendClientPacket((struct torp_spacket *) &clientVTorps[1]);	
	}
    } /* auesseres for */
} /* Function */


#ifdef LTD_STATS

void updatePlayerStats(void)
{
    struct stats_spacket        *stats;
    struct stats_s_spacket *s_stats = &singleStats;
    struct player               *pl;
    int i = efticks(5);

    unsigned int total_kills, total_deaths, total_armies_bombed, total_ticks,
        total_planets_taken, sb_kills, sb_deaths, sb_ticks;


    if(repCount % i)
	return;

    i = (repCount/i) % MAXPLAYER;

    pl = &players[i];
    if(!pl->p_status) return;

    stats = &clientStats[i];

    /* Taken from inl source, socket.c.  Hack for INL robot (when stats are
       reset).  Stick it in here for lack of a better place.  Needed because
       these are ntserv process variables, so robot can't touch them. */

    total_kills		= ltd_kills(pl, LTD_TOTAL);
    total_deaths	= ltd_deaths(pl, LTD_TOTAL);
    total_armies_bombed	= ltd_armies_bombed(pl, LTD_TOTAL);
    total_ticks		= ltd_ticks(pl, LTD_TOTAL);
    total_planets_taken	= ltd_planets_taken(pl, LTD_TOTAL);
    sb_kills		= ltd_kills(pl, LTD_SB);
    sb_deaths		= ltd_deaths(pl, LTD_SB);
    sb_ticks		= ltd_ticks(pl, LTD_SB);



    if (startTkills > total_kills ||
        startTlosses > total_deaths ||
        startTarms > total_armies_bombed ||
        startTplanets > total_planets_taken ||
        startTticks > total_ticks)
    {
        startTkills = total_kills;
        startTlosses = total_deaths;
        startTarms = total_armies_bombed;
        startTplanets = total_planets_taken;
        startTticks = total_ticks;
    }

    /*
     * Send stat packets once per five updates. But, only send one.  We
     * will cycle through them all eventually.
     */
    if (  stats->tkills   != htonl((long) total_kills) ||
	  stats->tlosses  != htonl((long) total_deaths) ||
	  stats->kills    != htonl((long) 0) ||
	  stats->losses   != htonl((long) 0) ||
	  stats->tticks   != htonl((long) total_ticks) ||
	  stats->tplanets != htonl((long) total_planets_taken) ||
	  stats->tarmies  != htonl((long) total_armies_bombed) ||
	  stats->sbkills  != htonl((long) sb_kills) ||
	  stats->sblosses != htonl((long) sb_deaths) ||
	  stats->armies   != htonl((long) 0) ||
	  stats->planets  != htonl((long) 0)) {

	stats->tkills   = htonl((long) total_kills);
	stats->tlosses  = htonl((long) total_deaths);
	stats->kills    = htonl((long) 0);
	stats->losses   = htonl((long) 0);
	stats->tticks   = htonl((long) total_ticks);
	stats->tplanets = htonl((long) total_planets_taken);
	stats->tarmies  = htonl((long) total_armies_bombed);
	stats->sbkills  = htonl((long) sb_kills);
	stats->sblosses = htonl((long) sb_deaths);
	stats->armies   = htonl((long) 0);
	stats->planets  = htonl((long) 0);

	if ((pl->p_ship.s_type == STARBASE) && (SBhours)) {
	    stats->maxkills=htonl((long) sb_ticks);
	} else {
	    stats->maxkills=htonl(ltd_kills_max(pl, LTD_TOTAL) * 100);
	}
	stats->sbmaxkills = htonl(ltd_kills_max(pl, LTD_SB) * 100);

	stats->type = SP_STATS;
	stats->pnum = i;
	if (send_short > 1 &&
	    total_kills         < 0xffff &&
	    total_deaths        < 0xffff &&
	    total_deaths        < 0xffff &&
	    total_planets_taken < 0xffff &&
	    sb_kills            < 0xffff &&
	    sb_deaths           < 0xffff &&
	    total_planets_taken < 0xffff ) {

	    s_stats->tkills    = htons(total_kills);
	    s_stats->tlosses   = htons(total_deaths);
	    s_stats->kills     = htons(0);
	    s_stats->losses    = htons(0);
	    s_stats->tticks    = htonl(total_ticks);
	    s_stats->tplanets  = htons(total_planets_taken);
	    s_stats->tarmies   = htonl(total_armies_bombed);
	    s_stats->sbkills   = htons(sb_kills);
	    s_stats->sblosses  = htons(sb_deaths);
	    s_stats->armies    = htons(0);
	    s_stats->planets   = htons(0);

	    if ((pl->p_ship.s_type == STARBASE) && (SBhours)) {
		s_stats->maxkills=htonl(sb_ticks);
	    } else {
		s_stats->maxkills=htonl(ltd_kills_max(pl, LTD_TOTAL) * 100);
	    }
	    s_stats->sbmaxkills=htonl(ltd_kills_max(pl, LTD_SB) * 100);

	    s_stats->type=SP_S_STATS;
	    s_stats->pnum=i;
	    sendClientPacket(s_stats);
	}
	else
	    sendClientPacket((CVOID) stats);
    }
}
#else /* LTD_STATS */

void updatePlayerStats(void)
{
    struct stats_spacket        *stats;
    struct stats_s_spacket *s_stats = &singleStats;
    struct player               *pl;
    int i = efticks(5);

    if(repCount % i)
	return;

    i = (repCount/i) % MAXPLAYER;

    pl = &players[i];
    if(!pl->p_status) return;

    stats = &clientStats[i];

    /* Taken from inl source, socket.c.  Hack for INL robot (when stats are
       reset).  Stick it in here for lack of a better place.  Needed because
       these are ntserv process variables, so robot can't touch them. */

    if (startTkills > me->p_stats.st_tkills ||
        startTlosses > me->p_stats.st_tlosses ||
        startTarms > me->p_stats.st_tarmsbomb ||
        startTplanets > me->p_stats.st_tplanets ||
        startTticks > me->p_stats.st_tticks)
    {
        startTkills = me->p_stats.st_tkills;
        startTlosses = me->p_stats.st_tlosses;
        startTarms = me->p_stats.st_tarmsbomb;
        startTplanets = me->p_stats.st_tplanets;
        startTticks = me->p_stats.st_tticks;
    }

    /*
     * Send stat packets once per five updates. But, only send one.  We
     * will cycle through them all eventually.
     */
    if (  stats->tkills != htonl(pl->p_stats.st_tkills) ||
	  stats->tlosses != htonl(pl->p_stats.st_tlosses) ||
	  stats->kills != htonl(pl->p_stats.st_kills) ||
	  stats->losses != htonl(pl->p_stats.st_losses) ||
	  stats->tticks != htonl(pl->p_stats.st_tticks) ||
	  stats->tplanets != htonl(pl->p_stats.st_tplanets) ||
	  stats->tarmies != htonl(pl->p_stats.st_tarmsbomb) ||
	  stats->sbkills != htonl(pl->p_stats.st_sbkills) ||
	  stats->sblosses != htonl(pl->p_stats.st_sblosses) ||
	  stats->armies != htonl(pl->p_stats.st_armsbomb) ||
	  stats->planets != htonl(pl->p_stats.st_planets)) {

	stats->tkills = htonl(pl->p_stats.st_tkills);
	stats->tlosses = htonl(pl->p_stats.st_tlosses);
	stats->kills = htonl(pl->p_stats.st_kills);
	stats->losses = htonl(pl->p_stats.st_losses);
	stats->tticks = htonl(pl->p_stats.st_tticks);
	stats->tplanets = htonl(pl->p_stats.st_tplanets);
	stats->tarmies = htonl(pl->p_stats.st_tarmsbomb);
	stats->sbkills = htonl(pl->p_stats.st_sbkills);
	stats->sblosses = htonl(pl->p_stats.st_sblosses);
	stats->armies = htonl(pl->p_stats.st_armsbomb);
	stats->planets = htonl(pl->p_stats.st_planets);

	if ((pl->p_ship.s_type == STARBASE) && (SBhours)) {
	    stats->maxkills=htonl((int) (pl->p_stats.st_sbticks));
	} else {
	    stats->maxkills=htonl((int) (pl->p_stats.st_maxkills * 100));
	}
	stats->sbmaxkills = htonl((int) (pl->p_stats.st_sbmaxkills * 100));
	stats->type = SP_STATS;
	stats->pnum = i;
	if (send_short > 1 &&
	    pl->p_stats.st_tkills < 0xffff &&
	    pl->p_stats.st_tlosses < 0xffff &&
	    pl->p_stats.st_losses < 0xffff &&
	    pl->p_stats.st_tplanets < 0xffff &&
	    pl->p_stats.st_sbkills < 0xffff &&
	    pl->p_stats.st_sblosses < 0xffff &&
	    pl->p_stats.st_planets < 0xffff ) {
	    s_stats->tkills = htons(pl->p_stats.st_tkills);
	    s_stats->tlosses = htons(pl->p_stats.st_tlosses);
	    s_stats->kills = htons(pl->p_stats.st_kills);
	    s_stats->losses = htons(pl->p_stats.st_losses);
	    s_stats->tticks = htonl(pl->p_stats.st_tticks);
	    s_stats->tplanets = htons(pl->p_stats.st_tplanets);
	    s_stats->tarmies = htonl(pl->p_stats.st_tarmsbomb);
	    s_stats->sbkills = htons(pl->p_stats.st_sbkills);
	    s_stats->sblosses = htons(pl->p_stats.st_sblosses);
	    s_stats->armies = htons(pl->p_stats.st_armsbomb);
	    s_stats->planets = htons(pl->p_stats.st_planets);
	    if ((pl->p_ship.s_type == STARBASE) && (SBhours)) {
		s_stats->maxkills=htonl((int) (pl->p_stats.st_sbticks));
	    } else {
		s_stats->maxkills=htonl((int) (pl->p_stats.st_maxkills * 100));
	    }
	    s_stats->sbmaxkills=htonl((int) (pl->p_stats.st_sbmaxkills * 100));
	    s_stats->type=SP_S_STATS;
	    s_stats->pnum=i;
	    sendClientPacket(s_stats);
	}
	else
	    sendClientPacket((CVOID) stats);
    }
}

#endif /* LTD_STATS */

/* Called by initClientData - This routine initialized the local packet
   information to an unobtainable state. (Which then forces updates to
   occur) */
void initSPackets(void)
{
    int i;

    for (i=0; i<MAXPLAYER; i++) {
	clientHostile[i].hostile= -1;
	clientStats[i].losses= -1;
	clientLogin[i].rank= -1;
	clientPlayersInfo[i].shiptype= -1;
	clientPStatus[i].status= -1;
	clientPlayers[i].x= htonl(-1);
	clientPhasers[i].status= -1;
	client_s_Phasers[i].status = -1;
	clientKills[i].kills= htonl(-1);
	clientFlags[i].flags= htonl(-1);
	mustUpdate[i]=0;
    }
    for (i=0; i<MAXPLAYER*MAXTORP; i++) {
	clientTorpsInfo[i].status= -1;
	clientTorps[i].x= -1;
	clientTorpsInfo[i].war = 0;
    }
    for (i=0; i<MAXPLAYER*MAXPLASMA; i++) {
	clientPlasmasInfo[i].status= -1;
	clientPlasmas[i].x= -1;
    }
    for (i=0; i<MAXPLANETS; i++) {
	clientPlanets[i].armies= htonl(-1);
	clientPlanetLocs[i].x= htonl(-1);
    }
    msgCurrent=(mctl->mc_current+1) % MAXMESSAGE;
    clientSelf.pnum= -1;

    clientSelfShip.damage = -1;
    clientSelfShort.pnum = -1;
}

/* Routine called by forceUpdate to clear local packet info, and force
   an update */
void
clearSPackets(int update_all, int update_sall)
{
    int i;


/* WE must do this or change the torp implementation ( It is now changed )*/
/* But it should be no problem because normally NO packet is send */
    if ( send_short) {
	for (i=0; i<MAXPLAYER*MAXTORP; i++) {
	    clientTorpsInfo[i].status= TFREE; /* That's the trick */
	}
	/* And again */
	for (i=0; i<MAXPLAYER*MAXPLASMA; i++)
	    clientPlasmasInfo[i].status= TFREE;
	for (i=0; i<MAXPLAYER; i++)
	    clientPhasers[i].status = PHFREE;
    }

/*    clientDead=0;*/
    for (i=0; i<MAXPLAYER; i++) {

	/* Do not update free Slots when a small, or medium
	   update is requested */
	if((update_all || update_sall)
	   && players[i].p_status == PFREE) continue;

	if (!update_sall) {

	    if(!update_all)
		/* Update only with a large request */
		clientStats[i].losses= -1;

	    /* Update these with large, or medium request */
	    clientHostile[i].hostile= -1;
	    /*	clientLogin[i].rank= -1;		(critical) */
	    /*	clientPlayersInfo[i].shiptype= -1;	(critical) */
	    /*	clientPStatus[i].status= -1;		(critical) */
	    clientPlayers[i].x= htonl(-1);		/* (non-critical, but nice) */
	    if(!send_short) clientPhasers[i].status= -1;
	    clientFlags[i].flags= htonl(-1);
	}

	/* Update these with large, medium, or small request */
	clientKills[i].kills= htonl(-1);	/* (non-critical, but nice) */
	mustUpdate[i]=0;
    }

    if ( !send_short ){
	for (i=0; i<MAXPLAYER*MAXTORP; i++) {
	    clientTorpsInfo[i].status= -1;
	    clientTorps[i].x= -1;		/*	(non-critical) */
	}
	for (i=0; i<MAXPLAYER*MAXPLASMA; i++) {
	    clientPlasmasInfo[i].status= -1;
/*	clientPlasmas[i].x= -1;			(non-critical) */
	}
    }
    for (i=0; i<MAXPLANETS; i++) {
	clientPlanets[i].info |= me->p_team;
	clientPlanets[i].armies= htonl(-1);
/*	clientPlanetLocs[i].x= htonl(-1);	(critical) */
    }
/*    msgCurrent=(mctl->mc_current+1) % MAXMESSAGE;*/
    clientSelf.pnum= -1;
    clientSelfShort.pnum = -1;
    clientSelfShip.damage = -1;
}

#ifdef FEATURE_PACKETS
void
sendFeature(struct feature_spacket *packet)
{
    packet->type = SP_FEATURE;
    packet->value = htonl(packet->value);
    sendClientPacket((CVOID) packet);
}
#endif /* FEATURE_PACKETS */

/*
 * If we're in UDP mode, add a sequence number to the transmission buffer.
 * Returns the #of bytes inserted.
 *
 * This will add a sequence # to transmissions on either channel.  However,
 * the current implementation doesn't put sequences on TCP transmissions
 * because mixed TCP packets and UDP packets rarely arrive in the order
 * in which they were sent.
 */
int
addSequence(char *outbuf, LONG *seq_no)
{
    struct sequence_spacket *ssp;

#ifdef nodef
    /* assume true */
    if (commMode != COMM_UDP || udpMode == MODE_TCP)
	return (0);
#endif

#ifdef PING             /* this needs to be counted */
    packets_sent ++;
#endif

    ssp = (struct sequence_spacket *) outbuf;
    ssp->type = SP_SEQUENCE;
    ssp->sequence = htons((u_short) *seq_no);
    if (!f_many_self)
	ssp->flag8 = (((unsigned int)me->p_flags >> 8) & 0xff); /* S_P2 */
    (*seq_no)++;

    return (sizeof(struct sequence_spacket));
}

void
sendQueuePacket(short pos)
{
    struct queue_spacket qPacket;

    qPacket.type=SP_QUEUE;
    qPacket.pos=htons(pos);
    sendClientPacket((CVOID) &qPacket);
    flushSockBuf();
}

void
sendPickokPacket(int state)
{
    struct pickok_spacket pickPack;

    pickPack.type=SP_PICKOK;
    pickPack.state=state;
    sendClientPacket((CVOID) &pickPack);
}

void 
sendClientLogin(struct stats *stats)
{
    struct login_spacket logPacket;

    logPacket.type=SP_LOGIN;
    if (stats==NULL) {
	logPacket.accept=0;
    } else {
	logPacket.accept=1;
	logPacket.flags=htonl(stats->st_flags);
	MCOPY(stats->st_keymap, logPacket.keymap, 96);
    }
    sendClientPacket((CVOID) &logPacket);
}

void
sendMotdLine(char *line)
{
    struct motd_spacket motdPacket;
    int len;

/* Well it seems that we can really only send 79 characters for the
   motd. Seems kinda hosed...

   Added wraparound capability (mostly for the compiler options)  DRG Jun 93
   */
    if ((len = strlen(line)) < (MSG_LEN - 1)) { /* no need to wrap around */
	motdPacket.type=SP_MOTD;
	STRNCPY(motdPacket.line, line, MSG_LEN);
	motdPacket.line[MSG_LEN-1]='\0';
	sendClientPacket((CVOID) &motdPacket);
    }
    else {
	char dmy[MSG_LEN];
	char *ptr1,*ptr2;
	int i,j;
	dmy[MSG_LEN-1] ='\0';
	for (i=0;i<(int)(((float)(len)/(float)(MSG_LEN-1.0))+0.99);i++) {
	    ptr1 = dmy; ptr2 = &(line[i*(MSG_LEN-1)]);
	    for (j=0;j<MSG_LEN-1;j++) *ptr1++ = *ptr2++;
	    motdPacket.type=SP_MOTD;
	    STRNCPY(motdPacket.line, dmy, MSG_LEN);
	    motdPacket.line[MSG_LEN-1]='\0';
	    sendClientPacket((CVOID) &motdPacket);
	}
    }

}

void
sendMaskPacket(int mask)
{
    struct mask_spacket maskPacket;

    maskPacket.type=SP_MASK;
    maskPacket.mask=mask;
    sendClientPacket((CVOID) &maskPacket);
}

/*  Hey Emacs!
 * Local Variables:
 * c-file-style:"bsd"
 * End:
 */
