From: fadden@uts.amdahl.com (Andy McFadden)
Newsgroups: rec.games.netrek
Subject: Amdahl scanning beam code
Date: 13 Apr 92 18:46:41 GMT
Reply-To: fadden@amdahl.uts.amdahl.com (Andy McFadden)
Organization: Amdahl Corporation, Sunnyvale CA


A couple of people have expressed an interest in scanning beams.  Here are
the support files which go along with the UDP scanning beam code, and
diffs to help adjust the other source files.  These are called "Amdahl
scanning beams" not because I invented them but rather to differentiate
my implementation from others.

(NOTE: this doesn't include the changes for packets.h and socket.c; I assume
you already have those as part of the UDP distribution.)

The diffs are old and may not work very well.  Fortunately they're short.
I think (hope) everything you'll need is here.


netrek/scan.c is just "stats.c" hacked by a coworker to display the scan
data.  It also has some entry points similar to those used in inform.c
for the 'i' window (which is how it was originally implemented).

ntserv/phaser.c is the same old phaser.c with a new routine tacked on to the
end of it.  Tweaking the scan policy is done here.

scan-patches is the pile of context diffs for the client.  It patches all
the stuff you'd expect (input.c, data.c, data.h).  You may have to apply these
by hand.


----- netrek/scan.c ----- cut here -----
/*
 * scan.c
 */
#include "copyright.h"

#include <stdio.h>
#include "Wlib.h"
#include "defs.h"
#include "struct.h"
#include "data.h"
#include "packets.h"

/* ATM - scanner stuff */
static W_Window scanww;
static int scanmx, scanmy;

scan(ww, x, y)
W_Window ww;
int x, y;
{
    struct obtype *gettarget(), *target;

    scanww = ww;	/* remember these for later */
    scanmx = x;
    scanmy = y;

    /* find player nearest to mouse */
    target = gettarget(ww, x, y, TARG_PLAYER);

    /* don't scan myself */
    if (target->o_num == me->p_no) {
	warning("Nobody to scan");
	return;
    }

    /* send the request to the server */
    sendScanReq(target->o_num);
}

informScan(pnum)
int pnum;
{
    scanplayer = pnum;
    W_MapWindow(scanwin);
    scanmapped = 1;
    redrawScan();
    calibrate_scan();
    updateScan();
}


/* from here on it's from stats.c */

#define	MIN(a,b)	(((a) < (b)) ? (a) : (b))

#define	BX_OFF()	((textWidth + 1) * W_Textwidth + S_IBORDER)
#define	BY_OFF(line)	((line) * (W_Textheight + S_IBORDER) + S_IBORDER)
#define	TX_OFF(len)	((textWidth - len) * W_Textwidth + S_IBORDER)
#define	TY_OFF(line)	BY_OFF(line)

#define SCAN_WIDTH		160
#define SCAN_HEIGHT		BY_OFF(NUM_SLIDERS)
#define SCAN_BORDER		2
#define S_IBORDER		5
#define SCAN_X			422
#define SCAN_Y			13

#define SL_WID			\
	(SCAN_WIDTH - 2 * S_IBORDER - (textWidth + 1) * W_Textwidth)
#define SL_HEI			(W_Textheight)

#define NUM_ELS(a)		(sizeof (a) / sizeof (*(a)))
#define NUM_SLIDERS		NUM_ELS(scanners)

typedef struct slider {
	char	*label;
	int	min, max;
	int	low_red, high_red;
	int	label_length;
	int	diff;
	int	*var;
	int	lastVal;
} SLIDER;

typedef struct record {
	int	*data;
	int	last_value;
} RECORD;

static SLIDER	scanners[] = {
	{ "Shields",		0,	100,	20,	100	},
	{ "Damage",		0,	100,	0,	0	},
	{ "Fuel",		0,	10000,	2000,	10000	},
	{ "Warp",		0,	9,	0,	9	},
	{ "Weapon Temp",	0,	1200,	0,	800	},
	{ "Engine Temp",	0,	1200,	0,	800	},
};

static int		textWidth = 0;
static int 		initialized = 0;

initScan()
{
    int	i;
    /*char	*str;*/
    scanners[0].var = &(players[scanplayer].p_shield);
    scanners[1].var = &(players[scanplayer].p_damage);
    scanners[2].var = &(players[scanplayer].p_fuel);
    scanners[3].var = &(players[scanplayer].p_speed);
    scanners[4].var = &(players[scanplayer].p_wtemp);
    scanners[5].var = &(players[scanplayer].p_etemp);
    for (i = 0; i < NUM_SLIDERS; i++) {
	scanners[i].label_length = strlen(scanners[i].label);
	textWidth = MAX(textWidth, scanners[i].label_length);
	scanners[i].diff = scanners[i].max - scanners[i].min;
	scanners[i].lastVal=0;
    }
}

redrawScan()
{
    int	i;
    char tempstr[128];

    W_ClearWindow(scanwin);
    initScan();
    for (i=0; i<NUM_SLIDERS; i++) {
	scanners[i].lastVal=0;
    }

    sprintf(tempstr,"SCAN of %s(%c%d)",players[scanplayer].p_name,
	teamlet[players[scanplayer].p_team],players[scanplayer].p_no);
    W_WriteText(scanwin, 0, TY_OFF(0),
	textColor, tempstr, strlen(tempstr), W_RegularFont);
    for (i = 0; i < NUM_SLIDERS; i++) {
	W_WriteText(scanwin, TX_OFF(scanners[i].label_length), TY_OFF(i+1),
	    textColor, scanners[i].label, scanners[i].label_length,
	    W_RegularFont);
	drwbox(0, BX_OFF() - 1, BY_OFF(i+1) - 1, SL_WID+2, SL_HEI+2, borderColor);
	scanners[i].lastVal=0;
    }
    W_WriteText(scanwin, TX_OFF(strlen("Armies:")), TY_OFF(NUM_SLIDERS+1),
	textColor, "Armies:", strlen("Armies:"), W_RegularFont);
    sprintf(tempstr,"%d",players[scanplayer].p_armies);
    W_WriteText(scanwin, BX_OFF()-1, TY_OFF(NUM_SLIDERS+1),
	textColor, tempstr, strlen(tempstr), W_RegularFont);
}

updateScan()
{
    int	i, value, diff, old_x, new_x;
    W_Color color;
    SLIDER	*s;

    initScan();
    for (i = 0; i < NUM_SLIDERS; i++) {
	s = &scanners[i];
	value= *(s->var);
	if (value < s->min)
	    value = s->min;
	else if (value > s->max)
	    value = s->max;
	if (value == s->lastVal)
	    continue;
	diff = value - s->lastVal;
	if (diff < 0) {
	    old_x = s->lastVal * SL_WID / s->diff;
	    new_x = value * SL_WID / s->diff;
	    drwbox(1, BX_OFF()+new_x, BY_OFF(i+1), old_x-new_x, SL_HEI, backColor);

	    if (s->lastVal >= s->low_red && value < s->low_red) 
		drwbox(1, BX_OFF(), BY_OFF(i+1), new_x, SL_HEI, warningColor);
	    else if (s->lastVal > s->high_red && value <= s->high_red) 
		drwbox(1, BX_OFF(), BY_OFF(i+1), new_x, SL_HEI, myColor);
	} else {
	    if (value < s->low_red)
		color = warningColor;
	    else if (value > s->high_red) {
		color = warningColor;
		if (s->lastVal <= s->high_red)
		    s->lastVal = 0;
	    } else {
		color = myColor;
		if (s->lastVal < s->low_red)
		    s->lastVal = 0;
	    }
	    old_x = s->lastVal * SL_WID / s->diff;
	    new_x = value * SL_WID / s->diff;
	    drwbox(1, BX_OFF() + old_x, BY_OFF(i+1), new_x - old_x, SL_HEI, color);
	}
	s->lastVal=value;
    }
}

drwbox(filled, x, y, wid, hei, color)
int filled, x, y, wid, hei;
W_Color color;
{
    if (wid==0) return;
    if (filled) {
	W_ClearArea(scanwin, x, y, wid+1, hei+1, color);
	return;
    }

    W_MakeLine(scanwin,x,y,x+wid,y,color);
    W_MakeLine(scanwin,x+wid,y,x+wid,y+hei,color);
    W_MakeLine(scanwin,x+wid,y+hei,x,y+hei,color);
    W_MakeLine(scanwin,x,y+hei,x,y,color);
}


calibrate_scan()
{
    register int i;

    scanners[0].max = players[scanplayer].p_ship.s_maxshield;
    scanners[0].low_red = .20 * ((double) scanners[0].max);
    scanners[0].high_red = scanners[0].max;

    scanners[1].max = players[scanplayer].p_ship.s_maxdamage;

    scanners[2].max = players[scanplayer].p_ship.s_maxfuel;
    scanners[2].low_red = .20 * ((double) scanners[2].max);
    scanners[2].high_red = scanners[2].max;

    scanners[3].max = players[scanplayer].p_ship.s_maxspeed;
    scanners[3].high_red = scanners[3].max;

    scanners[4].max = 1.2 * ((double) players[scanplayer].p_ship.s_maxwpntemp);
    scanners[4].high_red = .667 * ((double) scanners[4].max);

    scanners[5].max = 1.2 * ((double) players[scanplayer].p_ship.s_maxegntemp);
    scanners[5].high_red = .667 * ((double) scanners[5].max);

    for (i=0; i<NUM_SLIDERS; i++) 
	scanners[i].diff = scanners[i].max - scanners[i].min;

}

----- end of netrek/scan.c ----- cut here -----


----- ntserv/phaser.c ----- cut here -----
/*
 * phaser.c
 */
#include "copyright.h"

#include <stdio.h>
#include <math.h>
#include <signal.h>
#include "defs.h"
#include "struct.h"
#include "data.h"

phaser(course)
unsigned char course;
{
    register int i;
    register struct player *j, *target;
    register struct plasmatorp *target2;
    register struct plasmatorp *k;
    register struct phaser *mine;
    int whichtarget;
    int target_x, target_y;
    unsigned char dir;
    int range, trange;
    int maxangle;
    int myphrange;
    char buf[80];

    mine = &phasers[me->p_no];

    if (myship->s_phasercost < 0) {
	warning("Weapons Officer:  This ship is not armed with phasers, captain!");
	return;
    }
    if (mine->ph_status != PHFREE) {
	warning("Phasers have not recharged");
	return;
    }
    if (me->p_fuel < myship->s_phasercost) {
	warning("Not enough fuel for phaser");
	return;
    }
    if (me->p_flags & PFREPAIR) {
	warning("Can't fire while repairing");
	return;
    }
    if (me->p_flags & PFWEP) {
	warning("Weapons overheated");
	return;
    }
    if ((me->p_cloakphase) && (me->p_ship.s_type != ATT)) {
	warning("Cannot fire while cloaked");
	return;
    }

    me->p_fuel -= myship->s_phasercost;
    me->p_wtemp += myship->s_phasercost / 10;
    mine->ph_dir = course;

    whichtarget=0;
    range=1000000;	/* Sufficiently big. */

    for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
	if ((j->p_status != PALIVE) || (j == me))
	    continue;
	if ((!((j->p_swar | j->p_hostile) & me->p_team)) &&
	    (!((me->p_swar | me->p_hostile) & j->p_team)))
		continue;
	dir = (unsigned char) (atan2((double) (j->p_x - me->p_x),
	    (double) (me->p_y - j->p_y)) / 3.14159 * 128.);
	trange = (int) hypot((double) (j->p_x - me->p_x),
	    (double) (j->p_y - me->p_y));
	if (trange==0) trange=1;
	maxangle = atan((float) EXPDIST / trange) / 3.14159 * 128.0;
	if (angdist(dir, course) <= maxangle) {
	    if (range > trange) {
		whichtarget = 1;
		target = j;
		range = trange;
	    }
	}
    }

    for (i = 0, k = &plasmatorps[i]; i < MAXPLASMA*MAXPLAYER; i++, k++) {
	if ((k->pt_status != PTMOVE) || (k->pt_owner == me->p_no))
	    continue;
	if ((!(k->pt_war & me->p_team)) &&
	    (!((me->p_swar | me->p_hostile) & k->pt_team)))
		continue;
	dir = (unsigned char) (atan2((double) (k->pt_x - me->p_x),
	    (double) (me->p_y - k->pt_y)) / 3.14159 * 128.);
	trange = (int) hypot((double) (k->pt_x - me->p_x),
	    (double) (k->pt_y - me->p_y));
	if (trange==0) trange=1;
	maxangle = atan((float) EXPDIST / 4 / trange) / 3.14159 * 128.0;
	if (angdist(dir, course) <= (maxangle+1)) {
	    if (range > trange) {
		target_x = k->pt_x;
		target_y = k->pt_y;
		whichtarget = 2;
		target2 = k;
		range = trange;
	    }
	}
    }

    mine->ph_fuse=me->p_ship.s_phaserfuse;

    myphrange = PHASEDIST * me->p_ship.s_phaserdamage / 100;

    if ((whichtarget == 0) || 
	    (range > myphrange)) {
	mine->ph_status = PHMISS;
	warning("Phaser missed!!!");
    } else if (whichtarget == 2) {
	warning("You destroyed the plasma torpedo!");
	mine->ph_x = target_x;
	mine->ph_y = target_y;
	mine->ph_status = PHHIT2;
	target2->pt_status = PTDET;
    } else {
	mine->ph_target = target->p_no;
	mine->ph_damage = me->p_ship.s_phaserdamage * 
	    (1.0 - (range / (float) myphrange));
	if (mine->ph_damage < 0) mine->ph_damage = - mine->ph_damage;
	mine->ph_status = PHHIT;
	(void) sprintf(buf, "Phaser burst hit %s for %d points",
	    target->p_name,
	    mine->ph_damage);
	warning(buf);
    }
}

/*
 * ATM: scanners are kinda like phasers
 */
int
scan(pnum)
{
    int range;
    int scandamage, myscrange, scanstr;
    struct player *pp;

    pp = &players[pnum];

    /* scan range is 1.5 * phaser range; scout is 2 * phaser range */
    /* (not really scan "damage"; I'm just using a similar naming convention) */
    scandamage = me->p_ship.s_phaserdamage;
    if (me->p_ship.s_type == SCOUT)
	scandamage <<= 1;			/* 2 * phasers */
    else
	scandamage += (scandamage / 2);		/* 1.5 * phasers */
    myscrange = PHASEDIST * scandamage / 100;

    range = hypot((double) (me->p_x - pp->p_x), (double) (me->p_y - pp->p_y));
    if (range > myscrange) {
	warning("Out of scanner range");
	return(0);
    }

    /* ship in range, try to scan */
    me->p_fuel -= myship->s_phasercost / 4;
    if (pp->p_flags & PFSHIELD && pp->p_team != me->p_team) {
	scanstr = scandamage * (1.0 - (range / (float) myscrange));
	if (scanstr <= pp->p_shield) {
	    warning("Unable to penetrate shields");
	    return(0);
	}
    }

    /* successful scan (shields down, same team, or penetrated shields) */
    return(1);
}
----- end of ntserv/phaser.c ----- cut here -----


----- scan-patches ----- cut here -----
-----
*** defs.h	Mon Dec  9 12:13:31 1991
--- ../netrek/defs.h	Mon Dec 16 11:29:09 1991
***************
*** 170,175 ****
--- 170,176 ----
  #define sendByeReq() sendShortPacket(CP_BYE, 0)
  #define sendDockingReq(state) sendShortPacket(CP_DOCKPERM, state)
  #define sendResetStatsReq(verify) sendShortPacket(CP_RESETSTATS, verify)
+ #define sendScanReq(who) sendShortPacket(CP_SCAN, who)		/* ATM */
  
  /* This macro allows us to time things based upon # frames / sec.
   */
*** data.h	Mon Dec  9 12:13:31 1991
--- ../netrek/data.h	Mon Dec 16 11:22:08 1991
***************
*** 71,76 ****
--- 71,77 ----
  extern int warncount;
  extern int warntimer;
  extern int infomapped;
+ extern int scanmapped;	/* ATM - scanner stuff */
  extern int mustexit;
  extern int messtime;
  extern int keeppeace;
***************
*** 130,133 ****
  
  extern W_Window	messagew, w, mapw, statwin, baseWin, infow, iconWin, tstatw,
  		war, warnw, helpWin, teamWin[4], qwin, messwa, messwt, messwi,
! 		messwk, planetw, rankw, playerw, optionWin, reviewWin;
--- 131,134 ----
  
  extern W_Window	messagew, w, mapw, statwin, baseWin, infow, iconWin, tstatw,
  		war, warnw, helpWin, teamWin[4], qwin, messwa, messwt, messwi,
! 		messwk, planetw, rankw, playerw, optionWin, reviewWin, scanw;
*** data.c	Mon Dec  9 12:13:31 1991
--- ../netrek/data.c	Mon Dec 16 11:39:06 1991
***************
*** 42,47 ****
--- 42,48 ----
  int	warncount = 0;
  int	warntimer = -1;
  int	infomapped = 0;
+ int	scanmapped = 0;		/* ATM - scanners */
  int	mustexit = 0;
  int	messtime = 5;
  int	keeppeace = 0;
***************
*** 106,109 ****
  
  W_Window messagew, w, mapw, statwin, baseWin, infow, iconWin, tstatw,
  	war, warnw, helpWin, teamWin[4], qwin, messwa, messwt, messwi, messwk,
! 	planetw, playerw, rankw, optionWin = 0, reviewWin;
--- 107,110 ----
  
  W_Window messagew, w, mapw, statwin, baseWin, infow, iconWin, tstatw,
  	war, warnw, helpWin, teamWin[4], qwin, messwa, messwt, messwi, messwk,
! 	planetw, playerw, rankw, optionWin = 0, reviewWin, scanw;
*** input.c	Mon Dec  9 12:13:32 1991
--- ../netrek/input.c	Mon Dec 16 13:17:07 1991
***************
*** 115,121 ****
      struct obtype *gettarget(), *target;
      char key=data->key;
  
!     if (data->Window!=mapw && data->Window!=w && data->Window!=infow) return;
      if (!index("sbogadc", key) || !(localflags & PFREFIT)) {
  	if (key >= 32 && key < 127) {
  	    key=mystats->st_keymap[key - 32];
--- 115,121 ----
      struct obtype *gettarget(), *target;
      char key=data->key;
  
!     if (data->Window!=mapw && data->Window!=w && data->Window!=infow && data->Window!=scanw) return;
      if (!index("sbogadc", key) || !(localflags & PFREFIT)) {
  	if (key >= 32 && key < 127) {
  	    key=mystats->st_keymap[key - 32];
***************
*** 168,173 ****
--- 168,179 ----
  	case 'a':
  	    if (localflags & PFREFIT) {
  		do_refit(ASSAULT);
+ 	    } else {
+ 		/* ATM - scanners ("About...") */
+ 		if (!scanmapped)
+ 		    scan(data->Window, data->x, data->y);
+ 		else
+ 		    destroyScan();
  	    }
  	    break;
  	case 'k': /* k = set course */
----- end of scan-patches ----- cut here -----

-- 
fadden@uts.amdahl.com (Andy McFadden)
[ Above opinions are mine, Amdahl has nothing to do with them, etc, etc. ]