actionlib.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. #include "pch.h"
  2. // Utility functions:
  3. /*-------------------------------------------------------------------------
  4. * Function: getDirection
  5. *-------------------------------------------------------------------------
  6. * Purpose:
  7. * Get the button control mask to thrust in a given direction
  8. */
  9. int getDirection(const Vector& dP,
  10. const Orientation& orientation)
  11. {
  12. float z = dP * orientation.GetForward();
  13. float y = dP * orientation.GetUp();
  14. float x = dP * orientation.GetRight();
  15. double absX = fabs(x);
  16. double absY = fabs(y);
  17. double absZ = fabs(z);
  18. return (absX > absY)
  19. ? ((absX > absZ)
  20. ? (x >= 0.0f ? rightButtonIGC : leftButtonIGC)
  21. : (z >= 0.0f ? forwardButtonIGC : backwardButtonIGC))
  22. : ((absY > absZ)
  23. ? (y >= 0.0f ? upButtonIGC : downButtonIGC)
  24. : (z >= 0.0f ? forwardButtonIGC : backwardButtonIGC));
  25. }
  26. /*-------------------------------------------------------------------------
  27. * Enumeration: ShotStatus
  28. *-------------------------------------------------------------------------
  29. * Purpose:
  30. * How clean of a shot do we have??
  31. * Notes:
  32. * The values are ordered in order of importantance
  33. */
  34. enum ShotStatus
  35. {
  36. c_ssCleanShot = 0,
  37. c_ssNeutralBehind = 1,
  38. c_ssFriendlyBehind = 2,
  39. c_ssBlocked = 3
  40. };
  41. /*-------------------------------------------------------------------------
  42. * Function: checkModels
  43. *-------------------------------------------------------------------------
  44. * Purpose:
  45. * Check the model list to find anything affecting the status of the shot
  46. * that we would like to fire
  47. */
  48. ShotStatus checkModels(IshipIGC* pShip, ImodelIGC* pTarget, const ModelListIGC* models, const Vector& direction, const float dist2, const float range2)
  49. {
  50. assert(models);
  51. ShotStatus ss = c_ssCleanShot;
  52. IsideIGC* mySide = pShip->GetSide();
  53. // Traverse the object list
  54. for (ModelLinkIGC* mLink = models->first(); mLink != NULL; mLink = mLink->next())
  55. {
  56. ImodelIGC* m = mLink->data();
  57. IsideIGC* side = m->GetSide();
  58. if ((m != pTarget) && (m != pShip) && ((side == NULL) || (side == mySide))) // Then it's something that I don't want to hit
  59. {
  60. // Is it in my line of fire?
  61. Vector dp = m->GetPosition() - pShip->GetPosition();
  62. float dot = dp * direction;
  63. float dp2 = dp.LengthSquared();
  64. // Is it in front of me and in my weapons range??
  65. if (dot >= 0.0f && dp2 < range2)
  66. {
  67. assert((direction.LengthSquared() < 1.05f) && (direction.LengthSquared() > 0.95));
  68. Vector closest = pShip->GetPosition() + direction * dot;
  69. Vector offset = closest - m->GetPosition();
  70. float offsetLength2 = offset.LengthSquared();
  71. float r = m->GetRadius();
  72. if (offsetLength2 < (r * r))
  73. {
  74. if (dp2 > dist2)
  75. ss = (side == NULL) ? c_ssNeutralBehind : c_ssFriendlyBehind;
  76. else {
  77. return c_ssBlocked;
  78. }
  79. }
  80. }
  81. }
  82. }
  83. return ss;
  84. }
  85. /*-------------------------------------------------------------------------
  86. * Function: getShotStatus
  87. *-------------------------------------------------------------------------
  88. * Purpose:
  89. * Send the appropriate model lists into checkmodels to get the status of the
  90. * shot that we would like to fire
  91. */
  92. ShotStatus getShotStatus(IshipIGC* pShip, ImodelIGC* pTarget, const Vector& direction, float range)
  93. {
  94. Vector vShipToTarget = pTarget->GetPosition() - pShip->GetPosition();
  95. float dist2 = vShipToTarget.LengthSquared();
  96. float flRange2 = range * range;
  97. ShotStatus sStatus = c_ssCleanShot;
  98. IclusterIGC* cluster = pTarget->GetCluster();
  99. if (cluster)
  100. {
  101. // Try to check in order of likeliness (and size of the list)
  102. // Check the planets
  103. ShotStatus ss = checkModels(pShip, pTarget, reinterpret_cast<const ModelListIGC*>(cluster->GetAsteroids()), direction, dist2, flRange2);
  104. if (ss == c_ssBlocked) return c_ssBlocked;
  105. if (ss > sStatus) sStatus = ss;
  106. // Check the stations
  107. ss = checkModels(pShip, pTarget, reinterpret_cast<const ModelListIGC*>(cluster->GetStations()), direction, dist2, flRange2);
  108. if (ss == c_ssBlocked) return c_ssBlocked;
  109. if (ss > sStatus) sStatus = ss;
  110. // Check the warps
  111. ss = checkModels(pShip, pTarget, reinterpret_cast<const ModelListIGC*>(cluster->GetWarps()), direction, dist2, flRange2);
  112. if (ss == c_ssBlocked) return c_ssBlocked;
  113. if (ss > sStatus) sStatus = ss;
  114. // Check the ships
  115. ss = checkModels(pShip, pTarget, reinterpret_cast<const ModelListIGC*>(cluster->GetShips()), direction, dist2, flRange2);
  116. if (ss > sStatus) sStatus = ss;
  117. }
  118. return sStatus;
  119. }
  120. // External functions:
  121. /*-------------------------------------------------------------------------
  122. * Function: StopEverything
  123. *-------------------------------------------------------------------------
  124. * Purpose:
  125. * Clear the ship controls
  126. */
  127. bool StopEverything(IshipIGC* pShip, Time lastUpdate)
  128. {
  129. assert(pShip);
  130. pShip->SetStateBits(lastUpdate, weaponsMaskIGC | buttonsMaskIGC, 0); // stop all firing
  131. ControlData controls;
  132. controls.Reset();
  133. pShip->SetControls(controls); // zero the motion bits
  134. return true;
  135. }
  136. /*-------------------------------------------------------------------------
  137. * Function: StrafeAttackTarget
  138. *-------------------------------------------------------------------------
  139. * Purpose:
  140. * To fly straight at the target, guns blazing, and then pull up at the
  141. * last second.
  142. * Notes:
  143. * This never quite panned out. You can look at bug 1191 for information.
  144. * Basically, using the goto function and trying to create a nice path
  145. * for the drones to come in and then pull up was next to impossible.
  146. * They would either get too much momentum towards their target, and then
  147. * not be able to pull up (especially for stations). First, I was hitting
  148. * this in the DoGotoAction:
  149. * if ((offsetLength2 < (r * r)) && (offsetLength2 > 0.1f))
  150. *
  151. * In otherwords, since we couldn't divide by zero, if we were perfectly
  152. * on path with an obstacle, we would just hit it. That meant that I could
  153. * not just GOTO our target and let the dodge code do it's thing. So I
  154. * played with making a nice arc in at the target, and then up. Once again,
  155. * I either got a lot of good shots in, and then couldn't pull up, or I
  156. * would only get one or two shots in if I was pulling up in enough time.
  157. * I think doing it right would mean NOT using the DoGotoAction function,
  158. * and that was more than I felt I should do in the last week. Too dangerous.
  159. */
  160. /*
  161. bool StrafeAttackTarget(IshipIGC* pShip,
  162. ImodelIGC* pTarget,
  163. Time lastUpdate,
  164. float dt,
  165. float shootSkill,
  166. float moveSkill,
  167. float howClose)
  168. {
  169. int buttonsM = 0;
  170. Vector direction = pTarget->GetPosition() - pShip->GetPosition();
  171. IweaponIGC* w = (IweaponIGC*)pShip->GetMountedPart(ET_Weapon, 0);
  172. if (w && !OBJECT_IS_BAD(pTarget))
  173. {
  174. IprojectileTypeIGC* pt = w->GetProjectileType();
  175. float lifespan = pt->GetLifespan();
  176. Vector direction;
  177. Vector myPosition = pShip->GetPosition();
  178. assert (pt);
  179. float tToHit = solveForLead(pShip, pTarget, w, &direction, shootSkill);
  180. Vector destination = (tToHit < lifespan)
  181. ? (direction + pTarget->GetPosition())
  182. : pTarget->GetPosition();
  183. destination += (pShip->GetOrientation().GetUp() * pShip->GetRadius() * 5.0f) / ((destination - myPosition).Length());
  184. // destination += (CrossProduct(pShip->GetOrientation().GetRight(), destination).Normalize() * pShip->GetRadius() * 5.0f) / ((destination - myPosition).Length());
  185. Vector destVel = (destination - myPosition).Normalize() * pShip->GetEffectiveTopSpeed();
  186. // go straight for the ship, let the dodge code take care of any problems.
  187. DoGotoAction(pShip,
  188. lastUpdate,
  189. NULL,
  190. destination,
  191. // destVel,
  192. Vector::GetZero(),
  193. 0.0f,
  194. dt,
  195. moveSkill, false, false, false);
  196. ControlData controls;
  197. controls.Reset();
  198. //just need the angle... todo: replace this with only the necessary calcs, then delete all controls in this func.
  199. float deltaAngle = turnToFace((tToHit < lifespan) ? direction : (pTarget->GetPosition() - pShip->GetPosition()),
  200. dt, pShip, &controls, moveSkill);
  201. //shoot when appropriate
  202. if ((tToHit <= lifespan) && (deltaAngle < pi / 48.0f))
  203. buttonsM = allWeaponsIGC;
  204. if (buttonsM) {
  205. // if I am about to hit anything I don't want to hit,
  206. // then return false
  207. ShotStatus status = getShotStatus(pShip, pTarget, (tToHit < lifespan) ? direction : (pTarget->GetPosition() - pShip->GetPosition()), lifespan * pt->GetSpeed());
  208. if ((status == c_ssBlocked) ||
  209. (status == c_ssFriendlyBehind && (tToHit > shootSkill + 0.1))) // there is something behind him, do I risk it?
  210. {
  211. // not going to try it
  212. buttonsM = 0;
  213. }
  214. }
  215. }
  216. pShip->SetStateBits(lastUpdate, weaponsMaskIGC | buttonsMaskIGC, buttonsM);
  217. // ship controls will be set in the DoGotoAction function
  218. return (buttonsM != 0) ? true : false;
  219. }
  220. */
  221. /*-------------------------------------------------------------------------
  222. * Function: StationaryAttackTarget
  223. *-------------------------------------------------------------------------
  224. * Purpose:
  225. * Don't thrust at all, just rotate your target into position and fire away
  226. */
  227. bool StationaryAttackTarget(IshipIGC* pShip,
  228. Time lastUpdate,
  229. ImodelIGC* pTarget,
  230. float dt,
  231. float shootSkill,
  232. float moveSkill,
  233. bool fCareful) // fCareful: make sure you don't hit friendlies
  234. {
  235. ControlData controls;
  236. controls.Reset();
  237. int buttonsM = 0;
  238. assert(!OBJECT_IS_BAD(pShip));
  239. // Make sure I have a weapon
  240. IweaponIGC* w = (IweaponIGC*)pShip->GetMountedPart(ET_Weapon, 0);
  241. if (w && !OBJECT_IS_BAD(pTarget))
  242. {
  243. IprojectileTypeIGC* pt = w->GetProjectileType();
  244. assert (pt);
  245. float lifespan = pt->GetLifespan();
  246. Vector direction;
  247. float tToHit = solveForLead(pShip, pTarget, w, &direction, shootSkill);
  248. // Pivot to shoot the enemy
  249. float deltaAngle = turnToFace((tToHit < lifespan) ? direction : (pTarget->GetPosition() - pShip->GetPosition()),
  250. dt, pShip, &controls, moveSkill);
  251. // Shoot when appropriate
  252. if ((tToHit <= lifespan) && (deltaAngle < pi / 32.0f))
  253. buttonsM = allWeaponsIGC;
  254. if (fCareful && buttonsM) {
  255. // If I am about to hit anything I don't want to hit, then don't fire
  256. ShotStatus status = getShotStatus(pShip, pTarget, direction, lifespan * pt->GetSpeed());
  257. if ((status == c_ssBlocked) ||
  258. (status == c_ssFriendlyBehind && (tToHit > shootSkill + 0.1))) // There is something behind him, do I risk it?
  259. {
  260. // Not going to try it
  261. buttonsM = 0;
  262. }
  263. }
  264. }
  265. pShip->SetStateBits(lastUpdate, weaponsMaskIGC | buttonsMaskIGC, buttonsM);
  266. pShip->SetControls(controls);
  267. return (buttonsM != 0) ? true : false;
  268. }
  269. /*-------------------------------------------------------------------------
  270. * Function: DoGotoAction
  271. *-------------------------------------------------------------------------
  272. * Purpose:
  273. * This is the most used function in all of the drone code. It takes the
  274. * ship, the target position, and a slew of other parameters, and does three
  275. * things:
  276. * 1) Dodges immediate impacts
  277. * 2) Evaluates a path around huge static obstacles
  278. * 3) Pulls into the desired radius of the target position, or orbits
  279. */
  280. bool DoGotoAction(IshipIGC* pShip,
  281. Time lastUpdate,
  282. ImodelIGC* pTarget,
  283. Vector position,
  284. Vector velocity,
  285. float radius,
  286. float dt,
  287. float skill,
  288. bool bThroughWarps,
  289. bool orbit,
  290. bool dodgeBullets)
  291. {
  292. if (OBJECT_IS_BAD(pShip))
  293. return false;
  294. if (pTarget && pTarget->GetCluster() != pShip->GetCluster()) // Make sure that we are in the right cluster
  295. {
  296. if (!bThroughWarps)
  297. {
  298. StopEverything(pShip, lastUpdate);
  299. return false;
  300. }
  301. IwarpIGC* gotoWarp = FindPath(pShip, pTarget);
  302. pTarget = (ImodelIGC*) gotoWarp;
  303. position = gotoWarp->GetPosition();
  304. velocity = Vector::GetZero();
  305. radius = 0.0f;
  306. }
  307. const Vector& myPosition = pShip->GetPosition();
  308. const Vector& myVelocity = pShip->GetVelocity();
  309. const Orientation& myOrientation = pShip->GetOrientation();
  310. float myRadius = pShip->GetRadius();
  311. bool fCheckTargetForCollision;
  312. if (pTarget)
  313. {
  314. //The only time we do not check for a collision vs. the target is when it is a warp we want
  315. //to go through
  316. switch (pTarget->GetObjectType())
  317. {
  318. case OT_warp:
  319. {
  320. fCheckTargetForCollision = !bThroughWarps;
  321. }
  322. break;
  323. case OT_station:
  324. {
  325. fCheckTargetForCollision = false;
  326. }
  327. break;
  328. default:
  329. fCheckTargetForCollision = true;
  330. }
  331. //However far we want to be from the target, make it the distance from our bounding sphere
  332. radius += myRadius;
  333. }
  334. else
  335. {
  336. //Sorta weird: no target implies we want to get to a position exactly, so worry about "hitting" the point
  337. fCheckTargetForCollision = true;
  338. }
  339. Vector path = position - myPosition;
  340. float distance2 = path.LengthSquared();
  341. float maxSpeed = pShip->GetHullType()->GetMaxSpeed();
  342. float acceleration = pShip->GetHullType()->GetThrust() / pShip->GetMass();
  343. float speed = myVelocity.Length();
  344. float timeToDodge = (speed / (acceleration * pShip->GetHullType()->GetBackMultiplier())); //Worst case time to stop
  345. float distOffOrbit = 0.0f;
  346. //This behavior as 3 parts: avoid hitting stuff, get close to my goal,
  347. //and approach my goal without hitting it.
  348. bool fDiverted = false;
  349. //See if we are about to hit something (anything) or if there is something blocking out path to the goal
  350. ImodelIGC* modelCollide = NULL;
  351. float tCollide = (timeToDodge > 5.0f) ? timeToDodge : 5.0f;
  352. Vector directionCollide;
  353. {
  354. IclusterIGC* cluster = pShip->GetCluster();
  355. assert (cluster);
  356. const ModelListIGC* models = cluster->GetModels();
  357. assert (models);
  358. // There are cases that we DO want to check the target for collisions, like when out destination is in
  359. // respect to the target, but not the center of the target, and when we are going to a warp but not through the warp
  360. for (ModelLinkIGC* l = models->first(); (l != NULL); l = l->next())
  361. {
  362. ImodelIGC* m = l->data();
  363. ObjectType type = m->GetObjectType();
  364. if (m != pShip && (m != pTarget || fCheckTargetForCollision))
  365. {
  366. // Also make sure that we never dodge our own projectiles:
  367. if (type == OT_projectile &&
  368. ( (((IprojectileIGC*)m)->GetLauncher() == pShip) || !dodgeBullets ))
  369. continue;
  370. if (type == OT_missile && ((ImissileIGC*)m)->GetLauncher() == pShip)
  371. continue;
  372. float r = m->GetRadius() + myRadius + 20.0f;
  373. Vector dp = m->GetPosition() - myPosition;
  374. float d2 = dp.LengthSquared();
  375. float t = (d2 > r * r)
  376. ? solveForImpact(dp,
  377. m->GetVelocity()*skill - myVelocity,
  378. 0.0f,
  379. r,
  380. &directionCollide)
  381. : 0.0f;
  382. assert (t >= 0.0f);
  383. // Add some adjustments for skill level
  384. float adj = ((type == OT_projectile) || (type == OT_missile)) ? skill : 1.0f;
  385. if (t < tCollide*adj)
  386. {
  387. modelCollide = m;
  388. tCollide = t;
  389. }
  390. if ((type == OT_asteroid) || (type == OT_station) || (type == OT_ship) || (type == OT_warp))
  391. {
  392. if (orbit)
  393. { // Do we really want to do avoid this thing????
  394. // Don't do this unless we are so far away from our target that we are basically moving right towards it.
  395. }
  396. else
  397. {
  398. // A big non-moving thing ... is it in the way?
  399. float dot = dp * path;
  400. if ((dot >= 0.0f) && (d2 < distance2))
  401. {
  402. // Well ... it's not behind us (looking the way we want to go), and it is closer than where we'd like to go.
  403. Vector closest = myPosition + path * (dot / distance2);
  404. Vector offset = closest - m->GetPosition();
  405. float offsetLength2 = offset.LengthSquared();
  406. if ((offsetLength2 < (r * r)) && (offsetLength2 > 0.1f))
  407. {
  408. position = m->GetPosition() + offset * (r / (float)sqrt(offsetLength2));
  409. velocity = Vector::GetZero();
  410. path = position - myPosition;
  411. distance2 = path.LengthSquared();
  412. radius = 0.0f; //We want to go to this point exactly.
  413. orbit = false;
  414. fDiverted = true;
  415. }
  416. }
  417. }
  418. }
  419. }
  420. }
  421. }
  422. bool fAreWeThereYet = false;
  423. ControlData controls;
  424. controls.jsValues[c_axisYaw] = controls.jsValues[c_axisPitch] = controls.jsValues[c_axisRoll] = 0.0f;
  425. int stateM = 0;
  426. if (modelCollide)
  427. {
  428. // We are going to collide: find our relative positions at the time of collision
  429. // and generate as much of an away vector as possible
  430. const Vector& hisVelocity = modelCollide->GetVelocity();
  431. Vector directionAway = myPosition - modelCollide->GetPosition() +
  432. tCollide * (myVelocity - hisVelocity);
  433. // Dodging along his velocity vector doesn't do much good, so ...
  434. float lhv2 = hisVelocity.LengthSquared();
  435. if (lhv2 > 1.0f) // but, if he's moving slow, it doesn't matter
  436. {
  437. float lda2 = directionAway.LengthSquared();
  438. assert (lda2 != 0.0f); // should be, at least, the sum of the radii
  439. // Remove the component of his velocity from directionAway
  440. float dp = hisVelocity * directionAway;
  441. if (dp * dp > 0.99f * lhv2 * lda2)
  442. {
  443. // 99% (or more) of the away vector is parallel to his velocity vector ...
  444. // pick an arbitrary axis that is not parallel with his velocity
  445. Vector arbitrary(1.0f, 0.0f, 0.0f);
  446. float dot = arbitrary * hisVelocity;
  447. if (dot * dot > 0.99f * lhv2)
  448. {
  449. // Try the y axis as an arbitrary axis
  450. arbitrary.x = 0.0f;
  451. arbitrary.y = 1.0f;
  452. }
  453. // The direction in which to dodge is perpendicular to both his velocity and the arbitrary vector
  454. directionAway = CrossProduct(arbitrary, hisVelocity);
  455. }
  456. else
  457. {
  458. // The direction vector has enough of a perpendicular component to the
  459. // velocity vector to make this worthwhile
  460. // Subtract out the component of directionAway that is parallel to hisVelocity
  461. directionAway -= hisVelocity * (dp / lhv2);
  462. }
  463. }
  464. // Thrust along the away vector
  465. controls.jsValues[c_axisThrottle] = 1.0f;
  466. stateM = getDirection(directionAway, myOrientation);
  467. }
  468. else
  469. {
  470. Vector desiredVelocity;
  471. if (orbit)
  472. {
  473. assert(path.LengthSquared() > 0.0f);
  474. // Make sure that our radius is acceptable
  475. if (pTarget && radius < pTarget->GetRadius() + pShip->GetRadius())
  476. radius = pTarget->GetRadius() + pShip->GetRadius();
  477. // Get the tangent vector
  478. desiredVelocity = CrossProduct(path, pShip->GetVelocity());
  479. if (desiredVelocity.LengthSquared() <= 0.01f)
  480. {
  481. desiredVelocity = CrossProduct(path, pShip->GetOrientation().GetForward());
  482. if (desiredVelocity.LengthSquared() <= 0.01f)
  483. desiredVelocity = pShip->GetOrientation().GetRight();
  484. else
  485. desiredVelocity = CrossProduct(desiredVelocity, path);
  486. }
  487. else
  488. desiredVelocity = CrossProduct(desiredVelocity, path);
  489. // Adjust the tangent vector to smoothly approach the orbit if we are not currently in the orbit
  490. float distance = (float)sqrt(distance2);
  491. distOffOrbit = distance - radius;
  492. float topOrbitSpeed = (distOffOrbit > radius)
  493. ? maxSpeed
  494. : ((distOffOrbit < 0)
  495. ? maxSpeed/2
  496. : (maxSpeed * distance / (2 * radius)));
  497. float vel2= velocity.LengthSquared();
  498. desiredVelocity.SetNormalize();
  499. if (vel2<= 0.0f || vel2> topOrbitSpeed*topOrbitSpeed)
  500. desiredVelocity *= topOrbitSpeed;
  501. else
  502. desiredVelocity *= ((float)sqrt(vel2));
  503. // Spiral towards the perfect orbit
  504. Vector spiral = path.Normalize() * distOffOrbit;
  505. desiredVelocity += spiral;
  506. }
  507. else
  508. {
  509. // We do not have to worry about hitting anything real soon, so concentrate on following our target
  510. Vector direction;
  511. float t = solveForImpact(path,
  512. velocity,
  513. maxSpeed,
  514. radius,
  515. &direction);
  516. // t is the time required to get to the desired distance from our target.
  517. // If we are inside out manuevering envelope, match the targets velocity vector
  518. // otherwise, blend in a combination of the shortest path and the velocity vector
  519. desiredVelocity = velocity;
  520. if ((t <= timeToDodge) && fCheckTargetForCollision && (!fDiverted))
  521. {
  522. //the distance traveled is proportional to the square of the elapsed time,
  523. //so pick a velocity based on the square of the time ratio
  524. //float f = t / timeToDodge;
  525. //desiredVelocity += direction * (speed * f * f);
  526. }
  527. else if (t <= 1.0e10f)
  528. desiredVelocity += direction * maxSpeed;
  529. else
  530. {
  531. // Were not able to find any impact solution,
  532. // so if we are too close (a reason not to find a solution, move apart)
  533. // if we are too far, move closer
  534. float distance = (float)sqrt(distance2);
  535. if (distance < radius)
  536. desiredVelocity -= path * (maxSpeed * (radius - distance) / (radius * distance));
  537. else if (distance > 2.0f * radius)
  538. desiredVelocity += path * (maxSpeed / distance);
  539. }
  540. }
  541. float ldv2 = desiredVelocity.LengthSquared();
  542. if (ldv2 > 1.0f)
  543. {
  544. float deltaAngle = turnToFace(desiredVelocity,
  545. dt, pShip, &controls, skill);
  546. if (deltaAngle < pi * 0.25f)
  547. {
  548. // We are facing along (or close to) our desired velocity vector, set the throttle
  549. // appropriately
  550. controls.jsValues[c_axisThrottle] = (ldv2 < maxSpeed * maxSpeed)
  551. ? 2.0f * ((float)sqrt(ldv2) / maxSpeed - 0.5f)
  552. : 1.0f;
  553. }
  554. else
  555. {
  556. // We are not facing along (or close to) our desired velocity vector,
  557. // use side thrust to get there
  558. controls.jsValues[c_axisThrottle] = 1.0f; //use all of the throttle
  559. stateM = getDirection(desiredVelocity - myVelocity, myOrientation);
  560. }
  561. }
  562. else
  563. {
  564. controls.jsValues[c_axisThrottle] = -1.0f;
  565. fAreWeThereYet = !fDiverted;
  566. }
  567. }
  568. pShip->SetStateBits(lastUpdate, buttonsMaskIGC | weaponsMaskIGC, stateM); // Force all weapon to non-shooting
  569. pShip->SetControls(controls);
  570. if (orbit)
  571. return (distOffOrbit > -5.0f && distOffOrbit < 5.0f);
  572. return fAreWeThereYet;
  573. }