view redraw.c @ 3:5a977ccbc7a9 default tip

Empty changelog
author darius
date Sat, 06 Dec 1997 05:41:29 +0000
parents
children
line wrap: on
line source

/*
 * redraw.c
 */
#include "copyright.h"

#include <stdio.h>
#include <signal.h>
#include <math.h>
#include <ctype.h>
#include "Wlib.h"
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "packets.h"
#include "proto.h"
#include "gameconf.h"
#ifdef SOUND
#include "Slib.h"
#endif
#include "sound.h"

typedef struct tractor Tractor;
struct tractor {
    int     sx, sy, d1x, d1y, d2x, d2y;	/* source (x,y) dest (x1,y1) (x2,y2) */
    Tractor *next;
}      *tracthead = NULL, *tractcurrent = NULL, *tractrunner;

struct _clearzone *
new_czone()
{
    if (clearzone == 0) {
	czsize = 10;
	clearzone = (struct _clearzone *) malloc(sizeof(*clearzone) * czsize);
	clearcount = 0;
    } else if (clearcount >= czsize) {
	clearzone = (struct _clearzone *) realloc(clearzone,
					sizeof(*clearzone) * (czsize *= 2));
    }
    return &clearzone[clearcount++];
}

/* Prototypes */
static void local P((void));
#ifndef COW_HAS_IT_WHY_SHOULDNT_WE
static
#endif
void map P((void));
static void redraw P((void));
/* static void stline P((int flag));*/
static W_Icon planetBitmap P((struct planet * p));
static W_Icon planetmBitmap P((struct planet * p));

void
intrupt()
{
    static long lastread;
    static struct timeval lastredraw = {0, 0};
    struct timeval t;
    static int needredraw=0;

#ifndef __osf__
    long    time();
#endif

    udcounter++;
    
    needredraw += readFromServer();

    gettimeofday(&t, NULL);
    if (needredraw && ((unsigned int) redrawDelay * 100000 <
                       (unsigned int) ((t.tv_sec - lastredraw.tv_sec) * 1000000
                                       + (t.tv_usec - lastredraw.tv_usec)))) {
	needredraw = 0;
        lastredraw=t;
#if 0
	lastread = time(NULL);
#endif
#ifdef RECORDER
	if (!playback || (pb_update && 
			  ((!pb_scan) || !(udcounter % pb_advance))))
#endif
	{
	    redraw();
	    playerlist2();
	}
#ifdef RECORDER
	if (playback) {
	    if(!pb_scan) {
		if (pb_advance > 0) {
		    if ((pb_advance -= pb_update) <= 0) {
			pb_advance = 0;
			paused = 1;
		    }
		} else if (pb_advance < 0) {
		    switch (pb_advance) {
		    case PB_REDALERT:
			if (me->p_flags & PFRED) {
			    pb_advance = 0;
			    paused = 1;
			}
			break;
		    case PB_YELLOWALERT:
			if (me->p_flags & PFYELLOW) {
			    pb_advance = 0;
			    paused = 1;
			}
			break;
		    case PB_DEATH:
		    default:
			if (me->p_status != PALIVE) {
			    pb_advance = 0;
			paused = 1;
			}
			break;
		    }
		}
	    }
	    pb_update = 0;
	}
	if (recordGame)
	    writeUpdateMarker();
#endif
    }
#if 0
    if (lastread + 3 < time(NULL)) {
	/*
	   We haven't heard from server for awhile... Strategy:  send a
	   useless packet to "ping" server.
	*/
	sendWarReq(me->p_hostile);
    }
#endif
    if (me->p_status == POUTFIT) {
	death();
    }
}

static void
redraw()
{

    /* erase warning line if necessary */
    if ((warntimer <= udcounter) && (warncount > 0)) {
#ifndef AMIGA
	/* XFIX */
	W_ClearArea(warnw, 5, 5, W_Textwidth * warncount, W_Textheight);
#else
	W_ClearWindow(warnw);
#endif
	warncount = 0;
    }
    if (W_FastClear) {
	W_ClearWindow(w);
	clearcount = 0;
	clearlcount = 0;
	tractcurrent = tracthead;
    } else {
#if 0
	/* just to save a little time on all the function calls */
	/* all the normal clear functions are implemented as well. */
	W_FlushClearZones(w, clearzone, clearcount);
	clearcount = 0;
#else
	while (clearcount) {
	    clearcount--;
	    /* XFIX */
	    W_CacheClearArea(w, clearzone[clearcount].x,
		       clearzone[clearcount].y, clearzone[clearcount].width,
			     clearzone[clearcount].height);

	    /*
	       W_ClearArea(w, clearzone[clearcount].x,
	       clearzone[clearcount].y, clearzone[clearcount].width,
	       clearzone[clearcount].height);
	    */
	}
#endif
	while (clearlcount) {
	    clearlcount--;
	    /* XFIX */
	    W_CacheLine(w, clearline[0][clearlcount],
			clearline[1][clearlcount], clearline[2][clearlcount],
			clearline[3][clearlcount], backColor);
	    /*
	       W_MakeLine(w, clearline[0][clearlcount],
	       clearline[1][clearlcount], clearline[2][clearlcount],
	       clearline[3][clearlcount], backColor);
	    */
	}
	/* XFIX */
#ifndef AMIGA
	W_FlushClearAreaCache(w);
	W_FlushLineCaches(w);
#endif
	/* erase the tractor lines [BDyess] */
	for (tractrunner = tracthead; tractrunner != tractcurrent;
	     tractrunner = tractrunner->next) {
	    W_MakeTractLine(w, tractrunner->sx, tractrunner->sy,
			    tractrunner->d1x, tractrunner->d1y,
			    backColor);
	    W_MakeTractLine(w, tractrunner->sx, tractrunner->sy,
			    tractrunner->d2x, tractrunner->d2y,
			    backColor);
	}
	tractcurrent = tracthead;
    }

    local();			/* redraw local window */

#ifdef AMIGA			/* would do it in W_EventsPending, just have
				   it here so the display is updated sooner. */
    W_Flush();
#endif

    /* XFIX */
    W_FlushLineCaches(w);

    stline(0);

    if (W_IsMapped(statwin))
	updateStats();

    updateInform();		/* check and update info window [BDyess] */

    /* XFIX: last since its least accurate information */
    if (mapmode)
	map();

}

static W_Icon terrainBitmap(int x, int y)
{
   int aster_bm = 0;
   int aster_fluff = 0;
   
   /* is no asteroids, then return fluff if adjacent 'roids */
   if (!(terrainInfo[x*250 + y].types & T_ASTEROIDS)) aster_fluff = 1;

   /* check surrounding terrain */
   if (x > 0)
      if (terrainInfo[(x-1)*250 + y].types & T_ASTEROIDS)
	 aster_bm |= (1<<0);
   if (x < 249)
      if (terrainInfo[(x+1)*250 + y].types & T_ASTEROIDS) 
	 aster_bm |= (1<<2);
   if (y > 0)
      if (terrainInfo[x*250 + y-1].types & T_ASTEROIDS) 
	 aster_bm |= (1<<3);
   if (y < 249)
      if (terrainInfo[x*250 + y+1].types & T_ASTEROIDS) 
	 aster_bm |= (1<<1);
   
   if (aster_fluff && aster_bm) return asteroidfluff[(x*250 + y)%3];
   else return asteroidBM[aster_bm];
}

static  W_Icon
planetBitmap(p)
    register struct planet *p;
{
    int     i;
    if (paradise) {
	switch (PL_TYPE(*p)) {
	case PLWHOLE:
	    return wormBM[udcounter % WORMFRAMES];
	    break;
	case PLSTAR:
	    return starBM[udcounter % STARFRAMES];
	    break;
	case PLAST:
	    return basteroid[0];
	}
    }
    if (showlocal == 2) {
	return (bplanets[0]);
    } else if (p->pl_info & idx_to_mask(me->p_teami)) {
	if (showlocal == 1 || showlocal == 4) {
	    i = 0;
	    if ((paradise) && (p->pl_flags & PLSHIPYARD))
		i += 8;
	    if (p->pl_armies > 4)
		i += 4;
	    if (p->pl_flags & PLREPAIR)
		i += 2;
	    if (p->pl_flags & PLFUEL)
		i += 1;
	    return ((showlocal == 1 ? bplanets2 : bplanetsMOO)[i]);
	} else if (showlocal == 0) {
	    int     team = mask_to_idx(p->pl_owner);
	    if (team < -1)
		team = -1;
	    else if (team >= number_of_teams)
		team = number_of_teams - 1;
	    return (bplanets[1 + team]);
	} else {
	    int     mask;
	    if (paradise)
		mask = (p->pl_flags & PLSURMASK) >> PLSURSHIFT;
	    else {
		mask = ((p->pl_flags & PLFUEL) ? 1 : 0)
		    | ((p->pl_flags & PLREPAIR) ? 2 : 0)
		    | ((p->pl_flags & PLAGRI) ? 4 : 0);
	    }
	    return bplanetsr[mask];
	}
    } else {
	return (bplanets[5]);
    }
}


static  W_Icon
planetmBitmap(p)
    register struct planet *p;
{
    int     i;
    if (paradise) {
	switch (p->pl_flags & PLTYPEMASK) {
	case PLSTAR:
	    return mstarBM;
	case PLAST:
	    return mbasteroid[0];
#ifdef VISIBLE_WORMHOLES
	case PLWHOLE:
	    return mholeBM;
#endif /*VISIBLE_WORMHOLES*/
	}
    }
    if (showgalactic == 2) {
	return (mbplanets[0]);
    } else if (showgalactic == 4) {
	int     infoage = 4;
	if (!(p->pl_info & idx_to_mask(me->p_teami)))
	    return mbplanetsA[NSCOUTAGES - 1];
	if (p->pl_owner == idx_to_mask(me->p_teami))
	    return mbplanetsA[0];

	for (i = 0;
	   i < NSCOUTAGES - 1 && infoage < status2->clock - p->pl_timestamp;
	     i++, infoage = infoage * 5 / 3) {
	}
	return mbplanetsA[i];
    } else if (p->pl_info & idx_to_mask(me->p_teami)) {
	if (showgalactic == 1 || showgalactic == 5) {
	    i = 0;
	    if ((paradise) && (p->pl_flags & PLSHIPYARD))
		i += 8;
	    if (p->pl_armies > 4)
		i += 4;
	    if (p->pl_flags & PLREPAIR)
		i += 2;
	    if (p->pl_flags & PLFUEL)
		i += 1;
	    return ((showgalactic == 1 ? mbplanets2 : mbplanetsMOO)[i]);
	} else if (showgalactic == 0) {
	    int     team = mask_to_idx(p->pl_owner);
	    if (team < -1)
		team = -1;
	    else if (team >= number_of_teams)
		team = number_of_teams - 1;
	    return (mbplanets[1 + team]);
	} else {
	    int     mask;
	    if (paradise)
		mask = (p->pl_flags & PLSURMASK) >> PLSURSHIFT;
	    else {
		mask = ((p->pl_flags & PLFUEL) ? 1 : 0)
		    | ((p->pl_flags & PLREPAIR) ? 2 : 0)
		    | ((p->pl_flags & PLAGRI) ? 4 : 0);
	    }
	    return mbplanetsr[mask];
	}
    } else {
	return (mbplanets[5]);
    }
}

/* call this from local for each player, instead of having an extra loop! */
static void
redraw_photon_torps(j)
    struct player *j;
{
    int     i, h;
    struct torp *k;
    int     dx, dy;
    int     view;
    struct _clearzone *cz;

    view = SCALE * WINSIDE / 2;
    i = j->p_no;
    if (!j->p_ntorp)
	return;
    for (h = 0, k = &torps[ntorps * i + h]; h < ntorps; h++, k++) {
	if (!k->t_status)
	    continue;
	dx = k->t_x - me->p_x;
	dy = k->t_y - me->p_y;
	if (ABS(dx) > view || ABS(dy) > view) {
	    /* Call any torps off screen "free" (if owned by other) */
	    if (k->t_status == TEXPLODE && j != me) {
		k->t_status = TFREE;
		j->p_ntorp--;
	    }
	    continue;
	}
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
#ifdef UNIX_SOUND
        if ((k->t_status == TEXPLODE) && (k->t_fuse == 5)) play_sound (SND_TORPHIT);
#endif
	if (k->t_status == TEXPLODE) {

	    k->t_fuse--;
	    if (k->t_fuse <= 0) {
		k->t_status = TFREE;
		j->p_ntorp--;
		continue;
	    }
	    if (k->t_fuse >= NUMDETFRAMES) {
		k->t_fuse = NUMDETFRAMES - 1;
	    }
	    W_WriteBitmap(dx - (cloud_width / 2), dy - (cloud_height / 2),
			  cloud[k->t_fuse], torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (cloud_width / 2);
	    cz->y = dy - (cloud_height / 2);
	    cz->width = cloud_width;
	    cz->height = cloud_height;
	} else if (k->t_owner != me->p_no && ((k->t_war & idx_to_mask(me->p_teami)) ||
					      (idx_to_mask(players[k->t_owner].p_teami) & (me->p_hostile | me->p_swar)))) {
	    /*
	       solid.  Looks strange. W_FillArea(w, dx - (etorp_width/2), dy
	       - (etorp_height/2), etorp_width, etorp_height, torpColor(k));
	    */

#ifdef BORGTEST
	    W_CacheLine(w, dx - (etorp_width / 2), dy - (etorp_height / 2),
			dx + (etorp_width / 2), dy + (etorp_height / 2),
			(k->t_turns == 32767) ? notColor(k) : torpColor(k));
	    W_CacheLine(w, dx + (etorp_width / 2), dy - (etorp_height / 2),
			dx - (etorp_width / 2), dy + (etorp_height / 2),
			(k->t_turns == 32767) ? notColor(k) : torpColor(k));
#else
#ifdef TORPBITS
	    /*
	       went back to this for Amiga, one bitmap is faster than 2
	       lines.
	     */
	    W_WriteBitmap(dx - (etorp_width / 2), dy - (etorp_height / 2),
			  etorp, torpColor(k));
#else
	    /* XFIX */
	    if (0 && k->frame) {
		W_CacheLine(w, dx - 2, dy,
			    dx + 2, dy, torpColor(k));
		W_CacheLine(w, dx, dy - 2,
			    dx, dy + 2, torpColor(k));
	    } else {
		W_CacheLine(w, dx - 1, dy - 1,
			    dx + 1, dy + 1, torpColor(k));
		W_CacheLine(w, dx + 1, dy - 1,
			    dx - 1, dy + 1, torpColor(k));
	    }
	    k->frame = !k->frame;
#endif				/* TORPBITS */
#endif

	    cz = new_czone();
	    cz->x = dx - (etorp_width / 2);
	    cz->y = dy - (etorp_height / 2);
	    cz->width = etorp_width;
	    cz->height = etorp_height;
	} else {
	    /* XFIX */

	    if (0 /* animateTorps */ ) {
		switch (k->frame) {
		case 0:
		    W_CacheLine(w, dx - (mtorp_width / 2), dy, dx,
				dy, torpColor(k));
		    break;
		case 1:
		    W_CacheLine(w, dx - (mtorp_width / 2), dy - (mtorp_width / 2),
				dx, dy, torpColor(k));
		    break;
		case 2:
		    W_CacheLine(w, dx, dy, dx,
				dy + (mtorp_width / 2), torpColor(k));
		    break;
		case 3:
		    W_CacheLine(w, dx, dy,
				dx + (mtorp_width / 2), dy - (mtorp_width / 2), torpColor(k));
		    break;
		case 4:
		    W_CacheLine(w, dx, dy, dx + (mtorp_width / 2),
				dy, torpColor(k));
		    break;
		case 5:
		    W_CacheLine(w, dx - (mtorp_width / 2), dy - (mtorp_width / 2),
				dx, dy, torpColor(k));
		    break;
		case 6:
		    W_CacheLine(w, dx, dy - (mtorp_width / 2), dx,
				dy, torpColor(k));
		    break;
		case 7:
		    W_CacheLine(w, dx - (mtorp_width / 2), dy - (mtorp_width / 2),
				dx, dy, torpColor(k));
		    break;
		}
		k->frame++;
		if (k->frame > 7)
		    k->frame = 0;
	    } else {
#ifdef TORPBITS
		W_WriteBitmap(dx - (mtorp_width / 2), dy - (mtorp_height / 2),
			      mtorp, torpColor(k));
#else
		W_CacheLine(w, dx - (mtorp_width / 2), dy,
			    dx + (mtorp_width / 2), dy, torpColor(k));
		W_CacheLine(w, dx, dy - (mtorp_width / 2),
			    dx, dy + (mtorp_width / 2), torpColor(k));
#endif
	    }

	    cz = new_czone();
	    cz->x = dx - (mtorp_width / 2);
	    cz->y = dy - (mtorp_height / 2);
	    cz->width = mtorp_width;
	    cz->height = mtorp_height;
	}
    }
}

static void
draw_one_thingy(k)
    struct thingy *k;
{
    int     dx, dy;
    int     view;
    struct _clearzone *cz;
    view = SCALE * WINSIDE / 2;

    if (k->t_shape == SHP_BLANK)
	return;
    /* printf("%d,%d - %d,%d\n", me->p_x, me->p_y, k->t_x, k->t_y); */
    dx = k->t_x - me->p_x;
    dy = k->t_y - me->p_y;
    if (ABS(dx) > view || ABS(dy) > view) {
	return;
    }
    dx = dx / SCALE + WINSIDE / 2;
    dy = dy / SCALE + WINSIDE / 2;
    switch (k->t_shape) {
    case SHP_BOOM:
	k->t_fuse--;
	if (k->t_fuse <= 0) {
	    k->t_shape = SHP_BLANK;
	    return;
	}
	if (k->t_fuse >= NUMDETFRAMES) {
	    k->t_fuse = NUMDETFRAMES - 1;
	}
	W_WriteBitmap(dx - (cloud_width / 2), dy - (cloud_height / 2),
		      cloud[k->t_fuse], droneColor(k));
	cz = new_czone();
	cz->x = dx - (cloud_width / 2);
	cz->y = dy - (cloud_height / 2);
	cz->width = cloud_width;
	cz->height = cloud_height;
	break;
    case SHP_MISSILE:
	{
	    int     dview = (int) (k->t_dir * NDRONEVIEWS + 128) / 256;
	    if (dview >= NDRONEVIEWS)
		dview -= NDRONEVIEWS;
	    W_WriteBitmap
		(dx - (drone_width / 2), dy - (drone_height / 2),
		 drone_bm[dview],
		 droneColor(k));
	}
	cz = new_czone();
	cz->x = dx - (drone_width / 2);
	cz->y = dy - (drone_height / 2);
	cz->width = drone_width;
	cz->height = drone_height;
	break;
    case SHP_TORP:
	if (k->t_owner != me->p_no &&
	    ((k->t_war & idx_to_mask(me->p_teami)) ||
	     (idx_to_mask(players[k->t_owner].p_teami) & (me->p_hostile | me->p_swar)))) {
	    W_CacheLine(w, dx - (etorp_width / 2), dy - (etorp_height / 2),
	     dx + (etorp_width / 2), dy + (etorp_height / 2), torpColor(k));
	    W_CacheLine(w, dx + (etorp_width / 2), dy - (etorp_height / 2),
	     dx - (etorp_width / 2), dy + (etorp_height / 2), torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (etorp_width / 2);
	    cz->y = dy - (etorp_height / 2);
	    cz->width = etorp_width;
	    cz->height = etorp_height;
	} else {
	    W_CacheLine(w, dx - (mtorp_width / 2), dy, dx + (mtorp_width / 2), dy,
			torpColor(k));
	    W_CacheLine(w, dx, dy - (mtorp_width / 2), dx, dy + (mtorp_width / 2),
			torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (mtorp_width / 2);
	    cz->y = dy - (mtorp_height / 2);
	    cz->width = mtorp_width;
	    cz->height = mtorp_height;
	}
	break;
    case SHP_PLASMA:
    case SHP_MINE:		/* use plasma until I get a nifty bitmap */
	if (k->t_owner != me->p_no &&
	    ((k->t_war & idx_to_mask(me->p_teami)) ||
	     (idx_to_mask(players[k->t_owner].p_teami) & (me->p_hostile | me->p_swar)))) {
	    W_WriteBitmap(dx - (eplasmatorp_width / 2),
			  dy - (eplasmatorp_height / 2),
			  eplasmatorp, torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (eplasmatorp_width / 2);
	    cz->y = dy - (eplasmatorp_height / 2);
	    cz->width = eplasmatorp_width;
	    cz->height = eplasmatorp_height;
	} else {
	    W_WriteBitmap(dx - (mplasmatorp_width / 2),
			  dy - (mplasmatorp_height / 2),
			  mplasmatorp, torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (mplasmatorp_width / 2);
	    cz->y = dy - (mplasmatorp_height / 2);
	    cz->width = mplasmatorp_width;
	    cz->height = mplasmatorp_height;
	}
	break;
    case SHP_PBOOM:
	k->t_fuse--;
	if (k->t_fuse <= 0) {
	    k->t_shape = SHP_BLANK;
	    return;
	}
	if (k->t_fuse >= NUMDETFRAMES) {
	    k->t_fuse = NUMDETFRAMES - 1;
	}
	W_WriteBitmap(dx - (plasmacloud_width / 2),
		      dy - (plasmacloud_height / 2),
		      plasmacloud[k->t_fuse], torpColor(k));
	cz = new_czone();
	cz->x = dx - (plasmacloud_width / 2);
	cz->y = dy - (plasmacloud_height / 2);
	cz->width = plasmacloud_width;
	cz->height = plasmacloud_height;
	break;
    case SHP_FIGHTER:
	{
	    int     fview = (int) (k->t_dir * VIEWS + 128) / 256;
	    if (fview >= VIEWS)
		fview -= VIEWS;
	    W_WriteBitmap(dx - (fighter_width / 2),
			  dy - (fighter_height / 2),
			  fighter[fview], torpColor(k));
	    cz = new_czone();
	    cz->x = dx - (fighter_width / 2);
	    cz->y = dy - (fighter_height / 2);
	    cz->width = fighter_width;
	    cz->height = fighter_height;
	}
	break;
    case SHP_WARP_BEACON:
	{
	    cz = new_czone();
	    cz->x = dx - (warpbeacon_width / 2);
	    cz->y = dy - (warpbeacon_height / 2);
	    cz->width = warpbeacon_width;
	    cz->height = warpbeacon_height;
	    W_WriteBitmap(cz->x, cz->y,
			  warpbeacon, W_White);
	    if (k->t_fuse > 4) {
		W_WriteBitmap(cz->x, cz->y,
			      wbflash, shipCol[1 + mask_to_idx(k->t_owner)]);
	    }
	    if (++(k->t_fuse) > 6)
		k->t_fuse = 0;
	}
    }
}

static void
redraw_drones(j)
    struct player *j;
{
    int     i, h;
    int     count;

    i = j->p_no;

    if (!j->p_ndrone)
	return;
    count = 0;

    for (h = i * npthingies; h < npthingies * (i + 1); h++) {
	draw_one_thingy(&thingies[h]);
	if (thingies[h].t_shape != SHP_BLANK)
	    count++;
    }
    j->p_ndrone = count;
}

static void
redraw_other_drones()
{
    int     h;

    for (h = 0; h < ngthingies; h++)
	draw_one_thingy(&thingies[nplayers * npthingies + h]);
}

static void
redraw_plasma_torps(j)
    struct player *j;
{
    int     h, i;
    register struct plasmatorp *pt;
    struct _clearzone *cz;

    int     dx, dy;
    int     view;

    view = SCALE * WINSIDE / 2;
    i = j->p_no;

    if (!j->p_nplasmatorp)
	return;
    for (h = 0, pt = &plasmatorps[nplasmas * i + h]; h < nplasmas; h++, pt++) {
	if (!pt->pt_status)
	    continue;
	dx = pt->pt_x - me->p_x;
	dy = pt->pt_y - me->p_y;
	if (ABS(dx) > view || ABS(dy) > view)
	    continue;
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
#ifdef UNIX_SOUND
        if ((pt->pt_status == TEXPLODE) && (pt->pt_fuse == 5))
                play_sound (SND_TORPHIT); /* Torp Hit used for Plasma Hit */
#endif
	if (pt->pt_status == PTEXPLODE) {
	    pt->pt_fuse--;
	    if (pt->pt_fuse <= 0) {
		pt->pt_status = PTFREE;
		j->p_nplasmatorp--;
		continue;
	    }
	    if (pt->pt_fuse >= NUMDETFRAMES) {
		pt->pt_fuse = NUMDETFRAMES - 1;
	    }
	    W_WriteBitmap(dx - (plasmacloud_width / 2),
			  dy - (plasmacloud_height / 2),
			  plasmacloud[pt->pt_fuse], plasmatorpColor(pt));
	    cz = new_czone();
	    cz->x = dx - (plasmacloud_width / 2);
	    cz->y = dy - (plasmacloud_height / 2);
	    cz->width = plasmacloud_width;
	    cz->height = plasmacloud_height;
	}
	/* needmore: if(pt->pt_war & idx_to_mask(me->p_teami)) */
	else if (pt->pt_owner != me->p_no && ((pt->pt_war & idx_to_mask(me->p_teami)) ||
					      (idx_to_mask(players[pt->pt_owner].p_teami) & (me->p_hostile | me->p_swar)))) {
	    W_WriteBitmap(dx - (eplasmatorp_width / 2),
			  dy - (eplasmatorp_height / 2),
			  eplasmatorp, plasmatorpColor(pt));
	    cz = new_czone();
	    cz->x = dx - (eplasmatorp_width / 2);
	    cz->y = dy - (eplasmatorp_height / 2);
	    cz->width = eplasmatorp_width;
	    cz->height = eplasmatorp_height;
	} else {
	    W_WriteBitmap(dx - (mplasmatorp_width / 2),
			  dy - (mplasmatorp_height / 2),
			  mplasmatorp, plasmatorpColor(pt));
	    cz = new_czone();
	    cz->x = dx - (mplasmatorp_width / 2);
	    cz->y = dy - (mplasmatorp_height / 2);
	    cz->width = mplasmatorp_width;
	    cz->height = mplasmatorp_height;
	}
    }
}

#ifdef HOCKEY
void tactical_hockey P((void));
#endif

void
redraw_terrain()
{
   int i,j;
   int view;
   int nx, ny; /* for adjusted coords, based on ship position */
   int tx, ty, x; /* terrain grid x and y for 0,0 on the local */
   struct _clearzone *cz;
   
   view = SCALE * WINSIDE / 2;
   
   nx = (int) ((me->p_x - view) / SCALE)%terrain_width;
   ny = (int) ((me->p_y - view) / SCALE)%terrain_height;

   ty = (int) ((me->p_y - view)/(GWIDTH/250));
   x = tx = (int) ((me->p_x - view)/(GWIDTH/250));
   if (ty < 0) ty = 0;
   if (tx < 0) {
      tx = 0;
      x = 0;
   }

   if(received_terrain_info) {
      for (i=0; i < WINSIDE; i += terrain_height) {
	 for (j=0; j < WINSIDE; j += terrain_width) {
	    if ((terrainInfo[tx*250+ty].types & T_ASTEROIDS) ||
		((tx > 0) && (terrainInfo[(tx-1)*250+ty].types & T_ASTEROIDS)) ||
		((tx < 249) && (terrainInfo[(tx+1)*250+ty].types & T_ASTEROIDS)) ||
		((ty > 0) && (terrainInfo[tx*250+(ty-1)].types & T_ASTEROIDS)) ||
		((tx < 249) && (terrainInfo[tx*250+(ty+1)].types & T_ASTEROIDS))) {
	       W_WriteBitmap(j-nx, i-ny, terrainBitmap(tx,ty), W_Grey);
	       cz = new_czone();
	       cz->x = j-nx;
	       cz->y = i-ny;
	       cz->width = terrain_width;
	       cz->height = terrain_height;
	    } 
	    tx++;
	    if (tx >= 250) {
	       tx = x;
	       break;
	    }
	 }
	 ty++;
	 if (ty >= 250) break;
	 tx = x;
      }
   }
}

void
redraw_all_planets()
{
    int     view;
    int     i;
    int     dx, dy;
    struct _clearzone *cz;
    struct planet *l;
    int     nplan;

    view = SCALE * WINSIDE / 2;
    nplan = paradise ? nplanets : 40;

#ifdef HOCKEY
    if(hockey) {
      tactical_hockey();
    }
#endif /*HOCKEY*/
    for (i = 0, l = &planets[i]; i < nplan; i++, l++) {
	dx = l->pl_x - me->p_x;
	dy = l->pl_y - me->p_y;
	if (ABS(dx) > view || ABS(dy) > view)
	    continue;
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
	if (PL_TYPE(*l) == PLWHOLE)
	   W_WriteBitmap(dx - (wormhole_width / 2), dy - (wormhole_height / 2),
		      planetBitmap(l),
		      ((paradise) && (PL_TYPE(*l) == PLWHOLE))
		       ? textColor
		       : planetColor(l));
	else
	W_WriteBitmap(dx - (planet_width / 2), dy - (planet_height / 2),
		      planetBitmap(l),
			 ((paradise) && (PL_TYPE(*l) == PLSTAR))
		      ? textColor
		      : planetColor(l));
#ifdef SHOW_IND
	if (showIND && (l->pl_info & idx_to_mask(me->p_teami)) && (l->pl_owner == NOBODY) && l->pl_flags & PLPLANET)
	{
	    W_CacheLine (w, dx - (planet_width / 2), dy - (planet_height / 2),
			 dx + (planet_width / 2 - 1), dy + (planet_height / 2 - 1),
			 W_White);
	    W_CacheLine (w, dx + (planet_width / 2 - 1), dy - (planet_height / 2),
			 dx - (planet_width / 2), dy + (planet_height / 2 - 1),
			 W_White);
	}
#endif
	if (namemode) {
	   if (PL_TYPE(*l) != PLWHOLE) {
	    W_MaskText(w, dx - l->pl_namelen * W_Textwidth / 2, dy + (planet_height / 2),
			 ((paradise) && (PL_TYPE(*l) == PLSTAR))
		       ? textColor
		       : planetColor(l),
		       l->pl_name, l->pl_namelen, planetFont(l));
	    cz = new_czone();
	    cz->x = dx - l->pl_namelen * W_Textwidth / 2;
	    cz->y = dy + (planet_height / 2);
	    cz->width = W_Textwidth * l->pl_namelen;
	    cz->height = W_Textheight;
	}
	}
				/* put letters and number next to */
				/* planet bitmaps for resources and */
				/* armies */
	 if (paradise && tacPlanetInfo) {
	      if (PL_TYPE(*l) == PLPLANET) {
		   char dspstr[8];
		   if (tacPlanetInfo & 1) 
			sprintf(dspstr, "%d", l->pl_armies);
		   if ((tacPlanetInfo & 2) && (l->pl_flags & PLREPAIR)) 
			strcat(dspstr, "R");
		   if ((tacPlanetInfo & 4) && (l->pl_flags & PLFUEL)) 
			strcat(dspstr, "F");
		   if ((tacPlanetInfo & 8) && (l->pl_flags & PLAGRI)) 
			strcat(dspstr, "A");
		   if ((tacPlanetInfo & 16) && (l->pl_flags & PLSHIPYARD)) 
			strcat(dspstr, "S");
		   cz = new_czone();
		   cz->x = dx + planet_width/2 + 2;
		   cz->y = dy;
		   cz->width = W_Textwidth * strlen(dspstr);
		   cz->height = W_Textheight;
		   W_MaskText(w, cz->x, cz->y,
			      planetColor(l), dspstr, strlen(dspstr),
				   planetFont(l));
	      }
	 }

	/*--------draw tactical lock*/
	if ((showLock & 2) && (me->p_flags & PFPLLOCK) && (me->p_planet == l->pl_no)) {
	    W_WriteTriangle(w, dx, dy - (planet_height) / 2 - 6, 5, 0, foreColor);
	    cz=new_czone();
	    cz->x=dx-5;
	    cz->y=dy - (planet_height) / 2 - 12;
	    cz->width=11;
	    cz->height=7;
	}
	cz = new_czone();
	if (PL_TYPE(*l) == PLWHOLE) {
	   cz->x = dx - (wormhole_width / 2);
	   cz->y = dy - (wormhole_height / 2);
	   cz->width = wormhole_width;
	   cz->height = wormhole_height;
	} else {
	cz->x = dx - (planet_width / 2);
	/*cz->y = dy - (planet_height / 2) - 13;*/
	cz->y = dy - (planet_height / 2);
	cz->width = planet_width;
	/*cz->height = planet_height + 26;*/
	cz->height = planet_height;
	}
    }
}

void 
doShowMySpeed(dx, dy, ship_bits, j)
    int     dx, dy;
    struct ship_shape *ship_bits;
    struct player *j;
{
    struct _clearzone *cz;
    char    idbuf[5];
    int     len;
    int     color;

    sprintf(idbuf, "%c,%d", *(shipnos + j->p_no), me->p_speed);
    len = strlen(idbuf);
    /*
       color the playernum,speed based on warp/afterburn/warpprep state
       [BDyess]
    */
    switch (me->p_flags & (PFWARP | PFAFTER | PFWARPPREP)) {
    case PFWARP:
	color = W_Cyan;
	me->p_flags &= ~PFWARPPREP;
	break;
    case PFAFTER:
	color = rColor;
	break;
    case PFWARPPREP:
	color = yColor;
	break;
    default:			/* impulse */
	if (me->p_speed > 0) {
	    color = gColor;
	} else {		/* stopped */
	    color = textColor;
	}
	break;
    }
    dx += ship_bits->width / 2;
    dy -= ship_bits->height / 2;
    /* underline number,speed if warp is suspended [BDyess] */
    W_MaskText(w, dx, dy, color, idbuf, len, (me->p_flags & PFWPSUSPENDED) ?
	       W_UnderlineFont : shipFont(j));

    cz = new_czone();
    cz->x = dx;
    cz->y = dy;
    cz->width = len * W_Textwidth;
    cz->height = W_Textheight;
}

#ifdef LOCAL_SHIPSTATS
/* show just about anything next to ship on local display
   DSFAPWE - for each letter in statString, show a line for:
   Damage, Shields, Fuel, Armies, sPeed, Wtemp, Etemp 

   lower case = reverse length
 */
static void
doLocalShipstats()
{
    char *sptr;
    int num=0, len, x=localStatsX, i;
    struct _clearzone *cz;
    W_Color color;

    for(sptr=statString;*sptr;sptr++) {
	switch(toupper(*sptr)) {
	case 'W':
	    len=(statHeight*me->p_wtemp) / me->p_ship->s_maxwpntemp;
	    break;
	case 'E':
	    len=(statHeight*me->p_etemp) / me->p_ship->s_maxegntemp;
	    break;
	case 'P':
	    len=(statHeight*me->p_speed)/me->p_ship->s_maxspeed;
	    break;
	case 'D':
	    len=(statHeight*me->p_damage)/me->p_ship->s_maxdamage;
	    break;
	case 'S':
	    len=statHeight - ((statHeight*me->p_shield)/me->p_ship->s_maxshield);
	    break;
	case 'F':
	    len=statHeight - ((statHeight*me->p_fuel)/me->p_ship->s_maxfuel);
	    break;
	case 'A':
	    len= me->p_ship->s_maxarmies ?
		(statHeight*me->p_armies)/me->p_ship->s_maxarmies : 0;
	    break;
	default:
	    continue;
	}
	if(islower(*sptr))
	    len=statHeight - len;
	if(len>statHeight)
	    len=statHeight;

	if(len>2*(statHeight/3) || toupper(*sptr) == 'A')
	    color=W_Red;
	else if(len<(statHeight/3))
	    color=W_Green;
	else
	    color=W_Yellow;
	if(len>0)
	    W_CacheLine(w,x+W_Textwidth/2,localStatsY-len,x+W_Textwidth/2,localStatsY,color);
	W_MaskText(w,x,localStatsY+1,W_White,sptr,1,W_RegularFont);
	x+=W_Textwidth;
    }
    if(x>localStatsX) {
	W_CacheLine(w,localStatsX,localStatsY-statHeight,x,localStatsY-statHeight,W_White);
	W_CacheLine(w,localStatsX,localStatsY,x,localStatsY,W_White);
	cz=new_czone();
	cz->x=localStatsX;
	cz->y=localStatsY-statHeight+1;
	cz->width=x-localStatsX;
	cz->height=statHeight-2;
    }
}
#endif

static void
local()
{
    register int i;
    register struct player *j;
    register struct phaser *php;
    struct _clearzone *cz;

    int     dx, dy;
    int     view;
    char    idbuf[10];
    struct ship_shape *ship_bits;
    if (showKitchenSink) {
	cz = new_czone();
	cz->width = 76;
	cz->height = 60;
	cz->x = 500 - cz->width;
	cz->y = 0;
	W_WriteBitmap(cz->x, cz->y, kitchenSink, W_Grey);
    }
    /*
       Kludge to try to fix missing ID chars on tactical (short range)
       display.
    */
    idbuf[0] = '0';
    idbuf[1] = '\0';
    /* Draw Terrain */
    redraw_terrain();
    /* Draw Planets */
    redraw_all_planets();
    /* Draw ships */
    view = SCALE * WINSIDE / 2;
    for (i = 0, j = &players[i]; i < nplayers; i++, j++) {
	int     tx, ty;
	if (me->p_x < 0)
	    continue;

	/* more efficient than using a separate loop for this */
	redraw_photon_torps(j);
	redraw_drones(j);
	redraw_plasma_torps(j);

	if ((j->p_status != PALIVE) && (j->p_status != PEXPLODE))
	    continue;

#ifdef UNIX_SOUND
        if (myPlayer(j) && (j->p_flags & PFCLOAK) &&
           (j->p_cloakphase == 0)) play_sound (SND_CLOAK);
        if (myPlayer(j) && (!(j->p_flags & PFCLOAK)) && 
           (j->p_cloakphase == 6)) play_sound (SND_CLOAK);
#endif

	if (j->p_flags & PFCLOAK) {
	    if (j->p_cloakphase < (CLOAK_PHASES - 1)) {
		j->p_cloakphase++;
	    }
	} else {
	    if (j->p_cloakphase) {
		j->p_cloakphase--;
	    }
	}
	dx = j->p_x - me->p_x;
	dy = j->p_y - me->p_y;
	if (ABS(dx) > view || ABS(dy) > view) {
	    if(j->p_status == PEXPLODE)
		j->p_explode++;
	    continue;
	}
	dx = dx / SCALE + WINSIDE / 2;
	dy = dy / SCALE + WINSIDE / 2;
	if (j->p_status == PALIVE) {

	    ship_bits = shape_of_ship(j->p_teami, j->p_ship->s_bitmap);

	    if (j->p_flags & PFCLOAK && (j->p_cloakphase == (CLOAK_PHASES - 1))) {
		if (myPlayer(j)) {
		    W_WriteBitmap(dx - (cloak_width / 2), dy - (cloak_height / 2),
				  cloakicon, myColor);
		    cz = new_czone();
		    cz->x = dx - (ship_bits->width / 2 + 1);
		    cz->y = dy - (ship_bits->height / 2 + 1);
		    cz->width = ship_bits->width + 2;
		    cz->height = ship_bits->height + 2;
		    doShields(dx, dy, ship_bits, j);
#ifdef VARY_HULL
		    doHull(dx, dy, ship_bits, j);
#endif				/* VARY_HULL */
		    if (showMySpeed)
			doShowMySpeed(dx, dy, ship_bits, j);
		}
		continue;
	    }
	    cz = new_czone();
#ifdef BEEPLITE
	    if (emph_player_seq_n[j->p_no] > 0 &&
		((F_beeplite_flags & LITE_PLAYERS_LOCAL) ||
		 ((j == me) && (F_beeplite_flags & LITE_SELF)))) {
		int     seq_n = emph_player_seq_n[j->p_no] % emph_player_seql_frames;

		cz->x = dx - (emph_player_seql_width / 2);
		cz->y = dy - (emph_player_seql_height / 2);
		cz->width = emph_player_seql_width;
		cz->height = emph_player_seql_height;

		W_WriteBitmap(dx - (emph_player_seql_width / 2),
			      dy - (emph_player_seql_height / 2),
			      emph_player_seql[seq_n],
			      emph_player_color[j->p_no]);
	    } else
#endif
	    {
		cz->x = dx - (ship_bits->width / 2);
		cz->y = dy - (ship_bits->height / 2);
		cz->width = ship_bits->width;
		cz->height = ship_bits->height;
	    }
	    W_WriteBitmap(dx - (ship_bits->width / 2),
			  dy - (ship_bits->height / 2),
			  ship_bits->bmap[rosette((int) j->p_dir,
				 (int) ship_bits->nviews)], playerColor(j));
	    if (j->p_cloakphase > 0) {
		W_WriteBitmap(dx - (cloak_width / 2),
			dy - (cloak_height / 2), cloakicon, playerColor(j));
		doShields(dx, dy, ship_bits, j);
		if (j == me) {
#ifdef VARY_HULL
		    doHull(dx, dy, ship_bits, j);
#endif				/* VARY_HULL */
		    if (showMySpeed)
			doShowMySpeed(dx, dy, ship_bits, j);
		}
		continue;
	    }
	    if (showLock & 2) {
		if ((me->p_flags & PFPLOCK) && (me->p_playerl == j->p_no)) {
		    W_WriteTriangle(w, dx, dy + (ship_bits->width / 2),
				    4, 1, foreColor);
		    cz = new_czone();
		    cz->x = dx - 4;
		    cz->y = dy + (ship_bits->height / 2);
		    cz->width = 9;
		    cz->height = 5;
		}
	    }
	    doShields(dx, dy, ship_bits, j);
#ifdef VARY_HULL
	    doHull(dx, dy, ship_bits, j);
#endif				/* VARY_HULL */
	    if (showMySpeed && j == me)
		doShowMySpeed(dx, dy, ship_bits, j);
	    else {
		int     color = playerColor(j);
		idbuf[0] = *(shipnos + j->p_no);

		W_MaskText(w, dx + (ship_bits->width / 2),
			   dy - (ship_bits->height / 2), color,
			   idbuf, 1, shipFont(j));

		cz = new_czone();
		cz->x = dx + (ship_bits->width / 2);
		cz->y = dy - (ship_bits->height / 2);
		cz->width = W_Textwidth;
		cz->height = W_Textheight;
	    }
	} else if (j->p_status == PEXPLODE) {
	    int     i;
	    i = j->p_explode;
	    if (i < EX_FRAMES || (i < SBEXPVIEWS && j->p_ship->s_type == STARBASE)) {

#ifdef SOUND
		if(i==0)
		    S_PlaySound(S_EXPLOSION);
#endif
#ifdef UNIX_SOUND
                if (i==0)
                {
                    if (j->p_ship->s_type == STARBASE)
                    play_sound(SND_EXP_SB);         /* Starbase Explode */
                    else play_sound(SND_EXPLOSION); /* Ship Explosion */
                }
#endif 
    
		cz = new_czone();
		if (j->p_ship->s_type == STARBASE) {
		    W_WriteBitmap(dx - (sbexp_width / 2),
				  dy - (sbexp_height / 2), sbexpview[i],
				  playerColor(j));
		    cz->x = dx - (sbexp_width / 2);
		    cz->y = dy - (sbexp_height / 2);
		    cz->width = sbexp_width;
		    cz->height = sbexp_height;
		} else {
		    W_WriteBitmap(dx - (ex_width / 2), dy - (ex_height / 2),
				  expview[i], playerColor(j));
		    cz->x = dx - (ex_width / 2);
		    cz->y = dy - (ex_height / 2);
		    cz->width = ex_width;
		    cz->height = ex_height;
		}
		j->p_explode++;
	    }
	}
	/* 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 */
		tx = j->p_x + j->p_ship->s_phaserrange * Cos[php->ph_dir];
		ty = j->p_y + j->p_ship->s_phaserrange * Sin[php->ph_dir];
		tx = (tx - me->p_x) / SCALE + WINSIDE / 2;
		ty = (ty - me->p_y) / SCALE + WINSIDE / 2;
	    } else if (php->ph_status == PHHIT2) {
		tx = (php->ph_x - me->p_x) / SCALE + WINSIDE / 2;
		ty = (php->ph_y - me->p_y) / SCALE + WINSIDE / 2;
	    } else {		/* Start point is dx, dy */
		tx = (players[php->ph_target].p_x - me->p_x) /
		    SCALE + WINSIDE / 2;
		ty = (players[php->ph_target].p_y - me->p_y) /
		    SCALE + WINSIDE / 2;
	    }


	    php->ph_fuse++;

#ifdef CHECK_DROPPED
	    if (php->ph_fuse > longest_ph_fuse + 1 && php->ph_status != PHGHOST) {
		if (reportDroppedPackets)
		    printf("Dropped phaser free, player %d (fuse)\n", j->p_no);
		php->ph_status = PHGHOST;
	    }
	    if (php->ph_status != PHGHOST) {
#endif
#ifdef W_PHASERLINE
/*
 * an old redraw.c I used for the Amiga port(not this port) had this.
 * Draws a dashed line instead of solid..different pattern from tractor
 * lines.   At least that's what I guessed for amigawindow.c :-) -JR
 */

		if (j->p_teami != me->p_teami)
		    W_MakePhaserLine(w, dx, dy, tx, ty,
			    (php->ph_fuse % 2 && php->ph_status != PHMISS) ?
				     foreColor :
				     shipCol[1 + j->p_teami],
				     php->ph_fuse);
		else
#endif
		{
		    W_Color ph_col;
		    if (jubileePhasers) {

			switch (php->ph_fuse % 4) {
			case 0:
			    ph_col = W_Red;
			    break;
			case 1:
			    ph_col = W_Yellow;
			    break;
			case 2:
			    ph_col = W_Green;
			    break;
			case 3:
			    ph_col = W_Cyan;
			    break;
			}
			if (php->ph_status == PHMISS)
			    ph_col = W_White;
		    } else {
			ph_col = (php->ph_fuse % 2 && php->ph_status != PHMISS) ?
			    foreColor :
			    shipCol[1 + j->p_teami];
		    }
		    W_CacheLine(w, dx, dy, tx, ty, ph_col);
		}
		clearline[0][clearlcount] = dx;
		clearline[1][clearlcount] = dy;
		clearline[2][clearlcount] = tx;
		clearline[3][clearlcount] = ty;
		clearlcount++;
#ifdef CHECK_DROPPED
	    }			/* PHGHOST */
#endif
	}
    }

    /* ATM - show tractor/pressor beams (modified by James Collins) */
    /* showTractorPressor is a variable set by xtrekrc. */
    /* modified to show all T/P's 1/28/94 [BDyess] */
    /* fixed display bug 1/29/94 [BDyess] */
    dx = WINSIDE / 2;
    dy = WINSIDE / 2;
    if (showTractorPressor) {
	double  theta;
	unsigned char dir;
	int     lx[2], ly[2], px, py, target_width;
	struct player *victim = &players[me->p_tractor];
	int     last;
	if (paradise && showAllTractorPressor && allowShowAllTractorPressor) {
	    /* check everybody */
	    last = nplayers;
	    j = &players[0];
	    i = 0;
	} else {
	    /* only check self */
	    last = me->p_no + 1;
	    j = me;
	    i = me->p_no;
	}
	for (; i < last; i++, j++) {
	    if (!(j->p_flags & (PFTRACT | PFPRESS) && isAlive(j)))
		continue;
	    if (!paradise && RSA_Client > 0 && j != me)
		continue;
	    victim = &players[j->p_tractor];
	    if (victim->p_flags & PFCLOAK)
		break;		/* can't see tractors on cloaked opponents */
	    if (j == me) {
		dx = dy = WINSIDE / 2;
	    } else {
		dx = (j->p_x - me->p_x) / SCALE + WINSIDE / 2;
		dy = (j->p_y - me->p_y) / SCALE + WINSIDE / 2;
	    }
	    if (PtOutsideWin(dx, dy))
		continue;	/* he's off the screen */
	    px = (victim->p_x - me->p_x) / SCALE + WINSIDE / 2;
	    py = (victim->p_y - me->p_y) / SCALE + WINSIDE / 2;
	    if (px == dx && py == dy)
		break;
#define XPI     3.1415926
	    theta = atan2((double) (px - dx), (double) (dy - py)) + XPI / 2.0;
	    dir = (unsigned char) (theta / XPI * 128.0);
	    target_width = shape_of_ship(victim->p_teami,
					 victim->p_ship->s_bitmap)->width;
	    if (!(victim->p_flags & PFSHIELD))
		target_width /= 2;
	    lx[0] = px + (Cos[dir] * (target_width / 2));
	    ly[0] = py + (Sin[dir] * (target_width / 2));
	    lx[1] = px - (Cos[dir] * (target_width / 2));
	    ly[1] = py - (Sin[dir] * (target_width / 2));
#undef XPI
	    if (j->p_flags & PFPRESS) {
		W_MakeTractLine(w, dx, dy, lx[0], ly[0], W_Yellow);
		W_MakeTractLine(w, dx, dy, lx[1], ly[1], W_Yellow);
	    } else {
		W_MakeTractLine(w, dx, dy, lx[0], ly[0], W_Green);
		W_MakeTractLine(w, dx, dy, lx[1], ly[1], W_Green);
	    }
	    /*
	       keeping track of tractors seperately from other lines allows
	       clearing them diffently.  Clearing them the same as other
	       solid lines caused occasional bits to be left on the screen.
	       This is the fix.  [BDyess]
	    */
	    if (tractcurrent == NULL) {	/* just starting */
		tractcurrent = tracthead = (Tractor *) malloc(sizeof(Tractor));
		tracthead->next = NULL;
	    }
	    tractcurrent->sx = dx;
	    tractcurrent->sy = dy;
	    tractcurrent->d1x = lx[0];
	    tractcurrent->d1y = ly[0];
	    tractcurrent->d2x = lx[1];
	    tractcurrent->d2y = ly[1];
	    /* get ready for the next run through */
	    if (tractcurrent->next) {	/* already malloc'd before */
		tractcurrent = tractcurrent->next;
	    } else {		/* new maximum, create a new struct */
		tractcurrent->next = (Tractor *) malloc(sizeof(Tractor));
		tractcurrent = tractcurrent->next;
		tractcurrent->next = NULL;
	    }
	}
    }
    /* changed torps/drones/plasmas to one call per player, in the above loop */
    /* still have leftover drones to draw: */
    redraw_other_drones();

    /* Draw Edges */
    if (me->p_x < (WINSIDE / 2) * SCALE) {
	int     sy, ey;
	dx = (WINSIDE / 2) - (me->p_x) / SCALE;
	sy = (WINSIDE / 2) + (0 - me->p_y) / SCALE;
	ey = (WINSIDE / 2) + (blk_gwidth - me->p_y) / SCALE;
	if (sy < 0)
	    sy = 0;
	if (ey > WINSIDE - 1)
	    ey = WINSIDE - 1;
	/* XFIX */
	W_CacheLine(w, dx, sy, dx, ey, warningColor);
	/*
	   W_MakeLine(w, dx, sy, dx, ey, warningColor);
	*/
	clearline[0][clearlcount] = dx;
	clearline[1][clearlcount] = sy;
	clearline[2][clearlcount] = dx;
	clearline[3][clearlcount] = ey;
	clearlcount++;
    }
    if ((blk_gwidth - me->p_x) < (WINSIDE / 2) * SCALE) {
	int     sy, ey;
	dx = (WINSIDE / 2) + (blk_gwidth - me->p_x) / SCALE;
	sy = (WINSIDE / 2) + (0 - me->p_y) / SCALE;
	ey = (WINSIDE / 2) + (blk_gwidth - me->p_y) / SCALE;
	if (sy < 0)
	    sy = 0;
	if (ey > WINSIDE - 1)
	    ey = WINSIDE - 1;
	/* XFIX */
	W_CacheLine(w, dx, sy, dx, ey, warningColor);
	/*
	   W_MakeLine(w, dx, sy, dx, ey, warningColor);
	*/
	clearline[0][clearlcount] = dx;
	clearline[1][clearlcount] = sy;
	clearline[2][clearlcount] = dx;
	clearline[3][clearlcount] = ey;
	clearlcount++;
    }
    if (me->p_y < (WINSIDE / 2) * SCALE) {
	int     sx, ex;
	dy = (WINSIDE / 2) - (me->p_y) / SCALE;
	sx = (WINSIDE / 2) + (0 - me->p_x) / SCALE;
	ex = (WINSIDE / 2) + (blk_gwidth - me->p_x) / SCALE;
	if (sx < 0)
	    sx = 0;
	if (ex > WINSIDE - 1)
	    ex = WINSIDE - 1;
	/* XFIX */
	W_CacheLine(w, sx, dy, ex, dy, warningColor);
	/*
	   W_MakeLine(w, sx, dy, ex, dy, warningColor);
	*/
	clearline[0][clearlcount] = sx;
	clearline[1][clearlcount] = dy;
	clearline[2][clearlcount] = ex;
	clearline[3][clearlcount] = dy;
	clearlcount++;
    }
    if ((blk_gwidth - me->p_y) < (WINSIDE / 2) * SCALE) {
	int     sx, ex;
	dy = (WINSIDE / 2) + (blk_gwidth - me->p_y) / SCALE;
	sx = (WINSIDE / 2) + (0 - me->p_x) / SCALE;
	ex = (WINSIDE / 2) + (blk_gwidth - me->p_x) / SCALE;
	if (sx < 0)
	    sx = 0;
	if (ex > WINSIDE - 1)
	    ex = WINSIDE - 1;
	/* XFIX */
	W_CacheLine(w, sx, dy, ex, dy, warningColor);
	/*
	   W_MakeLine(w, sx, dy, ex, dy, warningColor);
	*/
	clearline[0][clearlcount] = sx;
	clearline[1][clearlcount] = dy;
	clearline[2][clearlcount] = ex;
	clearline[3][clearlcount] = dy;
	clearlcount++;
    }
    /* Change border color to signify alert status */

#ifdef UNIX_SOUND
    if (oldalert != (me->p_flags & (PFGREEN | PFYELLOW | PFRED))) 
    {
      if (me->p_flags & PFRED)
            maybe_play_sound (SND_REDALERT);   /* Red Alert, play ONLY once */
      else  sound_completed  (SND_REDALERT);   /* Done with Red Alert */
    }
#endif

    if (oldalert != (me->p_flags & (PFGREEN | PFYELLOW | PFRED))) {
	if(paradise && auto_zoom_timer<udcounter && (autoZoom || autoUnZoom)) {
	    int old_zoom=blk_zoom;
	    switch(autoZoom) {
	    case 1:
		if(me->p_flags & (PFYELLOW | PFRED))
		    blk_zoom = 1;
		break;
	    case 2:
		if(me->p_flags & (PFRED))
		    blk_zoom = 1;
		break;
	    }
	    switch(autoUnZoom) {
	    case 1:
		if(me->p_flags & (PFGREEN))
		    blk_zoom = 0;
		break;
	    case 2:
		if(me->p_flags & (PFYELLOW | PFGREEN))
		    blk_zoom = 0;
		break;
	    }
	    if(old_zoom != blk_zoom)
		redrawall=1;
	}
	oldalert = (me->p_flags & (PFGREEN | PFYELLOW | PFRED));
	if (infoIcon && iconified)
	    drawIcon();
	switch (oldalert) {
	case PFGREEN:
	    if (extraBorder)
		W_ChangeBorder(w, gColor);
	    W_ChangeBorder(baseWin, gColor);
	    W_ChangeBorder(iconWin, gColor);
	    break;
	case PFYELLOW:
	    if (extraBorder)
		W_ChangeBorder(w, yColor);
	    W_ChangeBorder(baseWin, yColor);
	    W_ChangeBorder(iconWin, yColor);
	    break;
	case PFRED:
	    if (extraBorder)
		W_ChangeBorder(w, rColor);
	    W_ChangeBorder(baseWin, rColor);
	    W_ChangeBorder(iconWin, rColor);
	    break;
	}
    }
    /* draw stars */

    if (blk_showStars)
	drawStars();

#ifdef LOCAL_SHIPSTATS
    if(localShipStats)
	doLocalShipstats();
#endif


}
#define DRAWGRID		4

int
zoom_offset(v)
    int     v;
{
    if (blk_zoom) {
	register gwidth, ov;
	/* dimension of zoom area */
	gwidth = blk_gwidth / 2;
	/* offset to bring us into new zoom area */
	ov = (v / (int) gwidth) * gwidth;
	if (blk_zoom > 1)
	    return ov;
	else
	    /* sector offset into new zoom area */
	    return ov + (((v - ov) / GRIDSIZE) * GRIDSIZE) - GRIDSIZE;
    } else
	return v;
}

#ifdef HOCKEY
void galactic_hockey P((void));
#endif

#ifndef COW_HAS_IT_WHY_SHOULDNT_WE
static 
#endif
void
map()
{
    int     nplan;
    register int i, k, tmp = blk_gwidth/250;
    register struct player *j;
    register struct planet *l;
    register int dx, dy, odx, ody;
    static  osx = 0, osy = 0;	/* old square */
    static  last_offsetx, last_offsety;
    static int grid_fuse;	/* TSH */
    register int gwidth, offsetx, offsety;
    int     color, pl = 0;
    /*
       last_lock is used to hold the begin/end point for lock line; [0] holds
       me->; [1] holds target lock; lockx[2] holds status of line so we can
       erase if line is there but lock if off
    */
    static  last_lockx[3] = {0, 0, 0}, last_locky[2];
    int     me_galx, me_galy;

    grid_fuse++;		/* we only draw the grids every DRAWGRID
				   interval */

    /* set number of planets for later */
    nplan = (paradise) ? nplanets : 40;

    if (reinitPlanets) {
	initPlanets();
	reinitPlanets = 0;
#ifdef HOCKEY
	/* planets moved so the lines need updating [BDyess] */
	if(hockey) hockeyInit();
#endif /*HOCKEY*/
    }

#ifdef HOCKEY
    galactic_hockey();
#endif /*HOCKEY*/

    if (blk_zoom) {
	gwidth = blk_gwidth / 2;
	offsetx = zoom_offset(me->p_x);
	offsety = zoom_offset(me->p_y);

	if (offsetx != last_offsetx || offsety != last_offsety)
	    redrawall = 1;

	last_offsetx = offsetx;
	last_offsety = offsety;
    } else {
	gwidth = blk_gwidth;
	offsetx = 0;
	offsety = 0;
    }

    me_galx = (me->p_x - offsetx) * WINSIDE / gwidth;
    me_galy = (me->p_y - offsety) * WINSIDE / gwidth;

/* draw asteroid dots -- this is a test only.  MDM */
    if( received_terrain_info && paradise ){
      /* but avoid that SEGV! */
      for( i = 0; i < 250; i++ ){
        for( k = udcounter%10; k < 250; k += 10){
          if(terrainInfo[i*250+k].types & T_ASTEROIDS) {
            W_DrawPoint( mapw, 
	                (i*tmp - offsetx) * WINSIDE / gwidth,
	                (k*tmp - offsety) * WINSIDE / gwidth, 
			W_White);
	  }
	  if (terrainInfo[i*250+k].types & T_NEBULA) {
	     W_DrawPoint( mapw, 
			 ((i*tmp - offsetx) * WINSIDE / gwidth) + 1,
			 ((k*tmp - offsety) * WINSIDE / gwidth) + 1, 
			 W_Red);
	  }
        }
      }
    }

    if (redrawall)
	W_ClearWindow(mapw);

    /* draw grid on galactic */
    if ((redrawall || (grid_fuse % DRAWGRID) == 0) && (paradise) && (drawgrid)) {
	int     x, y, w, h, grid;
	char    numbuf[1];
	grid = GRIDSIZE * WINSIDE / gwidth;
	for (i = 1; i <= 6 / (blk_zoom ? 2 : 1); i++) {
	    /* looks nasty but we only have to do it 3 times if blk_zoom */

	    /* horizontal line */
	    x = 0;
	    y = i * grid;
	    w = WINSIDE;
	    numbuf[0] = '0' + (char) i;
	    if (blk_zoom) {
		/* we might have to clip */
		dy = i * GRIDSIZE + offsety;
		if (dy >= 0 && dy <= blk_gwidth + 2 * GRIDSIZE) {
		    if (offsetx < 0) {
			x = grid;
			w = 2 * x;
		    } else if (offsetx + 3 * GRIDSIZE > blk_gwidth) {
			w = 2 * grid;
		    }
		    W_MakeTractLine(mapw, x, y, x + w, y, W_Grey);
		}
		if (sectorNums) {
		    numbuf[0] = '0' + (char) (i + offsety / 33333);
		    if ((numbuf[0] == '0') || (numbuf[0] == '7'))
			numbuf[0] = ' ';
		    if (i == 1)	/* so numbers dont overwrite in 1st box */
			W_WriteText(mapw, x + 2, y - grid + 11, W_Grey, numbuf, 1,
				    W_RegularFont);
		    else
			W_WriteText(mapw, x + 2, y - grid + 2, W_Grey, numbuf, 1,
				    W_RegularFont);
		}
	    } else {
		W_MakeTractLine(mapw, x, y, x + w, y, W_Grey);
		if (sectorNums) {
		    W_WriteText(mapw, x + 2, y - grid + 2, W_Grey, numbuf, 1, W_RegularFont);
		}
	    }
	    /* vertical line */
	    x = i * grid;
	    y = 0;
	    h = WINSIDE;

	    if (blk_zoom) {
		/* we might have to clip */
		dx = i * GRIDSIZE + offsetx;
		if (dx >= 0 && dx <= blk_gwidth + 2 * GRIDSIZE) {
		    if (offsety < 0) {
			y = grid;
			h = 2 * y;
		    } else if (offsety + 3 * GRIDSIZE > blk_gwidth) {
			h = 2 * grid;
		    }
		    W_MakeTractLine(mapw, x, y, x, y + h, W_Grey);
		}
		if (sectorNums) {
		    numbuf[0] = '0' + (char) (i + offsetx / 33333);
		    if ((numbuf[0] == '0') || (numbuf[0] == '7'))
			numbuf[0] = ' ';
		    if (i == 1)
			W_WriteText(mapw, x - grid + 11, y + 2, W_Grey, numbuf, 1,
				    W_RegularFont);
		    else
			W_WriteText(mapw, x - grid + 2, y + 2, W_Grey, numbuf, 1,
				    W_RegularFont);
		}
	    } else {
		W_MakeTractLine(mapw, x, y, x, y + h, W_Grey);
		if (sectorNums) {
		    W_WriteText(mapw, x - grid + 2, y + 2, W_Grey, numbuf, 1,
				W_RegularFont);
		}
	    }
	}

	dx = ((me->p_x - offsetx) / GRIDSIZE) * GRIDSIZE;
	dy = ((me->p_y - offsety) / GRIDSIZE) * GRIDSIZE;
	if (!redrawall && ((osx != dx) || (osy != dy))) {

	    /* clear old sector */
	    x = osx * WINSIDE / gwidth;
	    y = osy * WINSIDE / gwidth;
	    w = h = grid;

	    W_DrawSectorHighlight(mapw, x, y, w, h, backColor);

	    osx = dx;
	    osy = dy;
	}
	/* draw our current sector */
	x = dx * WINSIDE / gwidth;
	w = h = grid;
	y = dy * WINSIDE / gwidth;

	W_DrawSectorHighlight(mapw, x, y, w, h, yColor);
    }
    /* Erase ships */
    for (i = 0, j = &players[i]; i < nplayers; i++, j++) {
	lastUpdate[i]++;
	/*
	   Erase the guy if: redrawPlayer[i] is set and the mapmode setting
	   allows it.
	*/
	if (!redrawPlayer[i] || (mapmode == GMAP_INFREQUENT && lastUpdate[i] < 5))
	    continue;
	lastUpdate[i] = 0;
	/* Clear his old image... */
	if (mclearzone[2][i]) {
	    /* XFIX */
	    if (!redrawall) {
		W_ClearArea(mapw, mclearzone[0][i], mclearzone[1][i],
			    mclearzone[2][i], mclearzone[3][i]);
		/* Redraw the hole just left next update */
		checkRedraw(mclearzone[4][i], mclearzone[5][i]);
	    }
	    mclearzone[2][i] = 0;
	}
    }
    /* Draw Planets */
#ifdef HOCKEY
    if(! (hockey && cleanHockeyGalactic)) {
#endif
      for (i = 0, l = &planets[i]; i < nplan; i++, l++) {
	  char    buf[4];
	  int     color;
	  if (!(l->pl_flags & PLREDRAW) && (!redrawall))
	      continue;
	  l->pl_flags &= ~PLREDRAW;	/* Turn redraw flag off! */

	  dx = (l->pl_x - offsetx) * WINSIDE / gwidth;
	  dy = (l->pl_y - offsety) * WINSIDE / gwidth;

	  if (PtOutsideWin(dx, dy))
	      continue;

	  if (0 == strncmp(l->pl_name, "New ", 4)) {
	      strncpy(buf, l->pl_name + 4, 3);
	  } else if (0 == strncmp(l->pl_name, "Planet ", 7)) {
	      strncpy(buf, l->pl_name + 7, 3);
	  } else
	      strncpy(buf, l->pl_name, 3);

	  /* moving planets */
	  if (pl_update[l->pl_no].plu_update == 1) {
	      odx = (pl_update[l->pl_no].plu_x - offsetx) * WINSIDE / gwidth;
	      ody = (pl_update[l->pl_no].plu_y - offsety) * WINSIDE / gwidth;

	      /* XFIX */
	      W_ClearArea(mapw, odx - (mplanet_width / 2), ody - (mplanet_height / 2),
			  mplanet_width, mplanet_height);

	      W_WriteText(mapw, odx - (mplanet_width / 2), ody + (mplanet_height / 2),
			  backColor, buf, 3, planetFont(l));

	      pl_update[l->pl_no].plu_update = 0;
	  }
#if 0
/* not necessary, pl_update is now set whenever a planet needs to be
 * erased. -JR
 */
	  else {

	      /* XFIX */
	      W_ClearArea(mapw, dx - (mplanet_width / 2), dy - (mplanet_height / 2),
			  mplanet_width, mplanet_height);
	  }
#endif
	  color = ((paradise) && (l->pl_flags & (PLSTAR | PLWHOLE))) ?
	      textColor : planetColor(l);
#ifdef BEEPLITE
	  if (UseLite && emph_planet_seq_n[l->pl_no] > 0 &&
	      (F_beeplite_flags & LITE_PLANETS)) {
	      int     seq_n = emph_planet_seq_n[l->pl_no] % emph_planet_seq_frames;

	      if ((emph_planet_seq_n[l->pl_no] -= 1) > 0)
		  W_OverlayBitmap(dx - (emph_planet_seq_width / 2),
				  dy - (emph_planet_seq_height / 2),
				  emph_planet_seq[seq_n],
				  emph_planet_color[l->pl_no]);
	      else
		  W_ClearArea(mapw, dx - (emph_planet_seq_width / 2),
			      dy - (emph_planet_seq_height / 2),
			      emph_planet_seq_width, emph_planet_seq_height);
	      W_WriteBitmap(dx - (mplanet_width / 2), dy - (mplanet_height / 2),
			    planetmBitmap(l), color);
	      l->pl_flags |= PLREDRAW;	/* Leave redraw on until done
					     highlighting */
	      pl_update[l->pl_no].plu_update = 1;
	  } else
#endif
          if (!(PL_TYPE(*l) == PLWHOLE)) { /* non wormholes */
	  W_WriteBitmap(dx - (mplanet_width / 2), dy - (mplanet_height / 2),
			    planetmBitmap(l), color);
	  W_WriteText(mapw, dx - (mplanet_width / 2), dy + (mplanet_height / 2),
		      color, buf, ((strlen(buf) >= 3) ? 3 : strlen(buf)),
		      planetFont(l));
#ifdef SHOW_IND
	  if (showIND && (l->pl_info & idx_to_mask(me->p_teami)) && (l->pl_owner == NOBODY) && l->pl_flags & PLPLANET)
	  {
	      W_MakeLine (mapw, dx + (mplanet_width / 2 - 1), dy + (mplanet_height / 2 - 1),
			  dx - (mplanet_width / 2), dy - (mplanet_height / 2),
			  W_White);
	      W_MakeLine (mapw, dx - (mplanet_width / 2), dy + (mplanet_height / 2 - 1),
			  dx + (mplanet_width / 2 - 1), dy - (mplanet_height / 2),
			  W_White);
	  }
#endif
	  } 
#ifdef VISIBLE_WORMHOLES
	  else { /* wormholes show when scouted [BDyess] */
	    if(l->pl_info & idx_to_mask(me->p_teami)) { /* have info [BDyess]*/
	      printf("l->pl_info == %d\n",l->pl_info);
	      W_WriteBitmap(dx - (mplanet_width / 2), 
	                    dy - (mplanet_height / 2),
			    planetmBitmap(l), 
			    color);
	    }
	  }
#endif /*VISIBLE_WORMHOLES*/
#ifdef HOCKEY
    }
#endif
    /* Draw ships */
    for (i = 0, j = &players[i]; i < nplayers; i++, j++) {
	/*
	   We draw the guy if redrawall, or we just erased him. Also, we
	   redraw if we haven't drawn for 30 frames. (in case he was erased
	   by other ships).
	*/
	if (lastUpdate[i] != 0 && (!redrawall) && lastUpdate[i] < 30)
	    continue;
	if (j->p_status != PALIVE)
	    continue;
	lastUpdate[i] = 0;
	dx = (j->p_x - offsetx) * WINSIDE / gwidth;
	dy = (j->p_y - offsety) * WINSIDE / gwidth;

	if ((showLock & 1) && !(j->p_flags & PFCLOAK)) {
	    if ((me->p_flags & PFPLOCK) && (me->p_playerl == j->p_no)) {
		if (lockLine) {
		    if ((last_lockx[0] != me_galx) || (last_locky[0] != me_galx) ||
			(last_lockx[1] != dx) || (last_locky[1] != dy)) {
			W_MakeTractLine(mapw, last_lockx[0], last_locky[0],
				   last_lockx[1], last_locky[1], backColor);
			last_lockx[0] = me_galx;
			last_locky[0] = me_galy;
			last_lockx[1] = dx;
			last_locky[1] = dy;
			last_lockx[2] = 1;
			W_MakeTractLine(mapw, last_lockx[0], last_locky[0],
				     last_lockx[1], last_locky[1], W_Green);

		    }
		}
		W_WriteTriangle(mapw, dx, dy + 6, 4, 1, foreColor);
		pl = 1;
	    }
	}
	if (PtOutsideWin(dx, dy))
	    continue;

	if (blk_friendlycloak == 1) {
	    if (j->p_flags & PFCLOAK) {
		if (myPlayer(j))
		    color = myColor;
		else if (friendlyPlayer(j))
		    color = playerColor(j);
		else
		    color = unColor;
	    } else
		color = playerColor(j);

	    pl = 0;
	    if (j->p_flags & PFCLOAK)
		W_WriteText(mapw, dx - W_Textwidth * cloakcharslen / 2,
		    dy - W_Textheight / 2, color, cloakchars, cloakcharslen,
			    W_RegularFont);
	    else
		W_WriteText(mapw, dx - W_Textwidth,
			    dy - W_Textheight / 2, color, j->p_mapchars, 2,
			    shipFont(j));
	} else {
	    if (j->p_flags & PFCLOAK) {
		W_WriteText(mapw, dx - W_Textwidth * cloakcharslen / 2,
		  dy - W_Textheight / 2, unColor, cloakchars, cloakcharslen,
			    W_RegularFont);
	    } else {
		W_WriteText(mapw, dx - W_Textwidth,
		    dy - W_Textheight / 2, playerColor(j), j->p_mapchars, 2,
			    shipFont(j));
	    }
	}

#ifdef BEEPLITE
	if (UseLite && emph_player_seq_n[i] > 0 &&
	    (F_beeplite_flags & LITE_PLAYERS_MAP)) {
	    int     seq_n = emph_player_seq_n[i] % emph_player_seq_frames;

	    W_WriteBitmap(dx - (emph_player_seq_width / 2 - 1),
			  dy - (emph_player_seq_height / 2 + 1),
			  emph_player_seq[seq_n],
			  emph_player_color[i]);
	    emph_player_seq_n[i] -= 1;
	    mclearzone[0][i] = dx - (emph_player_seq_width / 2 - 1);
	    mclearzone[1][i] = dy - (emph_player_seq_height / 2 + 1);
	    mclearzone[2][i] = emph_player_seq_width;
	    mclearzone[3][i] = emph_player_seq_height;
	    mclearzone[4][i] = j->p_x;
	    mclearzone[5][i] = j->p_y;
	    /*
	       Force redraw for this guy no matter what. Even if stationary.
	    */
	    lastUpdate[i] = 30;
	    /* Leave redraw on until done highlighting */
	    redrawPlayer[i] = 1;
	} else
#endif
	{
	    if (j->p_flags & PFCLOAK) {
		mclearzone[0][i] = dx - W_Textwidth * cloakcharslen / 2;
		mclearzone[1][i] = dy - W_Textheight / 2;
		mclearzone[2][i] = W_Textwidth * cloakcharslen;
	    } else {
		mclearzone[0][i] = dx - W_Textwidth;
		mclearzone[1][i] = dy - W_Textheight / 2;
		mclearzone[2][i] = W_Textwidth * 2;
	    }
	    if (pl)
		mclearzone[3][i] = W_Textheight + 8;
	    else
		mclearzone[3][i] = W_Textheight;
	    /* Set these so we can checkRedraw() next time */
	    mclearzone[4][i] = j->p_x;
	    mclearzone[5][i] = j->p_y;
	    redrawPlayer[i] = 0;
	}
    }
    /* draw viewBox if wanted [BDyess] */
#define VIEWDIST SCALE * WINSIDE * WINSIDE / (gwidth * 2)
#define REDRAWDIST SCALE * WINSIDE / 2
    if (viewBox && allowViewBox) {
	static int viewx = 0, viewy = 0;

	dx = (me->p_x - offsetx) * WINSIDE / gwidth;
	dy = (me->p_y - offsety) * WINSIDE / gwidth;
	if (viewx != dx || viewy != dy || redrawall) {
	    /* clear old dots - placed here for less flicker */
	    W_DrawPoint(mapw, viewx + VIEWDIST, viewy + VIEWDIST, backColor);
	    W_DrawPoint(mapw, viewx + VIEWDIST, viewy - VIEWDIST, backColor);
	    W_DrawPoint(mapw, viewx - VIEWDIST, viewy + VIEWDIST, backColor);
	    W_DrawPoint(mapw, viewx - VIEWDIST, viewy - VIEWDIST, backColor);
	    /* redraw any planets they overwrote */
	    viewx *= gwidth / WINSIDE + offsetx;	/* correct from view
							   scale */
	    viewy *= gwidth / WINSIDE + offsety;
	    checkRedraw(viewx + REDRAWDIST, viewy + REDRAWDIST);
	    checkRedraw(viewx + REDRAWDIST, viewy - REDRAWDIST);
	    checkRedraw(viewx - REDRAWDIST, viewy + REDRAWDIST);
	    checkRedraw(viewx - REDRAWDIST, viewy - REDRAWDIST);
	    /* draw the new points */
	    W_DrawPoint(mapw, dx + VIEWDIST, dy + VIEWDIST, W_White);
	    W_DrawPoint(mapw, dx + VIEWDIST, dy - VIEWDIST, W_White);
	    W_DrawPoint(mapw, dx - VIEWDIST, dy + VIEWDIST, W_White);
	    W_DrawPoint(mapw, dx - VIEWDIST, dy - VIEWDIST, W_White);
	    viewx = dx;		/* store the points for later */
	    viewy = dy;		/* clearing */
	}
    }
#undef VIEWDIST
#undef REDRAWDIST

    if (clearlmcount) {
	W_WriteTriangle(mapw, clearlmark[0], clearlmark[1], 4, 0, backColor);
	clearlmcount--;
    }
    if (showLock & 1) {
	/* for now draw this everytime */
	if ((me->p_flags & PFPLLOCK) && (me->p_status != POBSERVE)) {
	    struct planet *l = &planets[me->p_planet];
	    dx = (l->pl_x - offsetx) * WINSIDE / gwidth;
	    dy = (l->pl_y - offsety) * WINSIDE / gwidth;

	    if (lockLine) {
		if ((last_lockx[0] != me_galx) || (last_locky[0] != me_galx) ||
		    (last_lockx[1] != dx) || (last_locky[1] != dy)) {
		    W_MakeTractLine(mapw, last_lockx[0], last_locky[0],
				    last_lockx[1], last_locky[1], backColor);
		    last_lockx[0] = me_galx;
		    last_locky[0] = me_galy;
		    last_lockx[1] = dx;
		    last_locky[1] = dy;
		    last_lockx[2] = 1;
		    W_MakeTractLine(mapw, last_lockx[0], last_locky[0],
				    last_lockx[1], last_locky[1], W_Green);
		}
	    }
	    if (!PtOutsideWin(dx, dy)) {
		W_WriteTriangle(mapw, dx, dy - (mplanet_height) / 2 - 4, 4, 0,
				foreColor);
		clearlmark[0] = dx;
		clearlmark[1] = dy - (mplanet_height) / 2 - 4;
		clearlmcount++;
	    }
	}
    }
    /* if lock line is drawn but no lock; erase lock line */
    if (lockLine && ((me->p_flags & (PFPLLOCK | PFPLOCK)) == 0) && last_lockx[2]) {
	W_MakeTractLine(mapw, last_lockx[0], last_locky[0], last_lockx[1],
			last_locky[1], backColor);
	last_lockx[2] = 0;
    }
    /* redraw warp beacon routes */

    for (i = 0; i < ngthingies; i += 2) {
	struct thingy *k = &thingies[i + nplayers * npthingies];
	if (k[0].t_shape == SHP_WARP_BEACON &&
	    k[1].t_shape == SHP_WARP_BEACON) {
	    W_MakeLine(mapw, (k[0].t_x - offsetx) * WINSIDE / gwidth,
		       (k[0].t_y - offsety) * WINSIDE / gwidth,
		       (k[1].t_x - offsetx) * WINSIDE / gwidth,
		       (k[1].t_y - offsety) * WINSIDE / gwidth,
		       W_Grey);
	}
    }
  }
  redrawall = 0;
}

#define TWODIGIT_L(p, val) \
{ \
    if ((val)<10) { \
		      (p)[0] = (val)+'0'; \
		      (p)[1] = ' '; \
    } else { \
	       (p)[0] = (val)/10 + '0'; \
	       (p)[1] = (val)%10 + '0'; \
	   } \
}

#define TWODIGIT_R(p, val) \
{ \
    if ((val)<10) { \
		      (p)[0] = ' '; \
		      (p)[1] = (val)+'0'; \
    } else { \
	       (p)[0] = (val)/10 + '0'; \
	       (p)[1] = (val)%10 + '0'; \
	   } \
}

#define THREEDIGIT_C(p, val) \
{ \
    if ((val)<10) { \
		    (p)[0] = ' '; (p)[1] = (val)+'0'; (p)[2] = ' '; \
    } else if ((val)<100) { \
			    (p)[0] = (val)/10 + '0'; \
			    (p)[1] = (val)%10 + '0'; \
			    (p)[2] = ' ';  \
    } else { \
	       (p)[0] = (val)/100 + '0'; \
	       (p)[1] = ((val)/10 %10) + '0'; \
	       (p)[2] = (val)%10 + '0'; \
	   } \
}

#define THREEDIGIT_R(p, val) \
{ \
    if ((val)<10) { \
		    (p)[0] = ' '; (p)[1] = ' '; (p)[2] = (val)+'0'; \
    } else if ((val)<100) { \
			    (p)[0] = ' ';  \
			    (p)[1] = (val)/10 + '0'; \
			    (p)[2] = (val)%10 + '0'; \
    } else { \
	       (p)[0] = (val)/100 + '0'; \
	       (p)[1] = ((val)/10 %10) + '0'; \
	       (p)[2] = (val)%10 + '0'; \
	   } \
}

#define FOURDIGIT_R(p, val) \
{ \
    if ((val)<10) { \
		      (p)[0] = ' '; \
		      (p)[1] = ' '; \
		      (p)[2] = ' '; \
		      (p)[3] = (val)+'0'; \
    } else if ((val)<100) { \
			      (p)[0] = ' ';  \
			      (p)[1] = ' ';  \
			      (p)[2] = (val)/10 + '0'; \
			      (p)[3] = (val)%10 + '0'; \
    } else if ((val)<1000) { \
			       (p)[0] = ' ';  \
			       (p)[1] = (val)/100 + '0'; \
			       (p)[2] = ((val)/10 %10) + '0'; \
			       (p)[3] = (val)%10 + '0'; \
    } else { \
	       (p)[0] = (val)/1000 + '0'; \
	       (p)[1] = ((val)/100 %10) + '0'; \
	       (p)[2] = ((val)/10 %10) + '0'; \
	       (p)[3] = (val)%10 + '0'; \
	   } \
}

#define SIXDIGIT_R(p, val) \
{ \
    if ((val)<10) { \
		      (p)[0] = ' '; \
		      (p)[1] = ' '; \
		      (p)[2] = ' '; \
		      (p)[3] = ' '; \
		      (p)[4] = ' '; \
		      (p)[5] = (val)+'0'; \
    } else if ((val)<100) { \
			      (p)[0] = ' ';  \
			      (p)[1] = ' ';  \
			      (p)[2] = ' ';  \
			      (p)[3] = ' ';  \
			      (p)[4] = (val)/10 + '0'; \
			      (p)[5] = (val)%10 + '0'; \
    } else if ((val)<1000) { \
			       (p)[0] = ' ';  \
			       (p)[1] = ' ';  \
			       (p)[2] = ' ';  \
			       (p)[3] = (val)/100 + '0'; \
			       (p)[4] = ((val)/10 %10) + '0'; \
			       (p)[5] = (val)%10 + '0'; \
    } else if ((val)<10000) { \
				(p)[0] = ' ';  \
				(p)[1] = ' ';  \
				(p)[2] = ((val)/1000 %10) + '0';  \
				(p)[3] = ((val)/100 %10) + '0'; \
				(p)[4] = ((val)/10 %10) + '0'; \
				(p)[5] = (val)%10 + '0'; \
    } else if ((val)<100000) { \
				 (p)[0] = ' ';  \
				 (p)[1] = ((val)/10000 %10) + '0';  \
				 (p)[2] = ((val)/1000 %10) + '0';  \
				 (p)[3] = ((val)/100 %10) + '0'; \
				 (p)[4] = ((val)/10 %10) + '0'; \
				 (p)[5] = (val)%10 + '0'; \
    } else { \
	       (p)[0] = (val)/100000 + '0';  \
	       (p)[1] = ((val)/10000 %10) + '0';  \
	       (p)[2] = ((val)/1000 %10) + '0'; \
	       (p)[3] = ((val)/100 %10) + '0'; \
	       (p)[4] = ((val)/10 %10) + '0'; \
	       (p)[5] = (val)%10 + '0'; \
	   } \
}

#define SIXnTWOf_R(p, val) \
{ \
    (p)[3] = '.'; \
    (p)[4] = ((int) (10*(val))) %10 + '0'; \
    (p)[5] = ((int) (100*(val))) %10 + '0'; \
    if ((val)<10) { \
		      (p)[0] = ' '; \
		      (p)[1] = ' '; \
		      (p)[2] = ((int)(val))+'0'; \
    } else if ((val)<100) { \
			      (p)[0] = ' ';  \
			      (p)[1] = ((int)(val))/10 + '0'; \
			      (p)[2] = ((int)(val))%10 + '0'; \
    } else { \
	       (p)[0] = ((int)(val))/100 + '0'; \
	       (p)[1] = (((int)(val))/10 %10) + '0'; \
	       (p)[2] = ((int)(val))%10 + '0'; \
	   } \
}

#if 0

static void
stline(flag)
    int     flag;
{
    static char buf1[80];
    static char buf2[80];
    static char whichbuf = 0;
    static int lastnewDashboard;
    register char *buf, *oldbuf;
    register char *s;
    register int i, j;
    int     k;
/* if you don't do something like this, then switching in the options menu
   is 'entertaining'  */
    if (newDashboard != lastnewDashboard) {
	lastnewDashboard = newDashboard;
	redrawTstats();
	return;
    }
/* use the new dashboard if we can */






    if (newDashboard) {
	db_redraw(flag);
	return;
    }
    /* Instead of one sprintf, we do all this by hand for optimization */

    if (flag)
	whichbuf = 0;		/* We must completely refresh */

    if (whichbuf != 2) {
	buf = buf1;
	oldbuf = buf2;
    } else {
	buf = buf2;
	oldbuf = buf1;
    }
    buf[0] = (me->p_flags & PFSHIELD ? 'S' : ' ');
    if (me->p_flags & PFGREEN)
	buf[1] = 'G';
    else if (me->p_flags & PFYELLOW)
	buf[1] = 'Y';
    else if (me->p_flags & PFRED)
	buf[1] = 'R';
    buf[2] = (me->p_flags & (PFPLLOCK | PFPLOCK) ? 'L' : ' ');
    buf[3] = (me->p_flags & PFREPAIR ? 'R' : ' ');
    buf[4] = (me->p_flags & PFBOMB ? 'B' : ' ');
    buf[5] = (me->p_flags & PFORBIT ? 'O' : ' ');
    buf[6] = (me->p_flags & PFDOCKOK ? 'D' : ' ');
/*      buf[6] = (me->p_flags & PFDOCK ? 'D' : ' ');*/
    buf[7] = (me->p_flags & PFCLOAK ? 'C' : ' ');
    buf[8] = (me->p_flags & PFWEP ? 'W' : ' ');
    buf[9] = (me->p_flags & PFENG ? 'E' : ' ');
    if (me->p_flags & PFPRESS)
	buf[10] = 'P';
    else if (me->p_flags & PFTRACT)
	buf[10] = 'T';
    else
	buf[10] = ' ';
    if (me->p_flags & PFBEAMUP)
	buf[11] = 'u';
    else if (me->p_flags & PFBEAMDOWN)
	buf[11] = 'd';
    else
	buf[11] = ' ';
    if (!paradise)
	buf[12] = (status->tourn) ? 't' : ' ';
    else
	buf[12] = (status2->tourn) ? 't' : ' ';

    buf[13] = ' ';

#if 1
/* w/i indicator is a kludge - it just guesses based on the speed of
   the ship */
    sprintf(buf + 14, "%2d%c   %3d %3d  %1d  %6.2f %3d %6d  %4d %4d  ",
	me->p_speed, (me->p_speed > me->p_ship->s_maxspeed + 2) ? 'w' : 'i',
	    me->p_damage, me->p_shield, me->p_ntorp, me->p_kills,
	    me->p_armies, me->p_fuel, me->p_wtemp, me->p_etemp);
#else
#if 0
    TWODIGIT_L(&buf[14], me->p_speed);
    buf[16] = 'i';
    buf[17] = ' ';
    buf[18] = ' ';
    buf[19] = ' ';
    THREEDIGIT_R(&buf[20], me->p_damage);
    buf[23] = ' ';
    THREEDIGIT_R(&buf[24], me->p_shield);
    buf[27] = ' ';
    TWODIGIT_R(&buf[28], me->p_ntorp);
    buf[30] = ' ';
    buf[31] = ' ';
    SIXnTWOf_R(&buf[32], me->p_kills);
    buf[38] = ' ';
    THREEDIGIT_C(&buf[39], me->p_armies);
    buf[42] = ' ';
    SIXDIGIT_R(&buf[43], me->p_fuel);
    buf[49] = ' ';
    buf[50] = ' ';
    FOURDIGIT_R(&buf[51], me->p_wtemp / 10);
    buf[55] = ' ';
    FOURDIGIT_R(&buf[56], me->p_etemp / 10);
    buf[60] = ' ';
    buf[61] = ' ';
#else
    buf[14] = '0' + ((me->p_speed % 100) / 10);
    if (buf[14] == '0')
	buf[14] = ' ';
    buf[15] = '0' + (me->p_speed % 10);	/* speed */
    buf[16] = ' ';
    buf[17] = ' ';
    buf[18] = '0' + (me->p_damage / 100);
    if (buf[18] == '0')
	buf[18] = ' ';
    buf[19] = '0' + ((me->p_damage % 100) / 10);
    if ((buf[19] == '0') && (me->p_damage < 100))
	buf[19] = ' ';
    buf[20] = '0' + (me->p_damage % 10);
    buf[21] = ' ';
    buf[22] = '0' + (me->p_shield / 100);
    if (buf[22] == '0')
	buf[22] = ' ';
    buf[23] = '0' + ((me->p_shield % 100) / 10);
    if ((buf[23] == '0') && (me->p_shield < 100))
	buf[23] = ' ';
    buf[24] = '0' + (me->p_shield % 10);
    buf[25] = ' ';
    buf[26] = ' ';
    buf[27] = '0' + ((me->p_ntorp % 100) / 10);
    if (buf[27] == '0')
	buf[27] = ' ';
    buf[28] = '0' + (me->p_ntorp % 10);
    buf[29] = ' ';
    buf[30] = ' ';
    buf[31] = ' ';
    buf[32] = ' ';
    buf[33] = '0' + ((int) (me->p_kills / 10));
    if (buf[33] == '0')
	buf[33] = ' ';
    buf[34] = '0' + (((int) me->p_kills) % 10);
    buf[35] = '.';
    buf[36] = '0' + (((int) (me->p_kills * 10)) % 10);
    buf[37] = '0' + (((int) (me->p_kills * 100)) % 10);
    buf[38] = ' ';
    buf[39] = ' ';
    buf[40] = ' ';
    buf[41] = '0' + ((me->p_armies % 100) / 10);
    if (buf[41] == '0')
	buf[41] = ' ';
    buf[42] = '0' + (me->p_armies % 10);
    buf[43] = ' ';
    buf[44] = ' ';
    buf[45] = ' ';

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

    buf[55] = '0' + ((me->p_wtemp / 10) / 100);
    if (buf[55] == '0')
	buf[55] = ' ';
    buf[56] = '0' + (((me->p_wtemp / 10) % 100) / 10);
    if ((buf[56] == '0') && (me->p_wtemp < 1000))
	buf[56] = ' ';
    buf[57] = '0' + ((me->p_wtemp / 10) % 10);

    buf[58] = ' ';
    buf[59] = ' ';
    buf[60] = ' ';
    buf[61] = '0' + ((me->p_etemp / 10) / 1000);
    if (buf[61] == '0')
	buf[61] = ' ';
    buf[62] = '0' + (((me->p_etemp / 10) % 1000) / 100);
    if (buf[62] == '0' && me->p_etemp < 1000)
	buf[62] = ' ';
    buf[63] = '0' + (((me->p_etemp / 10) % 100) / 10);
    if ((buf[63] == '0') && (me->p_etemp < 1000))
	buf[63] = ' ';
    buf[64] = '0' + ((me->p_etemp / 10) % 10);
    buf[65] = ' ';
#endif
#endif

    if (whichbuf == 0) {
	/* Draw status line */
	W_WriteText(tstatw, TSTATW_BASEX, 16, textColor, buf, 66, W_RegularFont);
	whichbuf = 1;
    } else {			/* Hacks to make it print only what is
				   necessary */
	whichbuf = 3 - whichbuf;
	j = -1;
	for (i = 0; i < 66; i++) {
	    if (*(buf++) != *(oldbuf++)) {
		/* Different string */
		if (j == -1) {
		    k = i;
		    s = buf - 1;
		}
		j = 0;
	    } else {
		/* Same string */
		if (j == -1)
		    continue;
		j++;
		if (j == 20) {	/* Random number */
		    W_WriteText(tstatw, TSTATW_BASEX + W_Textwidth * k, 16, textColor,
				s, i - k - 19, W_RegularFont);
		    j = -1;
		}
	    }
	}
	if (j != -1) {
	    W_WriteText(tstatw, TSTATW_BASEX + W_Textwidth * k, 16, textColor, s, i - k - j,
			W_RegularFont);
	}
    }
}

void
redrawTstats()
{
    char    buf[100];
    W_ClearWindow(tstatw);
    /* use new dashboard if possible */
    if (newDashboard) {
	db_redraw(1);
	return;
    }
    stline(1);			/* This is for refresh.  We redraw player
				   stats too */
    strcpy(buf, "Flags        Speed  Dam Shd Trp  Kills Ams   Fuel  Wtmp Etmp  Special"	/* "Flags        Warp
											   Dam Shd Torps  Kills
											   Armies   Fuel  Wtemp
	       Etemp" */ );
    W_WriteText(tstatw, TSTATW_BASEX, 5, textColor, buf, strlen(buf), W_RegularFont);
    sprintf(buf,
	    "Maximum:      %2d    %3d %3d  8         %3d %6d  %4d %4d ",
	    me->p_ship->s_maxspeed, me->p_ship->s_maxdamage,
	    me->p_ship->s_maxshield, me->p_ship->s_maxarmies,
	    me->p_ship->s_maxfuel, me->p_ship->s_maxwpntemp / 10,
	    me->p_ship->s_maxegntemp / 10);
    W_WriteText(tstatw, TSTATW_BASEX, 27, textColor, buf, strlen(buf), W_RegularFont);
}
#endif