* Copyright (c) 1980 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that this notice is preserved and that due credit is given
* to the University of California at Berkeley. The name of the University
* may not be used to endorse or promote products derived from this
* software without specific prior written permission. This software
* is provided ``as is'' without express or implied warranty.
static char sccsid
[] = "@(#)phaser.c 5.2 (Berkeley) %G%";
/* factors for phaser hits; see description below */
# define ALPHA 3.0 /* spread */
# define BETA 3.0 /* franf() */
# define GAMMA 0.30 /* cos(angle) */
# define EPSILON 150.0 /* dist ** 2 */
# define OMEGA 10.596 /* overall scaling factor */
/* OMEGA ~= 100 * (ALPHA + 1) * (BETA + 1) / (EPSILON + 1) */
** There are up to NBANKS phaser banks which may be fired
** simultaneously. There are two modes, "manual" and
** "automatic". In manual mode, you specify exactly which
** direction you want each bank to be aimed, the number
** of units to fire, and the spread angle. In automatic
** mode, you give only the total number of units to fire.
** The spread is specified as a number between zero and
** one, with zero being minimum spread and one being maximum
** spread. You will normally want zero spread, unless your
** short range scanners are out, in which case you probably
** don't know exactly where the Klingons are. In that case,
** you really don't have any choice except to specify a
** Phasers spread slightly, even if you specify zero spread.
"m", "anual", (int (*)())1, 0,
register struct kling
*k
;
double anglefactor
, distfactor
;
register struct banks
*b
;
struct banks bank
[NBANKS
];
return(printf("Phasers cannot fire through starbase shields\n"));
return (printf("Sulu: Captain, we cannot fire through shields.\n"));
printf("Sulu: Captain, surely you must realize that we cannot fire\n");
printf(" phasers with the cloaking device up.\n");
/* decide if we want manual or automatic mode */
printf(Device
[COMPUTER
].name
);
printf(Device
[SRSCAN
].name
);
printf(" damaged, manual mode selected\n");
ptr
= getcodpar("Manual or automatic", Matab
);
manual
= (int) ptr
->value
;
if (!manual
&& damaged(COMPUTER
))
printf("Computer damaged, manual selected\n");
/* initialize the bank[] array */
for (i
= 0; i
< NBANKS
; i
++)
/* collect manual mode statistics */
printf("%d units available\n", Ship
.energy
);
for (i
= 0; i
< NBANKS
; i
++)
printf("\nBank %d:\n", i
);
hit
= getintpar("units");
printf("available energy exceeded. ");
hit
= getintpar("course");
if (hit
< 0 || hit
> 360)
b
->angle
= hit
* 0.0174532925;
b
->spread
= getfltpar("spread");
if (b
->spread
< 0 || b
->spread
> 1)
/* automatic distribution of power */
return (printf("Sulu: But there are no Klingons in this quadrant\n"));
printf("Phasers locked on target. ");
printf("%d units available\n", Ship
.energy
);
hit
= getintpar("Units to fire");
printf("available energy exceeded. ");
anglefactor
= ALPHA
* BETA
* OMEGA
/ (distfactor
* distfactor
+ EPSILON
);
distfactor
/= anglefactor
;
hitreqd
[i
] = distfactor
+ 0.5;
b
->angle
= atan2(dy
, dx
);
b
->units
= ((n
- i
) / tot
) * extra
;
printf("b%d hr%d u%d df%.2f af%.2f\n",
distfactor
, anglefactor
);
hit
= b
->units
- hitreqd
[i
];
/* give out any extra energy we might have around */
hit
= hitreqd
[i
] - b
->units
;
printf("%d units overkill\n", extra
);
for (i
= 0; i
< NBANKS
; i
++)
printf("b%d u%d", i
, b
->units
);
printf(" a%.2f s%.2f\n", b
->angle
, b
->spread
);
/* actually fire the shots */
for (i
= 0; i
< NBANKS
; i
++)
printf("\nPhaser bank %d fires:\n", i
);
** The formula for hit is as follows:
** zap = OMEGA * [(sigma + ALPHA) * (rho + BETA)]
** / (dist ** 2 + EPSILON)]
** * [cos(delta * sigma) + GAMMA]
** where sigma is the spread factor,
** rho is a random number (0 -> 1),
** GAMMA is a crud factor for angle (essentially
** cruds up the spread factor),
** delta is the difference in radians between the
** angle you are shooting at and the actual
** ALPHA scales down the significance of sigma,
** BETA scales down the significance of rho,
** OMEGA is the magic number which makes everything
** up to "* hit" between zero and one,
** dist is the distance to the klingon
** hit is the number of units in the bank, and
** zap is the amount of the actual hit.
** Everything up through dist squared should maximize
** at 1.0, so that the distance factor is never
** greater than one. Conveniently, cos() is
** never greater than one, but the same restric-
distfactor
= BETA
+ franf();
distfactor
*= ALPHA
+ b
->spread
;
distfactor
/= anglefactor
* anglefactor
+ EPSILON
;
anglefactor
= atan2(dy
, dx
) - b
->angle
;
anglefactor
= cos((anglefactor
* b
->spread
) + GAMMA
);
hit
= anglefactor
* distfactor
+ 0.5;
printf("%d unit hit on Klingon", hit
);
printf(" at %d,%d", k
->x
, k
->y
);
for (i
= 0; i
< NBANKS
; i
++)
printf("\n%d units expended on empty space\n", extra
);