|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T r
Length: 14848 (0x3a00)
Types: TextFile
Names: »rmove.c«
└─⟦b20c6495f⟧ Bits:30007238 EUUGD18: Wien-båndet, efterår 1987
└─⟦this⟧ »EUUGD18/X/Xtrek/rmove.c«
static char sccsid[] = "@(#)rmove.c 1.1";
#ifndef lint
static char *rcsid_rmove_c = "$Header: /uraid2/riedl/src/xceltrek/RCS/rmove.c,v 1.1 88/04/18 16:10:39 riedl Exp Locker: riedl $";
#endif lint
/* Copyright (c) 1986 Chris Guthrie */
#include <X11/Xlib.h>
#include <stdio.h>
#include "defs.h"
#include "data.h"
#define AVOID_TIME 4
#define STAY 0x1
#define RUN 0x2
#define ATTACK 0x3
#define REPAIR 0x4
#define AVOID 0x5
#define NORMALIZE(d) ((((d) % 256) + 256) % 256)
#define rgetcourse newcourse
#define rstatus (p->p_rmode)
#define avoidTime (p->p_timer)
extern int debug;
extern int playerchange;
extern int nplayers;
extern int nrobots;
extern long isin[], icos[];
extern unsigned char iatan2();
double hypot();
extern unsigned char newcourse();
int calculate_hit();
rmove(p)
struct player *p;
{
struct player *enemy;
int edist;
unsigned char ecourse;
register int i;
register struct player *j;
register int burst;
register int numHits, tDir;
int avDir;
int torp_can_hit;
double dx, dy;
int tdist;
unsigned char tcourse = 10;
/* Find an enemy */
enemy = p;
edist = GWIDTH + 1;
for (i = 0, j = &players[i]; i < MAXPLAYER; i++, j++) {
if ((j->p_status != PALIVE) || (j == p) ||
((j->p_flags & PFROBOT) && (!(p->p_flags & PFRHOSTILE))))
continue;
if (((j->p_swar | j->p_hostile) & p->p_team) ||
((p->p_swar | p->p_hostile) & j->p_team)) {
/* We have an enemy */
/* Get his range */
dx = j->p_x - p->p_x;
dy = j->p_y - p->p_y;
/* No way this enemy can be closer than known enemy */
if (dx > edist || dy > edist) continue;
tdist = hypot(dx, dy);
/* Check to see if ship is in our space. */
if (!(p->p_flags & PFRHOSTILE)) {
if (tdist > 15000) {
switch (p->p_team) {
case FED:
if ((j->p_x > GWIDTH/2) || (j->p_y < GWIDTH/2))
continue;
break;
case ROM:
if ((j->p_x > GWIDTH/2) || (j->p_y > GWIDTH/2))
continue;
break;
case KLI:
if ((j->p_x < GWIDTH/2) || (j->p_y > GWIDTH/2))
continue;
break;
case ORI:
if ((j->p_x < GWIDTH/2) || (j->p_y < GWIDTH/2))
continue;
break;
}
}
}
if (debug)
fprintf(stderr, "%d) found enemy %d in our space at %d,%d\n",
p->p_no,
j->p_no,
j->p_x,
j->p_y);
if (tdist < edist) {
enemy = j;
edist = tdist;
continue;
}
}
}
/** level 1 **/
if (enemy == p) {
if (!(p->p_flags & PFRSTICKY) || (nplayers - nrobots) == 0) { /* No more enemies */
if (p->p_explode == 0)
p->p_explode = p->p_updates + RGIVEUPTIME;
if (p->p_updates >= p->p_explode) {
playerchange = 1;
p->p_status = PFREE;
return(0);
}
go_home(p);
} else {
p->p_explode = 0;
go_home(p);
}
return(0);
}
/** level 1 **/
/* Get course for torp to nearest enemy */
/*
torp_can_hit = calculate_hit
(p->p_ship.s_torpspeed*WARP1, p->p_x, p->p_y,
enemy->p_speed*WARP1, enemy->p_dir, enemy->p_x, enemy->p_y,
&impact_dir, &impact_time, &impact_dist,
&impact_x, &impact_y);
*/
/*
* This code figures out how to shoot at the enemy chosen above.
* For the old style torps that have a fixed velocity I have an
* analytical solution in calculate_hit (below), but for the fancy
* new torps that pick up the velocity of the ship that shoots them I
* have to compute the direction iteratively. The approach is:
*
* for each time from 0 to (a guess at how long a torp lasts)
* compute where the enemy will be at that time if he doesn't turn
* (this is the potential impact point)
*
* determine the course that we should aim a torpedo to get
* from where we are to where he will be. This involves
* calculating an adjusted impact point by subtracting the
* total influence of the robot's speed over i turns from the
* primary impact point.
*
* figure out where a `normal' torpedo (one that doesn't get the
* velocity of the ship added in) aimed in that direction will
* be at the impact time.
*
* see if the adjusted torpedo will be close enough at impact time
* to the adjusted impact point to make the shot worthwhile.
*
* currently, we check through all possible times and choose the
* best possible hit. This is probably a mistake since a late
* "perfect" hit is unlikely to succeed since the enemy will
* have plenty of time to dodge. Better is to choose the first
* reasonable hit, but that will have to wait until I think up
* a good definition of reasonable. Choosing the first hit also
* has the advantage of being faster.
*/
{
int i;
int impact_x, impact_y, impact_dx, impact_dy;
int adjust_impact_dx, adjust_impact_dy;
int torp_dx, torp_dy, torp_x, torp_y;
double error, best_error;
int new_tcourse;
best_error = 10000;
torp_can_hit = 0;
adjust_impact_dx = (icos[p->p_dir] * p->p_speed * WARP1) >> TRIGSCALE;
adjust_impact_dy = (isin[p->p_dir] * p->p_speed * WARP1) >> TRIGSCALE;
impact_dx = (icos[enemy->p_dir] * enemy->p_speed * WARP1) >> TRIGSCALE;
impact_dy = (isin[enemy->p_dir] * enemy->p_speed * WARP1) >> TRIGSCALE;
for (i = 0, impact_x = enemy->p_x, impact_y = enemy->p_y;
i < 50;
i++, impact_x += impact_dx - adjust_impact_dx,
impact_y += impact_dy - adjust_impact_dy) {
new_tcourse = rgetcourse(p, impact_x, impact_y);
torp_dx = p->p_ship.s_torpspeed * icos[new_tcourse] * WARP1;
torp_dy = p->p_ship.s_torpspeed * isin[new_tcourse] * WARP1;
torp_dx = (torp_dx + (TRIGSCALE>>1)) >> TRIGSCALE;
torp_dy = (torp_dy + (TRIGSCALE>>1)) >> TRIGSCALE;
torp_x = p->p_x + torp_dx*i;
torp_y = p->p_y + torp_dy*i;
error = hypot((double)(torp_x-impact_x), (double)(torp_y-impact_y));
if (error < best_error) {
torp_can_hit = (error < EXPDIST);
best_error = error;
tcourse = new_tcourse;
}
}
if (debug) {
if (torp_can_hit) {
printf("Aim in dir %d to hit in time %d at adjusted x=%d, y=%d\n",
tcourse, i, impact_x, impact_y);
}
else {
printf("Can't hit\n");
}
}
}
/** level 1 **/
ecourse = rgetcourse(p, enemy->p_x, enemy->p_y);
if (debug)
fprintf(stderr, "Course to enemy is %d (%d)\n", (int)ecourse,
(int) ecourse * 360 / 256);
if ((edist > 40000) && !((p->p_flags & PFRHOSTILE))) {
if (p->p_damage > 0) {
p->p_desspeed = 0;
shield_down(p);
repair(p);
if (debug)
fprintf(stderr, "%d) repairing damage at %d\n",
p->p_no,
p->p_damage);
}
else {
rstatus = STAY;
go_home(p);
}
return;
}
if (enemy == p) go_home(p);
/** level 1 **/
if ((p->p_damage > 20 || p->p_fuel < 1000) && edist < 25000) {
/* Run away */
p->p_desspeed = 6;
if (!(p->p_flags & PFCLOAK) && p->p_fuel > 2000)
cloak(p);
shield_down(p);
p->p_desdir = ecourse - 128;
}
else if (rstatus == AVOID) {
if (--avoidTime <= 0)
rstatus = ATTACK;
if (debug)
fprintf(stderr, "avoiding: dir = %d\n", p->p_desdir);
} else {
rstatus = ATTACK;
if (p->p_flags & PFCLOAK)
cloak(p);
if (p->p_desdir != p->p_dir)
p->p_desspeed = 2;
else if (p->p_etemp > 900) /* 90% of 1000 */
p->p_desspeed = 4;
else
p->p_desspeed = 6;
shield_up(p);
if (edist < 15000) {
numHits = projectDamage(p, enemy->p_no, &avDir);
if (debug) {
fprintf(stderr, "%d hits expected from %d from dir = %d\n",
numHits, enemy->p_no, avDir);
}
if (numHits == 0) {
p->p_desdir = ecourse + 32;
}
else {
/*
* Avoid Torps
*/
avoidTime = AVOID_TIME;
tDir = avDir - p->p_dir;
/* put into 0->255 range */
tDir = NORMALIZE(tDir);
switch (tDir / 64) {
case 0:
case 1:
p->p_desdir = NORMALIZE(avDir + 64);
break;
case 2:
case 3:
p->p_desdir = NORMALIZE(avDir - 64);
break;
}
if (!(p->p_flags & PFCLOAK) && p->p_fuel > 2000)
cloak(p);
rstatus = AVOID;
if (debug)
fprintf(stderr, "evading to dir = %d\n", p->p_desdir);
}
} else {
if (!(p->p_flags & PFRHARD))
p->p_desdir = ecourse;
else { /* try to go where he will be when we catch with him */
int can_hit;
int impact_dir, impact_x, impact_y;
double impact_dist, impact_time;
can_hit = calculate_hit
(p->p_speed*WARP1, p->p_x, p->p_y,
enemy->p_speed*WARP1, enemy->p_dir, enemy->p_x, enemy->p_y,
&impact_dir, &impact_time, &impact_dist,
&impact_x, &impact_y);
if (can_hit)
p->p_desdir = impact_dir;
else
p->p_desdir = ecourse; /* go straight at him */
}
}
}
/** level 1 **/
/* Fire weapons!!! */
if (p->p_fuel > 0 && (float)edist/p->p_fuel < 1.0000 && torp_can_hit) {
for (burst = 0; (burst < 1) && (p->p_ntorp < MAXTORP); burst++) {
if (p->p_flags & PFCLOAK)
cloak(p);
if (!(p->p_flags & PFRHARD))
ntorp(p, tcourse, TMOVE);
else
ntorp(p, tcourse, TSTRAIGHT);
}
}
/** level 1 **/
if ((edist < 5000) && (p->p_flags & PFRHARD) && p->p_fuel > 1000) {
if (p->p_flags & PFCLOAK)
cloak(p);
phaser(p, ecourse);
}
}
/*
* calculate_hit: figure out what direction to aim to hit somebody.
* - works with torps/ships/...
* - doesn't work with torps anymore since some of their speed depends
* on the speed and direction of the ship that fires them. Oh well.
*
* We'll call the robot's current position A the enemy's current position
* B, and the place where the torpedo hits C. T will be the time at
* which the torpedo and enemy both reach C. We'll call the internal
* angle in ABC at A alpha, at B beta and at C gamma. a and b are the
* speeds of the robot and enemy, and c is the distance between them.
*
* To solve the problem we'll use the first compute beta as the difference
* between the enemy's current direction (beta1) and the direction from
* the enemy to the robot (beta2). Now we can use the law of sines to
* compute alpha from
* sin(alpha) / b*T = sin(beta) / a*T
* since the T's (which we don't yet know!) cancel
*
* This gives delta = pi - alpha - beta since alpha, beta and delta are
* the three angles of a triangle. Now we apply the law of sines again
* to compute T from
* sin(alpha) / b*T = sin(delta) / d
*
* Since we now know the time to collision and we know the speed and
* direction of the enemy it is easy to compute where the enemy will be
* when the collision takes place (C). Knowing C and A it is trivial
* to compute the angle between them.
*
* We'll return a 0 if a hit is impossible and a 1 if it is possible.
* Note that some `possible' hits will take place a long time in the
* future.
*
* Sorry about the ridiculous number of arguments. Most of them are
* pretty obvious with the exception that the speeds used by this
* routine must be multiplied by the constant WARP1 by the calling
* procedure.
* John Riedl
*/
int
calculate_hit(me_speed, me_x, me_y,
enemy_speed, enemy_dir, enemy_x, enemy_y,
pimpact_dir, pimpact_time, pimpact_dist, pimpact_x, pimpact_y)
int me_speed, me_x, me_y, enemy_speed, enemy_x, enemy_y;
unsigned char enemy_dir;
int *pimpact_dir, *pimpact_x, *pimpact_y;
double *pimpact_time, *pimpact_dist;
{
int normal_isin();
extern unsigned char iatan2();
extern long isin[], icos[];
unsigned char beta1;
unsigned char beta2;
unsigned char alpha, beta, delta;
double asin_input, pi = 3.14159;
double hypot(), rint(), asin();
double fabs();
beta1 = enemy_dir;
beta2 = iatan2(me_x - enemy_x, enemy_y - me_y);
beta = beta1 - beta2;
beta = beta>128 ? 256-beta : beta;
asin_input = (double) (enemy_speed * normal_isin(beta))
/ (double) (me_speed << TRIGSCALE);
if (fabs(asin_input) > 1) { /* No way to hit */
return(0);
}
else {
alpha = (unsigned char) rint(asin(asin_input) / pi * 128.0);
alpha = alpha>128 ? 256-alpha: alpha;
/* Choose the more acute of the solution angles (quicker hit) */
alpha = 128-alpha < alpha ? 128-alpha : alpha;
delta = 128 - alpha - beta;
/* calculate the time to the impact */
*pimpact_dist = hypot((double)(enemy_x - me_x),
(double)(enemy_y - me_y));
*pimpact_time = (double) normal_isin(alpha) / normal_isin(delta) *
(double) *pimpact_dist / enemy_speed;
/* calculate the location of the impact */
*pimpact_x = enemy_x +
rint((enemy_speed*icos[enemy_dir]*(*pimpact_time))/(1<<TRIGSCALE));
*pimpact_y = enemy_y +
rint((enemy_speed*isin[enemy_dir]*(*pimpact_time))/(1<<TRIGSCALE));
*pimpact_dir = iatan2(*pimpact_x - me_x, me_y - *pimpact_y);
if (debug)
printf("Aim in direction %d to hit in time %lf at x=%d, y=%d\n",
*pimpact_dir, *pimpact_time, *pimpact_x, *pimpact_y);
}
return(1);
}
/*
* Stupid Sun 3.2 tan routine calls matherr and *prints* a message if
* it returns something other that 1.
*/
int matherr()
{
return(1);
}
struct {
int x;
int y;
} center[] = { {0, 0},
{GWIDTH / 4, GWIDTH * 3 / 4}, /* Fed */
{GWIDTH / 4, GWIDTH / 4}, /* Rom */
{0, 0},
{GWIDTH * 3 / 4, GWIDTH / 4}, /* Kli */
{0, 0},
{0, 0},
{0, 0},
{GWIDTH * 3 / 4, GWIDTH * 3 / 4}}; /* Ori */
/* This function will send the robot back to the center of it's
space when it has nothing better to do. Centers are defined
above.
*/
go_home(p)
struct player *p;
{
int x, y;
double dx, dy;
x = center[p->p_team].x;
y = center[p->p_team].y;
if ((ABS(x - p->p_x) < 100) && (ABS(y - p->p_y) < 100))
p->p_desspeed = 0;
else {
p->p_desdir = rgetcourse(p, x, y);
dx = x - p->p_x;
dy = y - p->p_y;
p->p_desspeed = (hypot(dx, dy) / 10000) + 1;
}
}
projectDamage(p, eNum, dirP)
struct player *p;
int *dirP;
{
register int i, j, numHits = 0, mx, my, tx, ty, dx, dy;
long tdx, tdy, mdx, mdy;
register struct torp *t;
*dirP = 0;
/* XX Fix this like the tcourse computation above */
for (i = 0, t = &torps[eNum * MAXTORP]; i < MAXTORP; i++, t++) {
if (t->t_status == TFREE)
continue;
tx = t->t_x; ty = t->t_y;
mx = p->p_x; my = p->p_y;
tdx = (t->t_speed * icos[t->t_dir] * WARP1) >> TRIGSCALE;
tdy = (t->t_speed * isin[t->t_dir] * WARP1) >> TRIGSCALE;
mdx = (p->p_speed * icos[p->p_dir] * WARP1) >> TRIGSCALE;
mdy = (p->p_speed * isin[p->p_dir] * WARP1) >> TRIGSCALE;
for (j = t->t_fuse; j > 0; j--) {
tx += tdx; ty += tdy;
mx += mdx; my += mdy;
dx = tx - mx; dy = ty - my;
if (ABS(dx) < EXPDIST && ABS(dy) < EXPDIST) {
numHits++;
*dirP += t->t_dir;
break;
}
}
}
if (numHits > 0)
*dirP /= numHits;
return (numHits);
}