DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

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

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T r

⟦67647c4e1⟧ TextFile

    Length: 14848 (0x3a00)
    Types: TextFile
    Names: »rmove.c«

Derivation

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

TextFile

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);
}