DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦9bf1c1141⟧ TextFile

    Length: 25146 (0x623a)
    Types: TextFile
    Names: »redraw.c«

Derivation

└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
    └─⟦this⟧ »EUUGD18/X/Xtrek/redraw.c« 

TextFile

static char sccsid[] = "@(#)redraw.c	1.1";
/*

	Copyright (c) 1986 	Chris Guthrie

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.

*/

#include <X11/Xlib.h>
#include <stdio.h>
#include <signal.h>
#include <math.h>
#include "defs.h"
#include "data.h"
#include "bitmaps.h"

#define WINSIDE 500

/* NOTE: This definition depends on MAXPLAYERS! */
static char *shipnos = "0123456789abcdef";

static short nplayers;
static int stlinecount = 1;

extern unsigned char	newcourse();	/* Down below... */

intrupt()
{
    register int		i;
    register struct player	*p;

    udcounter++;
    move();
    for (i = 0, p = &players[i]; i < MAXPLAYER; i++, p++) {
#ifdef notdef
	    auto_features(p);	/* Called in move() */
	    redraw(p);
#endif
    }
    ++stlinecount;
}

redraw(j)
register struct player	*j;
{
    /* erase warning line if necessary */
    if ((j->warntimer <= udcounter) && (j->warncount > 0)) {
	XClearWindow(j->display, j->warnw);
	j->warncount = 0;
    }

    if (j->clearcount) {
	XFillRectangles(j->display, j->w, j->cleargc,
		j->clearzone, j->clearcount);
	j->clearcount = 0;
    }

/* NOTE: Can this be made into an XDrawLines? */
    while (j->clearlcount) {
	j->clearlcount--;
	XDrawLine(j->display, j->w, j->cleargc,
	    j->clearline[0][j->clearlcount],
	    j->clearline[1][j->clearlcount],
	    j->clearline[2][j->clearlcount],
	    j->clearline[3][j->clearlcount]);
    }

    if ((j->mapmode) && (udcounter % ((nplayers == 0) ? 1 : nplayers) == 0))
	map(j);

    /* Display a new message every MESSTIME/UPS seconds */
    if ((udcounter % MESSTIME) == 0)
	dmessage(j);

    local(j);	/* redraw local window */

    if ((stlinecount&02) == 0)
	stline(j);	/* update every 4 times we update the window */

    if (j->p_flags & PFSHOWSTATS)
	updateStats(j, j->statwin);
}

drawPartialPhaser(p, j)
register struct player *p, *j;
{
int	sx,ex,sy,ey;
struct	phaser *php;


    sx= j->p_x - p->p_x;
    sy= j->p_y - p->p_y;
    /* Now draw his phaser (if it exists) */
    php = &phasers[j->p_no];
    if (php->ph_status == PHMISS) {
	/* Here I will have to compute end coordinate */
	phasedist(j, php, &ex, &ey);
	ex -= p->p_x;
	ey -= p->p_y;
    }
    else {
	ex = (players[php->ph_target].p_x) - p->p_x;
	ey = (players[php->ph_target].p_y) - p->p_y;
    }
    /* phaser end points are now relative to our position, make them
     * relative to window origin (so X clips them correctly)
     */
    sx= sx/SCALE+WINSIDE/2; sy= sy/SCALE+WINSIDE/2;
    ex= ex/SCALE+WINSIDE/2; ey= ey/SCALE+WINSIDE/2;
    if ((sx<0)&&(ex<0))	return;
    if ((sy<0)&&(ey<0))	return;
    if ((sx>WINSIDE)&&(ex>WINSIDE))	return;
    if ((sy>WINSIDE)&&(ey>WINSIDE))	return;
    XSetForeground(p->display, p->xfgc, phaserColor(php));
    XDrawLine(p->display, p->w, p->xfgc,
	    sx, sy, ex, ey);
/*
    p->clearline[p->clearlcount].x1 = sx;
    p->clearline[p->clearlcount].y1 = sy;
    p->clearline[p->clearlcount].x2 = ex;
    p->clearline[p->clearlcount].y2 = ey;
*/
    p->clearline[0][p->clearlcount] = sx;
    p->clearline[1][p->clearlcount] = sy;
    p->clearline[2][p->clearlcount] = ex;
    p->clearline[3][p->clearlcount] = ey;
    p->clearlcount++;
}

local(p)
register struct player *p;
{
    register int h, i;
    register struct player *j;
    register struct torp *k;
    register struct planet *l;
    register struct phaser *php;
    char glyph;
    int dx, dy;
    int view;

    /* Draw Planets */
    view = SCALE * WINSIDE / 2;
    for (i = 0, l = &planets[0]; i < MAXPLANETS; i++, l++) {
	dx = l->pl_x - p->p_x;
	dy = l->pl_y - p->p_y;
	if (dx > view || dx < -view || dy > view || dy < -view)
	    continue;
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
	glyph = planetGlyph(l);
	XSetForeground(p->display, p->xfgc, planetColor(l));
	XDrawString(p->display, p->w, p->xfgc, dx - (planet_width/2),
		dy - (planet_height/2), &glyph, 1);
	if (p->namemode) {
	    XDrawImageString(p->display, p->w, p->dfgc, dx - (planet_width/2), dy + (planet_height/2 + p->dfont->ascent),
		l->pl_name, l->pl_namelen);
	    p->clearzone[p->clearcount].x = dx - (planet_width/2);
	    p->clearzone[p->clearcount].y = dy + (planet_height/2);
	    /*NOTE: put this calculation into the player data */
	    p->clearzone[p->clearcount].width = XTextWidth(p->dfont, l->pl_name, l->pl_namelen);
	    p->clearzone[p->clearcount].height = fontHeight(p->dfont);
	    p->clearcount++;
	}
	p->clearzone[p->clearcount].x = dx - (planet_width/2);
	p->clearzone[p->clearcount].y = dy - (planet_height/2);
	p->clearzone[p->clearcount].width = planet_width;
	p->clearzone[p->clearcount].height = planet_height;
	p->clearcount++;
    }

    /* Draw ships */
    nplayers = 0;
    view = SCALE * WINSIDE / 2;
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
	int tx, ty;
	if ((j->p_status != PALIVE) && (j->p_status != PEXPLODE))
	    continue;
	if ((j->p_flags & PFCLOAK) && (j != p))
	    continue;
	nplayers++;
	dx = j->p_x - p->p_x;
	dy = j->p_y - p->p_y;
	if (dx > view || dx < -view || dy > view || dy < -view) {
	    if (phasers[j->p_no].ph_status != PHFREE)
		drawPartialPhaser(p, j);
	    continue;
	}
	XSetForeground(p->display, p->xfgc, playerColor(j));
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
	if (j->p_status == PALIVE) {
	    switch (j->p_team) {
		case FED: glyph = FED_GLYPHS + rosette(j->p_dir); break;
		case ROM: glyph = ROM_GLYPHS + rosette(j->p_dir); break;
		case KLI: glyph = KLI_GLYPHS + rosette(j->p_dir); break;
		case ORI: glyph = ORI_GLYPHS + rosette(j->p_dir); break;
	    }
	    XDrawString(p->display, p->w, p->xfgc, dx - (ship_width/2),
		dy - (ship_height/2), &glyph, 1);
	/* NOTE: This DrawImageString doesn't use the right GC */
	    XDrawImageString(p->display, p->w, p->dfgc, dx + (ship_width/2), dy - (ship_height/2 - p->dfont->ascent),
		shipnos + j->p_no, 1);
	       
/* NOTE: fix to change shield color depending on damage.. */
	    if (p->showShields && j->p_flags & PFSHIELD) {
		if (j == p) {
		    if (j->p_damage > (j->p_ship.s_maxdamage / 2))
			glyph = RSHIELD_GLYPH;
		    else if (j->p_shield < (j->p_ship.s_maxshields / 2))
			glyph = YSHIELD_GLYPH;
		    else
			glyph = SHIELD_GLYPH;
		} else
		    glyph = SHIELD_GLYPH;
		XDrawString(p->display, p->w, p->xfgc, dx - (shield_width / 2),
			dy - (shield_height / 2), &glyph, 1);
	    }

	    p->clearzone[p->clearcount].x = dx + (ship_width/2);
	    p->clearzone[p->clearcount].y = dy - (ship_height/2);
	    /* NOTE: put this calculattion into  player data */
	    p->clearzone[p->clearcount].width = XTextWidth(p->dfont, shipnos + j->p_no, 1);
	    p->clearzone[p->clearcount].height = fontHeight(p->dfont);
	    p->clearcount++;
	    p->clearzone[p->clearcount].x = dx - (shield_width/2);
	    p->clearzone[p->clearcount].y = dy - (shield_height/2);
	    p->clearzone[p->clearcount].width = shield_width;
	    p->clearzone[p->clearcount].height = shield_height;
	    p->clearcount++;
	}
	else if (j->p_status == PEXPLODE) {
	    glyph = EXP_GLYPHS_LEFT + (10 - j->p_explode)/2;
	    XDrawString(p->display, p->w, p->xfgc, dx - (ex_width / 2),
		dy - (ex_height / 2), &glyph, 1);

	    glyph = EXP_GLYPHS_RIGHT + (10 - j->p_explode)/2;
	    XDrawString(p->display, p->w, p->xfgc, dx,
		dy - (ex_height / 2), &glyph, 1);

	    p->clearzone[p->clearcount].x = dx - (ex_width/2);
	    p->clearzone[p->clearcount].y = dy - (ex_height/2);
	    p->clearzone[p->clearcount].width = ex_width;
	    p->clearzone[p->clearcount].height = ex_height;
	    p->clearcount++;
	}
	/* Now draw his phaser (if it exists) */
	php = &phasers[j->p_no];
	if (php->ph_status != PHFREE) {
	    if (php->ph_status == PHMISS) {
		/* Here I will have to compute end coordinate */
		phasedist(j, php, &tx, &ty);
		tx = (tx - p->p_x) / SCALE + WINSIDE / 2;
		ty = (ty - p->p_y) / SCALE + WINSIDE / 2;
		XSetForeground(p->display, p->xfgc, phaserColor(php));
		XDrawLine(p->display, p->w, p->xfgc, dx, dy, tx, ty);
	    }
	    else { /* Start point is dx, dy */
		tx = (players[php->ph_target].p_x - p->p_x) /
		    SCALE + WINSIDE / 2;
		ty = (players[php->ph_target].p_y - p->p_y) /
		    SCALE + WINSIDE / 2;
		XSetForeground(p->display, p->xfgc, phaserColor(php));
		XDrawLine(p->display, p->w, p->xfgc, dx, dy, tx, ty);
	    }
	    p->clearline[0][p->clearlcount] = dx;
	    p->clearline[1][p->clearlcount] = dy;
	    p->clearline[2][p->clearlcount] = tx;
	    p->clearline[3][p->clearlcount] = ty;
	    p->clearlcount++;
	}
    }
    /* Draw torps */
    view = SCALE * WINSIDE / 2;
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
	if (!j->p_ntorp)
	    continue;
	for (h = 0, k = &torps[MAXTORP * i + h]; h < MAXTORP; h++, k++) {
	    if (!k->t_status)
		continue;
	    dx = k->t_x - p->p_x;
	    dy = k->t_y - p->p_y;
	    if (dx > view || dx < -view || dy > view || dy < -view)
		continue;
	    XSetForeground(p->display, p->xfgc, torpColor(k));
	    dx = dx / SCALE + WINSIDE / 2;
	    dy = dy / SCALE + WINSIDE / 2;
	    if (k->t_status == TEXPLODE) {
		glyph = CLOUD_GLYPH;
		XDrawString(p->display, p->w, p->xfgc, dx - (cloud_width / 2),
			dy - (cloud_height / 2), &glyph, 1);

		p->clearzone[p->clearcount].x = dx - (cloud_width/2);
		p->clearzone[p->clearcount].y = dy - (cloud_height/2);
		p->clearzone[p->clearcount].width = cloud_width;
		p->clearzone[p->clearcount].height = cloud_height;
		p->clearcount++;
	    }
	    else if (k->t_owner != p->p_no && ((k->t_war & p->p_team) ||
		      (k->t_team & (p->p_hostile | p->p_swar))))
	    {
		glyph = ETORP_GLYPH;
		XDrawString(p->display, p->w, p->xfgc, dx - (etorp_width / 2),
			dy - (etorp_height / 2), &glyph, 1);

		p->clearzone[p->clearcount].x = dx - (etorp_width/2);
		p->clearzone[p->clearcount].y = dy - (etorp_height/2);
		p->clearzone[p->clearcount].width = etorp_width;
		p->clearzone[p->clearcount].height = etorp_height;
		p->clearcount++;
	    }
	    else {
		glyph = MTORP_GLYPH;
		XDrawString(p->display, p->w, p->xfgc, dx - (mtorp_width / 2),
			dy - (mtorp_height / 2), &glyph, 1);

		p->clearzone[p->clearcount].x = dx - (mtorp_width/2);
		p->clearzone[p->clearcount].y = dy - (mtorp_height/2);
		p->clearzone[p->clearcount].width = mtorp_width;
		p->clearzone[p->clearcount].height = mtorp_height;
		p->clearcount++;
	    }
	}
    }
    /* Draw Edges */
    XSetForeground(p->display, p->xfgc, p->warningColor);
    if (p->p_x < (WINSIDE / 2) * SCALE) {
	int	sy, ey;

	dx = (WINSIDE / 2) - (p->p_x) / SCALE;
	sy = (WINSIDE / 2) + (0 - p->p_y) / SCALE;
	ey = (WINSIDE / 2) + (GWIDTH - p->p_y) / SCALE;
	if (sy < 0) sy = 0;
	if (ey > WINSIDE - 1) ey = WINSIDE - 1;
	XDrawLine(p->display, p->w, p->xfgc, dx, sy, dx, ey);
	p->clearline[0][p->clearlcount] = dx;
	p->clearline[1][p->clearlcount] = sy;
	p->clearline[2][p->clearlcount] = dx;
	p->clearline[3][p->clearlcount] = ey;
	p->clearlcount++;
    }
    if ((GWIDTH - p->p_x) < (WINSIDE / 2) * SCALE) {
	int	sy, ey;

	dx = (WINSIDE / 2) + (GWIDTH - p->p_x) / SCALE;
	sy = (WINSIDE / 2) + (0 - p->p_y) / SCALE;
	ey = (WINSIDE / 2) + (GWIDTH - p->p_y) / SCALE;
	if (sy < 0) sy = 0;
	if (ey > WINSIDE - 1) ey = WINSIDE - 1;
	XDrawLine(p->display, p->w, p->xfgc, dx, sy, dx, ey);
	p->clearline[0][p->clearlcount] = dx;
	p->clearline[1][p->clearlcount] = sy;
	p->clearline[2][p->clearlcount] = dx;
	p->clearline[3][p->clearlcount] = ey;
	p->clearlcount++;
    }
    if (p->p_y < (WINSIDE / 2) * SCALE) {
	int	sx, ex;

	dy = (WINSIDE / 2) - (p->p_y) / SCALE;
	sx = (WINSIDE / 2) + (0 - p->p_x) / SCALE;
	ex = (WINSIDE / 2) + (GWIDTH - p->p_x) / SCALE;
	if (sx < 0) sx = 0;
	if (ex > WINSIDE - 1) ex = WINSIDE - 1;
	XDrawLine(p->display, p->w, p->xfgc, sx, dy, ex, dy);
	p->clearline[0][p->clearlcount] = sx;
	p->clearline[1][p->clearlcount] = dy;
	p->clearline[2][p->clearlcount] = ex;
	p->clearline[3][p->clearlcount] = dy;
	p->clearlcount++;
    }
    if ((GWIDTH - p->p_y) < (WINSIDE / 2) * SCALE) {
	int	sx, ex;

	dy = (WINSIDE / 2) + (GWIDTH - p->p_y) / SCALE;
	sx = (WINSIDE / 2) + (0 - p->p_x) / SCALE;
	ex = (WINSIDE / 2) + (GWIDTH - p->p_x) / SCALE;
	if (sx < 0) sx = 0;
	if (ex > WINSIDE - 1) ex = WINSIDE - 1;
	XDrawLine(p->display, p->w, p->xfgc, sx, dy, ex, dy);
	p->clearline[0][p->clearlcount] = sx;
	p->clearline[1][p->clearlcount] = dy;
	p->clearline[2][p->clearlcount] = ex;
	p->clearline[3][p->clearlcount] = dy;
	p->clearlcount++;
    }

    /* Change border color to signify alert status */

    if (p->oldalert != (p->p_flags & (PFGREEN|PFYELLOW|PFRED))) {
        p->oldalert = (p->p_flags & (PFGREEN|PFYELLOW|PFRED));
	switch (p->oldalert) {
	    case PFGREEN:
	        if (!p->mono) {
		    XSetWindowBorder(p->display, p->baseWin, p->gColor);
		    XSetWindowBorder(p->display, p->iconWin, p->gColor);
	        } else {
		    XSetWindowBorderPixmap(p->display, p->baseWin, p->gTile);
		    XSetWindowBorderPixmap(p->display, p->iconWin, p->gTile);
		}
		break;
	    case PFYELLOW:
	        if (!p->mono) {
		    XSetWindowBorder(p->display, p->baseWin, p->yColor);
		    XSetWindowBorder(p->display, p->iconWin, p->yColor);
	        } else {
		    XSetWindowBorderPixmap(p->display, p->baseWin, p->yTile);
		    XSetWindowBorderPixmap(p->display, p->iconWin, p->yTile);
		}
		break;
	    case PFRED:
	        if (!p->mono) {
		    XSetWindowBorder(p->display, p->baseWin, p->rColor);
		    XSetWindowBorder(p->display, p->iconWin, p->rColor);
	        } else {
		    XSetWindowBorderPixmap(p->display, p->baseWin, p->rTile);
		    XSetWindowBorderPixmap(p->display, p->iconWin, p->rTile);
		}
		break;
	}
    }
}

/*
 * compute position of the end of the phasor
 * and return in tx and ty.
 */
phasedist(j, php, tx, ty)
    struct player *j;
    struct phaser *php;
    int *tx, *ty;
{
	*tx = j->p_x + (int) ((j->p_ship.s_phasedist) * Cos[php->ph_dir]);
	*ty = j->p_y + (int) ((j->p_ship.s_phasedist) * Sin[php->ph_dir]);
}

map(p)
register struct player	*p;
{
    register int		i;
    register struct player	*j;
    register struct planet	*l;
    int				dx, dy;
    char			glyph;

    if (p->mclearcount) {
	XFillRectangles(p->display, p->mapw, p->cleargc,
		p->mclearzone, p->mclearcount);
	p->mclearcount = 0;
    }

    /* Draw Planets */
    for (i = 0, l = &planets[0]; i < MAXPLANETS; i++, l++) {
	if (!(l->pl_flags & PLREDRAW) && (!p->redrawall))
	    continue;
	dx = l->pl_x * WINSIDE / GWIDTH;
	dy = l->pl_y * WINSIDE / GWIDTH;

	glyph = mplanetGlyph(l);
	XSetForeground(p->display, p->xfgc, planetColor(l));
	XDrawString(p->display, p->mapw, p->xfgc, dx - (mplanet_width / 2),
		dy - (mplanet_height / 2), &glyph, 1);
	XDrawImageString(p->display, p->mapw, p->dfgc, dx - (mplanet_width/2), dy + (mplanet_height/2 + p->dfont->ascent),
	    l->pl_name, 3);

/*
		p->mclearzone[p->mclearcount].x = dx - (mplanet_width/2);
		p->mclearzone[p->mclearcount].y = dy + (mplanet_height/2);
		NOTE: Put this calculation into player data
		p->mclearzone[p->mclearcount].width = XTextWidth(p->dfont, l->pl_name, 3);
		p->mclearzone[p->mclearcount].height = fontHeight(p->dfont);
		p->mclearcount++;
		p->mclearzone[p->mclearcount].x = dx - (mplanet_width/2);
		p->mclearzone[p->mclearcount].y = dy - (mplanet_height/2);
		p->mclearzone[p->mclearcount].width = mplanet_width;
		p->mclearzone[p->mclearcount].height = mplanet_height;
		p->mclearcount++;
*/
    }
    p->redrawall = 0;

    /* Draw ships */
    nplayers = 0;
    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
	char	*str;

	if (j->p_status != PALIVE)
	    continue;
	nplayers++;
	dx = j->p_x * WINSIDE / GWIDTH;
	dy = j->p_y * WINSIDE / GWIDTH;
	if (!(j->p_flags & PFCLOAK)) {
		/* NOTE: put these calculations into the player data */
	    XDrawImageString(p->display, p->mapw, p->dfgc, dx - XTextWidth(p->dfont, j->p_mapchars, 2), dy - fontHeight(p->dfont)/2 + p->dfont->ascent,
		str = j->p_mapchars, 2);
	    p->mclearzone[p->mclearcount].x = dx - XTextWidth(p->dfont, j->p_mapchars, 2);
	    p->mclearzone[p->mclearcount].y = dy - fontHeight(p->dfont)/2;
	    p->mclearzone[p->mclearcount].width = XTextWidth(p->dfont, str, 2);
	    p->mclearzone[p->mclearcount].height = fontHeight(p->dfont);
	    p->mclearcount++;
	}
    }
}

stline(p)
register struct player	*p;
{
    static char buf[80] = "               0    0    0  0    0.00   0        0    0     0";

    /* Instead of one sprintf, we do all this by hand for optimization */

    if (buf[0] == 0) {
	int i;
	for (i = 0; i < 63; ++i)
	    buf[i] = ' ';
    }

    buf[0] = (p->p_flags & PFSHIELD ? 'S': ' ');
    if (p->p_flags & PFGREEN)
	buf[1] = 'G';
    else if (p->p_flags & PFYELLOW)
	buf[1] = 'Y';
    else if (p->p_flags & PFRED)
	buf[1] = 'R';
    buf[2] = (p->p_flags & (PFPLLOCK | PFPLOCK) ? 'L': ' ');
    buf[3] = (p->p_flags & PFREPAIR ? 'R': ' ');
    buf[4] = (p->p_flags & PFBOMB ? 'B': ' ');
    buf[5] = (p->p_flags & PFORBIT ? 'O': ' ');
    buf[6] = (p->p_flags & PFCLOAK ? 'C': ' ');
    buf[7] = (p->p_flags & PFWEP ? 'W': ' ');
    buf[8] = (p->p_flags & PFENG ? 'E': ' ');
    buf[9] = (p->p_flags & PFBEAMUP ? 'u': ' ');
    buf[10] = (p->p_flags & PFBEAMDOWN ? 'd': ' ');
    buf[11] = (p->p_flags & PFCOPILOT ? 'P' : ' ');
    buf[12] = ' ';
    buf[13] = ' ';
    buf[14] = '0' + p->p_speed;	/* speed */
    buf[15] = ' ';
    buf[16] = ' ';
    buf[17] = ' ';
    buf[18] = ' ';
    buf[19] = '0' + (p->p_damage / 100);
    if (buf[19] == '0')
	buf[19] = ' ';
    buf[20] = '0' + ((p->p_damage % 100) / 10);
    if ((buf[20] == '0') && (p->p_damage < 100))
	buf[20] = ' ';
    buf[21] = '0' + (p->p_damage % 10);
    buf[22] = ' ';
    buf[23] = '0' + (p->p_shield / 100);
    if (buf[23] == '0')
	buf[23] = ' ';
    buf[24] = '0' + ((p->p_shield % 100) / 10);
    if ((buf[24] == '0') && (p->p_shield < 100))
	buf[24] = ' ';
    buf[25] = '0' + (p->p_shield % 10);
    buf[26] = ' ';
    buf[27] = ' ';
    buf[28] = '0' + ((p->p_ntorp % 100) / 10);
    if (buf[28] == '0')
	buf[28] = ' ';
    buf[29] = '0' + (p->p_ntorp % 10);
    buf[30] = ' ';
    buf[31] = ' ';
    buf[32] = ' ';
    buf[33] = '0' + ((int) (p->p_kills / 10));
    if (buf[33] == '0')
	buf[33] = ' ';
    buf[34] = '0' + (((int) p->p_kills) % 10);
    buf[35] = '.';
    buf[36] = '0' + (((int) (p->p_kills * 10)) % 10);
    buf[37] = '0' + (((int) (p->p_kills * 100)) % 10);
    buf[38] = ' ';
    buf[39] = ' ';
    buf[40] = ' ';
    buf[41] = '0' + ((p->p_armies % 100) / 10);
    if (buf[41] == '0')
	buf[41] = ' ';
    buf[42] = '0' + (p->p_armies % 10);
    buf[43] = ' ';
    buf[44] = ' ';

    buf[45] = '0' + (p->p_fuel / 10000);
    if (buf[45] == '0')
	buf[45] = ' ';
    buf[46] = '0' + ((p->p_fuel % 10000) / 1000);
    if ((buf[46] == '0') && (p->p_fuel < 10000))
	buf[46] = ' ';
    buf[47] = '0' + ((p->p_fuel % 1000) / 100);
    if ((buf[47] == '0') && (p->p_fuel < 1000))
	buf[47] = ' ';
    buf[48] = '0' + ((p->p_fuel % 100) / 10);
    if ((buf[48] == '0') && (p->p_fuel < 100))
	buf[48] = ' ';
    buf[49] = '0' + (p->p_fuel % 10);
    buf[50] = ' ';
    buf[51] = ' ';

    buf[52] = '0' + ((p->p_wtemp / 10) / 100);
    if (buf[52] == '0')
	buf[52] = ' ';
    buf[53] = '0' + (((p->p_wtemp / 10) % 100) / 10);
    if ((buf[53] == '0') && (p->p_wtemp < 1000))
	buf[53] = ' ';
    buf[54] = '0' + ((p->p_wtemp / 10) % 10);

    buf[55] = ' ';
    buf[56] = ' ';
    buf[57] = ' ';

    buf[58] = '0' + ((p->p_etemp / 10) / 100);
    if (buf[58] == '0')
	buf[58] = ' ';
    buf[59] = '0' + (((p->p_etemp / 10) % 100) / 10);
    if ((buf[59] == '0') && (p->p_etemp < 1000))
	buf[59] = ' ';
    buf[60] = '0' + ((p->p_etemp / 10) % 10);
    buf[61] = '\0';

    /* Draw status line */
    if (!p->ts_offset)
	redrawTstats(p);
    XDrawImageString(p->display, p->tstatw, p->dfgc, p->ts_offset, 20 + p->dfont->ascent, buf, 61);

#ifdef notdef

    /* This code is being left around because it is much more elegant
    ** than that above.  However, it lacks a tremendous amount in efficiency.
    */
    char alertchar = '?';

    if (me->p_flags & PFGREEN)
	alertchar = 'G';
    else if (me->p_flags & PFYELLOW)
	alertchar = 'Y';
    else if (me->p_flags & PFRED)
	alertchar = 'R';
    /* Draw status line */
    sprintf(buf,
"%c%c%c%c%c%c%c%c%c%c%c%c   %1d  %3d %3d  %2d    %5.2f  %2d    %5d   %3d   %3d",
	(me->p_flags & PFSHIELD ? 'S': ' '),
	alertchar,
	(me->p_flags & (PFPLLOCK | PFPLOCK) ? 'L': ' '),
	(me->p_flags & PFREPAIR ? 'R': ' '),
	(me->p_flags & PFBOMB ? 'B': ' '),
	(me->p_flags & PFORBIT ? 'O': ' '),
	(me->p_flags & PFCLOAK ? 'C': ' '),
	(me->p_flags & PFWEP ? 'W': ' '),
	(me->p_flags & PFENG ? 'E': ' '),
	(me->p_flags & PFBEAMUP ? 'u': ' '),
	(me->p_flags & PFBEAMDOWN ? 'd': ' '),
	(me->p_flags & PFCOPILOT ? 'P' : ' '),
	me->p_speed,
	me->p_damage,
	me->p_shield,
	me->p_ntorp,
	me->p_kills,
	me->p_armies,
	me->p_fuel,
	me->p_wtemp/10,
	me->p_etemp/10);
    XDrawImageString(display, tstatw, dfgc, 50, 20, buf, strlen(buf));
    XFlush();

#endif notdef
}

/* These are routines that need to be done on interrupts but
   don't belong in the redraw routine and particularly don't
   belong in the daemon. */

auto_features(p)
register struct player	*p;
{
    register int		i;
    char buf[80];
    struct player *pl;
    struct planet *pln;

#ifdef notdef
	/* NOTE: this will be handled elsewhere */
    if (p->copilot && (!(me->p_flags & PFCOPILOT))) {
	printf("Owning player has kicked you out\n");
	exit(0);
    }
#endif
    if (p->p_flags & PFSELFDEST) {
#ifdef notdef
	if ((p->p_updates >= p->selfdest) ||
	    ((p->p_flags & PFGREEN) && (p->p_damage == 0)
		&& (p->p_shield == 100))) {
#endif
	if (p->p_updates >= p->selfdest) {
	    p->p_flags &= ~PFSELFDEST;
	    p->p_explode = 10;
	    p->p_whydead = KQUIT;
	    p->p_status = PEXPLODE;
	}
	else {
	    sprintf(buf, "Self Destruct in %d seconds",
		(p->selfdest - p->p_updates) / UPS);
	    warning(p, buf);
	}
    }
    /* give certain information about bombing or beaming */
    if (p->p_flags & PFBOMB) {
	if (planets[p->p_planet].pl_armies < 5) {
	    sprintf(buf, "Cannot bomb %s while armies are less than 5",
		planets[p->p_planet].pl_name);
	    warning(p, buf);
	    p->p_flags &= ~PFBOMB;
	}
	else {
	    sprintf(buf, "Bombing %s.  %d armies left",
		planets[p->p_planet].pl_name,
		planets[p->p_planet].pl_armies);
	    warning(p, buf);
	}
    }

    if (p->p_flags & PFBEAMUP) {
	if (planets[p->p_planet].pl_armies < 5) {
	    sprintf(buf, "%s: Too few armies to beam up",
		planets[p->p_planet].pl_name);
	    warning(p, buf);
	    p->p_flags &= ~PFBEAMUP;
	}
	else if ((p->p_armies == (int) (p->p_kills * 2)) ||
	    (p->p_armies == p->p_ship.s_maxarmies)) {
		sprintf(buf, "No more room on board for armies");
	    warning(p, buf);
	    p->p_flags &= ~PFBEAMUP;
	}
	else {
	    sprintf(buf, "Beaming up.  (%d/%d)", p->p_armies,
		((p->p_kills * 2) > p->p_ship.s_maxarmies) ?
		    p->p_ship.s_maxarmies : (int) (p->p_kills * 2));
	    warning(p, buf);
	}
    }
    if (p->p_flags & PFBEAMDOWN) {
	if (p->p_armies == 0) {
	    sprintf(buf, "No more armies to beam down to %s.",
		planets[p->p_planet].pl_name);
	    warning(p, buf);
	    p->p_flags &= ~PFBEAMDOWN;
	}
	else {
	    sprintf(buf, "Beaming down.  (%d/%d) %s has %d armies left",
		p->p_armies,
		((p->p_kills * 2) > p->p_ship.s_maxarmies) ?
		    p->p_ship.s_maxarmies : (int) (p->p_kills * 2),
		planets[p->p_planet].pl_name,
		planets[p->p_planet].pl_armies);
	    warning(p, buf);
	}
    }
    if (p->p_flags & PFREPAIR) {
	if ((p->p_damage == 0) && (p->p_shield == 100))
		p->p_flags &= ~PFREPAIR;
    }
    if (p->p_flags & PFPLOCK) { 	/* set course to player x */
	pl = &players[p->p_playerl];
	if (pl->p_status != PALIVE)
	    p->p_flags &= ~PFPLOCK;
	set_course(p, newcourse(p, pl->p_x, pl->p_y));
    }
    if (p->p_flags & PFPLLOCK) { 	/* set course to planet x */
	int dist;
	pln = &planets[p->p_planet];
	dist = hypot((double) (p->p_x - pln->pl_x),
	    (double) (p->p_y - pln->pl_y));

	/* This is magic.  It should be based on defines, but it slows
	   the ship down to warp two an appropriate distance from the
	   planet for orbit */

	if (dist < (50 * ((p->p_speed * (p->p_speed+1)) + 10)))
	    set_speed(p, ORBSPEED);
	if ((dist < ORBDIST) && (p->p_speed <= ORBSPEED))  {
	    p->p_flags &= ~PFPLLOCK;
	    orbit(p);
	}
	else {
	    set_course(p, newcourse(p, pln->pl_x, pln->pl_y));
	}
    }
}

unsigned char
newcourse(p, x, y)
register struct player	*p;
register int		x, y;
{
	return((unsigned char) (atan2((double) (x - p->p_x),
	    (double) (p->p_y - y)) / 3.14159 * 128.));
}

redrawTstats(p)
register struct player	*p;
{
    char	buf[BUFSIZ];

    sprintf(buf, 
	"Flags        warp  dam shd torps kills armies fuel wtemp etemp");
    if (!p->ts_offset)
	p->ts_offset = (WINSIDE - XTextWidth(p->dfont, buf, strlen(buf))) / 2;
    XDrawImageString(p->display, p->tstatw, p->dfgc, p->ts_offset, 10 + p->dfont->ascent, buf, strlen(buf));
}