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