goal.h 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156
  1. #ifndef GOAL_H_
  2. #define GOAL_H_
  3. /*-------------------------------------------------------------------------
  4. * Constant: HowClose
  5. *-------------------------------------------------------------------------
  6. * Purpose:
  7. * How close do I want the GotoGoal to put me to my target.
  8. * Since I didn't want to have every call to GotoGoal have to specify the
  9. * acceptable radius from the target, I overloaded the constructor, and let
  10. * the default value be defined with this constant.
  11. */
  12. const float c_fHowClose = 40.0f; //Leave a lot of slack so things won't bounce on autopilot
  13. /*-------------------------------------------------------------------------
  14. * Constant: HowCloseFollow
  15. *-------------------------------------------------------------------------
  16. * Purpose:
  17. * Probably don't want to follow something as close as I would want to goto
  18. * it, so make that it's own variable
  19. */
  20. const float c_fHowCloseFollow = 25.0f;
  21. // Abstract Goal Types:
  22. /*-------------------------------------------------------------------------
  23. * Abstract Class: Goal
  24. *-------------------------------------------------------------------------
  25. * Purpose:
  26. * This class sets up the interface and framework for all of the goal classes
  27. * and implements default behaviors so that the children don't have to redo code.
  28. */
  29. class Goal
  30. {
  31. public:
  32. Goal(Drone* pDrone, CommandType type) :
  33. m_pDrone(pDrone),
  34. m_pShip(pDrone->GetShip()),
  35. m_tCreated(Time::Now()),
  36. m_tLastUpdate(Time::Now()),
  37. m_ctType(type),
  38. DONE(true)
  39. {};
  40. virtual ~Goal() // Need virtual destructor so that I can call Goal::~Goal for all children, too
  41. {};
  42. virtual void Update(Time now, float dt) // Keep timing, and update CshipIGC targeting info
  43. {
  44. m_tLastUpdate = now;
  45. };
  46. virtual bool Done(void) // Never end
  47. {
  48. return false;
  49. };
  50. virtual void Status(void) = 0; // Just an interface class
  51. virtual void DoneEvent(void) // Default done message
  52. {
  53. m_pDrone->Verbose("Goal Accomplished...");
  54. };
  55. CommandType GetType(void) // Return the type of child this is
  56. {
  57. return m_ctType;
  58. };
  59. virtual ImodelIGC* GetTarget(void) // Some goals do have targets, but assume that we don't
  60. {
  61. return NULL;
  62. };
  63. protected:
  64. void Report(const char* format, ...); // Call Gamesite::DroneSendChat()
  65. Drone* m_pDrone; // Keep track of the drone that is using this goal
  66. IshipIGC* m_pShip; // Can get this from the drone, but we use it all the time
  67. Time m_tCreated; // Keep some timing information
  68. Time m_tLastUpdate;
  69. CommandType m_ctType; // Need to know a which child it is
  70. const bool DONE; // Just mapping true to the name DONE
  71. friend class Drone; // Drone needs to get at this stuff
  72. };
  73. /*-------------------------------------------------------------------------
  74. * Abstract Class: TargetedGoal
  75. *-------------------------------------------------------------------------
  76. * Purpose:
  77. * A majority of the goals need to keep a target. Hold on to that TRef here,
  78. * and handle the basic checks for whether that object is still valid, etc.
  79. */
  80. class TargetedGoal : public Goal
  81. {
  82. public:
  83. TargetedGoal(Drone* pDrone, ImodelIGC* pTarget, CommandType type) :
  84. Goal(pDrone, type),
  85. m_pTarget(pTarget)
  86. {};
  87. virtual bool Done(void) // Done if my object is no longer valid
  88. {
  89. return (OBJECT_IS_BAD(m_pTarget));
  90. };
  91. virtual void DoneEvent(void) // Default targeted goal done message
  92. {
  93. m_pDrone->Verbose("Target is no longer valid");
  94. };
  95. virtual ImodelIGC* GetTarget(void) // Return the real target
  96. {
  97. return m_pTarget;
  98. };
  99. protected:
  100. TRef<ImodelIGC> m_pTarget; // Keep track of a target for the goal
  101. };
  102. // Actual Goal Types
  103. /*-------------------------------------------------------------------------
  104. * Class: IdleGoal
  105. *-------------------------------------------------------------------------
  106. * Purpose:
  107. * Don't do anything but sit still and dodge. This goal never ends.
  108. */
  109. class IdleGoal : public Goal
  110. {
  111. public:
  112. IdleGoal (Drone* pDrone) :
  113. Goal(pDrone, c_ctStop)
  114. {};
  115. virtual void Update(Time now, float dt);
  116. virtual void Status(void)
  117. {
  118. Report("Awaiting orders");
  119. };
  120. };
  121. /*-------------------------------------------------------------------------
  122. * Class: StayPutGoal
  123. *-------------------------------------------------------------------------
  124. * Purpose:
  125. * Don't do anything but sit still and dodge. This goal times out after
  126. * the TIME_LIMIT.
  127. */
  128. class StayPutGoal : public IdleGoal
  129. {
  130. public:
  131. StayPutGoal (Drone* pDrone) :
  132. IdleGoal(pDrone),
  133. TIME_LIMIT(120.0f)
  134. {};
  135. virtual bool Done(void) // Have we hit the time limit yet?
  136. {
  137. float length = m_tLastUpdate - m_tCreated;
  138. return (length >= TIME_LIMIT);
  139. };
  140. virtual void DoneEvent(void) // If it ended, it was because it timed out
  141. {
  142. m_pDrone->Verbose("I'm not going to just sit here forever");
  143. };
  144. protected:
  145. const float TIME_LIMIT; // How long will I just sit there?
  146. };
  147. /*-------------------------------------------------------------------------
  148. * Class: GotoGoal
  149. *-------------------------------------------------------------------------
  150. * Purpose:
  151. * Use the DoGotoAction to get within the specified radius of the target,
  152. * and maybe stop when we get there.
  153. */
  154. class GotoGoal : public TargetedGoal
  155. {
  156. public:
  157. GotoGoal (Drone* pDrone, ImodelIGC* pTarget, bool stopThere = false, bool dodgeBullets = true) :
  158. TargetedGoal(pDrone,pTarget, c_ctGoto),
  159. fGotThere(false),
  160. fStopThere(stopThere),
  161. fDodgeBullets(dodgeBullets)
  162. {
  163. distFromTarget = c_fHowClose + pTarget->GetRadius();
  164. m_dist2 = distFromTarget * distFromTarget;
  165. };
  166. GotoGoal (Drone* pDrone, ImodelIGC* pTarget, float radius, bool stopThere = false, bool dodgeBullets = true) :
  167. TargetedGoal(pDrone,pTarget, c_ctGoto),
  168. fGotThere(false),
  169. distFromTarget(radius - 1.0f), // If we are given a radius, then adjust it to account for the
  170. fStopThere(stopThere), // weirdness of DoGotoAction (considers a goal done if the distance between the
  171. fDodgeBullets(dodgeBullets) // goal and the current pos is less that sqrt(1) )
  172. {
  173. m_dist2 = distFromTarget * distFromTarget;
  174. };
  175. virtual void Update(Time now, float dt);
  176. virtual void Status()
  177. {
  178. Report("Going to %s", GetModelName(m_pTarget));
  179. };
  180. virtual bool Done() // Either the object is bad, or we got there
  181. {
  182. //Hack time ... do a special case for going to a warp: you are there if you are in the same sector as its destination
  183. if (m_pTarget->GetObjectType() == OT_warp)
  184. {
  185. IwarpIGC* pwarpDestination = ((IwarpIGC*)((ImodelIGC*)m_pTarget))->GetDestination();
  186. assert (pwarpDestination);
  187. return m_pShip->GetCluster() == pwarpDestination->GetCluster();
  188. }
  189. return (fGotThere || TargetedGoal::Done()) ;
  190. };
  191. virtual void DoneEvent() // Report a message appropriate to why we finished
  192. {
  193. if (TargetedGoal::Done())
  194. TargetedGoal::DoneEvent();
  195. else
  196. m_pDrone->Verbose("I have reached %s", GetModelName(m_pTarget));
  197. };
  198. private:
  199. float distFromTarget; // Need to figure out the actual range that we want (but only need to do it once)
  200. bool fGotThere; // Set this flag according to DoGotoAction
  201. bool fStopThere; // Do we want to push a stop command when we get there?
  202. bool fDodgeBullets; // Sometimes, we don't want to dodge bullets in the process
  203. float m_dist2; // Only compute distance*distance one time
  204. };
  205. class NewGotoGoal : public TargetedGoal
  206. {
  207. public:
  208. NewGotoGoal (Drone* pDrone,
  209. ImodelIGC* pTarget,
  210. Waypoint::Objective objective = Waypoint::c_oEnter,
  211. float offset = c_fHowClose,
  212. CommandType ct = c_ctGoto)
  213. :
  214. TargetedGoal(pDrone, pTarget, ct),
  215. m_gotoplan(pDrone->GetShip())
  216. {
  217. m_gotoplan.Set(objective, pTarget, offset);
  218. };
  219. virtual void Update(Time now, float dt)
  220. {
  221. if (m_pTarget)
  222. m_gotoplan.Execute(now, dt, true);
  223. }
  224. virtual void Status()
  225. {
  226. Report("Going to %s", GetModelName(m_pTarget));
  227. };
  228. virtual bool Done() // Either the object is bad, or we got there
  229. {
  230. return !m_pTarget; //m_gotoplan.GetMaskWaypoints() == 0;
  231. };
  232. virtual void DoneEvent() // Report a message appropriate to why we finished
  233. {
  234. if (TargetedGoal::Done())
  235. TargetedGoal::DoneEvent();
  236. else
  237. m_pDrone->Verbose("I have reached %s", GetModelName(m_pTarget));
  238. };
  239. void SetGotoPlan(Waypoint::Objective o, ImodelIGC * pmodelTarget, float offset = 0.0f)
  240. {
  241. m_pTarget = pmodelTarget;
  242. m_gotoplan.Set(o, pmodelTarget, offset);
  243. }
  244. protected:
  245. GotoPlan m_gotoplan;
  246. };
  247. /*-------------------------------------------------------------------------
  248. * Class: GotoSameSectorGoal
  249. *-------------------------------------------------------------------------
  250. * Purpose:
  251. * If we aren't in the same sector as the target, then we need to go through
  252. * alephs until we are in the right sector. FindPath should always return the
  253. * correct to go through next.
  254. */
  255. class GotoSameSectorGoal : public GotoGoal
  256. {
  257. public:
  258. GotoSameSectorGoal (Drone *pDrone, ImodelIGC* pTarget, bool dodgeBullets = true) :
  259. GotoGoal(pDrone, FindPath(pDrone->GetShip(), pTarget), 0.0f, false, dodgeBullets),
  260. m_pFinalTarget(pTarget),
  261. m_pCurCluster(pDrone->GetShip()->GetCluster()),
  262. m_pTarCluster(pTarget->GetCluster())
  263. {};
  264. virtual void Update(Time now, float dt) // If the clusters of either of the objects change,
  265. { // then recompute the FindPath
  266. assert (!OBJECT_IS_BAD(m_pTarget) && !OBJECT_IS_BAD(m_pFinalTarget));
  267. if ((m_pShip->GetCluster() != m_pCurCluster) || (m_pFinalTarget->GetCluster() != m_pTarCluster))
  268. {
  269. m_pCurCluster = m_pShip->GetCluster();
  270. m_pTarCluster = m_pFinalTarget->GetCluster();
  271. m_pTarget = FindPath(m_pShip, m_pFinalTarget);
  272. if (Done())
  273. return;
  274. }
  275. GotoGoal::Update(now, dt); // Just goto the aleph
  276. };
  277. virtual bool Done() // If either of the objects is no longer valid,
  278. { // or we have succeeding in getting to the same sector
  279. return (TargetedGoal::Done() || OBJECT_IS_BAD(m_pFinalTarget) || (m_pShip->GetCluster() == m_pFinalTarget->GetCluster()));
  280. };
  281. virtual void DoneEvent() // Announce that we got there
  282. {
  283. if (TargetedGoal::Done())
  284. TargetedGoal::DoneEvent();
  285. else
  286. m_pDrone->Verbose("%s and I are both in %s", GetModelName(m_pFinalTarget), m_pTarCluster->GetName());
  287. };
  288. private:
  289. TRef<ImodelIGC> m_pFinalTarget; // This is the model we're trying to get to
  290. TRef<IclusterIGC> m_pCurCluster; // This is the cluster we are currently in
  291. TRef<IclusterIGC> m_pTarCluster; // This is the cluster that we are trying to get to
  292. };
  293. /*-------------------------------------------------------------------------
  294. * Class: FollowGoal
  295. *-------------------------------------------------------------------------
  296. * Purpose:
  297. * Fly on the wing of the target object. If the target is static, then this
  298. * is just an un-ending goto command
  299. */
  300. class FollowGoal : public TargetedGoal
  301. {
  302. public:
  303. FollowGoal (Drone* pDrone, ImodelIGC* pTarget) :
  304. TargetedGoal(pDrone,pTarget, c_ctFollow)
  305. {};
  306. virtual void Update(Time now, float dt);
  307. virtual void Status(void)
  308. {
  309. Report("Following %s", GetModelName(m_pTarget));
  310. };
  311. };
  312. /*-------------------------------------------------------------------------
  313. * Class: DestroyGoal
  314. *-------------------------------------------------------------------------
  315. * Purpose:
  316. * Attack the target with all of your guns. If you don't have any guns,
  317. * then try to ram it to death
  318. */
  319. class DestroyGoal : public TargetedGoal
  320. {
  321. public:
  322. DestroyGoal (Drone* pDrone, ImodelIGC* pTarget) :
  323. TargetedGoal(pDrone,pTarget, c_ctDestroy),
  324. sCurrent(c_None)
  325. {};
  326. virtual void Update(Time now, float dt);
  327. virtual void Status(void)
  328. {
  329. Report("Attempting to destroy %s", GetModelName(m_pTarget));
  330. };
  331. virtual void DoneEvent(void) // Somehow the object is no longer around
  332. {
  333. m_pDrone->Verbose("%s has been destroyed", GetModelName(m_pTarget));
  334. };
  335. protected:
  336. enum State // Maintian some state information for verbose comments
  337. {
  338. c_Shooting, // Four different "modes"
  339. c_Goto,
  340. c_Ramming,
  341. c_None
  342. };
  343. virtual void SetState(State sNew) // Call this all the time, and only use it if the state changed
  344. {
  345. if (sNew == sCurrent)
  346. return;
  347. sCurrent = sNew;
  348. switch (sNew)
  349. {
  350. case c_Shooting:
  351. m_pDrone->Verbose("I'm in range, and opening fire on %s", GetModelName(m_pTarget));
  352. break;
  353. case c_Goto:
  354. m_pDrone->Verbose("%s is out of range, I'm going after it", GetModelName(m_pTarget));
  355. break;
  356. case c_Ramming:
  357. m_pDrone->Verbose("I don't have any weapons mounted, I'm trying to RAM %s", GetModelName(m_pTarget));
  358. break;
  359. }
  360. };
  361. State sCurrent; // Remember the state
  362. };
  363. /*-------------------------------------------------------------------------
  364. * Class: KillAnythingGoal
  365. *-------------------------------------------------------------------------
  366. * Purpose:
  367. * Look for the closest enemy in the sector, and try to destroy it. If there
  368. * aren't any enemies, then just hang tight, and dodge.
  369. */
  370. class KillAnythingGoal : public Goal
  371. {
  372. public:
  373. KillAnythingGoal(Drone *pDrone) :
  374. Goal(pDrone, c_ctDestroy)
  375. {};
  376. virtual void Update(Time now, float dt);
  377. virtual void Status(void)
  378. {
  379. Report("Looking for enemies");
  380. };
  381. };
  382. /*-------------------------------------------------------------------------
  383. * Class: SameSectorDestroyGoal
  384. *-------------------------------------------------------------------------
  385. * Purpose:
  386. * Same as the DestroyGoal, except we don't actually leave the sector trying
  387. * to kill this guy.
  388. */
  389. class SameSectorDestroyGoal : public DestroyGoal
  390. {
  391. public:
  392. SameSectorDestroyGoal(Drone* pDrone, ImodelIGC* pTarget) :
  393. DestroyGoal(pDrone, pTarget)
  394. {};
  395. virtual bool Done(void) // End if our clusters are not the same
  396. {
  397. return (DestroyGoal::Done() || m_pShip->GetCluster() != m_pTarget->GetCluster());
  398. };
  399. virtual void DoneEvent(void) // Could be that we killed him, or he might have left the sector
  400. {
  401. if (DestroyGoal::Done())
  402. DestroyGoal::DoneEvent();
  403. else
  404. m_pDrone->Verbose("%s has left the sector", GetModelName(m_pTarget));
  405. };
  406. };
  407. /*-------------------------------------------------------------------------
  408. * Class: DisableGoal
  409. *-------------------------------------------------------------------------
  410. * Purpose:
  411. * Same as DestroyGoal, except we stop once we have taken out the target's shields
  412. */
  413. class DisableGoal : public DestroyGoal
  414. {
  415. public:
  416. DisableGoal (Drone* pDrone, ImodelIGC* pTarget) :
  417. DestroyGoal(pDrone, pTarget)
  418. {};
  419. virtual bool Done(void) // Check if the shields have been destroyed
  420. {
  421. switch (m_pTarget->GetObjectType()) // Different ways to get the shields
  422. {
  423. case OT_ship:
  424. {
  425. IshieldIGC* shield = (IshieldIGC*) ((IshipIGC*)m_pTarget.operator->())->GetMountedPart(ET_Shield, 0);
  426. return ((shield == NULL) || (shield->GetFraction() < 0.0f));
  427. }
  428. case OT_station:
  429. {
  430. IstationIGC* pTargetStation = (IstationIGC*) m_pTarget.operator->();
  431. return ( pTargetStation->GetShieldFraction() < 0.0f);
  432. }
  433. default:
  434. return true;
  435. }
  436. };
  437. virtual void Status(void)
  438. {
  439. Report("Attempting to disable %s", GetModelName(m_pTarget));
  440. };
  441. virtual void DoneEvent(void) // Could have died, but hopefully we disabled it
  442. {
  443. if (OBJECT_IS_BAD(m_pTarget))
  444. m_pDrone->Verbose("%s was destroyed while I was attempting to disable it", GetModelName(m_pTarget));
  445. else
  446. m_pDrone->Verbose("%s is disabled", GetModelName(m_pTarget));
  447. };
  448. };
  449. /*-------------------------------------------------------------------------
  450. * Class: DefendingDestroyGoal
  451. *-------------------------------------------------------------------------
  452. * Purpose:
  453. * Try to destroy this guy, but end if you get too far from your defend target,
  454. * or if there are better targets for you to try to get.
  455. */
  456. class DefendingDestroyGoal : public DestroyGoal {
  457. public:
  458. DefendingDestroyGoal (Drone* pDrone, ImodelIGC* pTarget, ImodelIGC* pDefendee, float range) :
  459. DestroyGoal(pDrone,pTarget), m_pDefendee(pDefendee), fRangeSquared(range * range)
  460. {};
  461. virtual bool Done(void)
  462. {
  463. if (DestroyGoal::Done()) // The normal destroy ending conditions still apply
  464. return true;
  465. if (!OBJECT_IS_BAD(m_pDefendee))
  466. { // If my defendee dies, I probably want to go ahead
  467. // and kill the guy
  468. // Otherwise, make sure I'm not too far from home
  469. Vector vFromHome = m_pShip->GetPosition() - m_pDefendee->GetPosition();
  470. return (vFromHome.LengthSquared() > fRangeSquared);
  471. }
  472. // todo: add a check for other possible (more worthy targets here)
  473. return false;
  474. };
  475. virtual void DoneEvent(void)
  476. {
  477. if (OBJECT_IS_BAD(m_pDefendee))
  478. m_pDrone->Verbose("I have failed");
  479. else
  480. m_pDrone->Verbose("%s is no longer a threat to %s", GetModelName(m_pTarget), GetModelName(m_pDefendee));
  481. };
  482. protected:
  483. const TRef<ImodelIGC> m_pDefendee; // Need to remember who I am defending
  484. const float fRangeSquared; // How far can I get from him? (only compute the square once)
  485. };
  486. /*-------------------------------------------------------------------------
  487. * Class: PatrolGoal
  488. *-------------------------------------------------------------------------
  489. * Purpose:
  490. * Fly back and forth from the starting position and the target, attacking
  491. * any enemies that I find on the way
  492. */
  493. class PatrolGoal : public TargetedGoal
  494. {
  495. public:
  496. PatrolGoal(Drone* pDrone, ImodelIGC* pTarget, Vector vSweetSpot) :
  497. TargetedGoal(pDrone, pTarget, c_ctPatrol),
  498. m_vFavoriteSpot(vSweetSpot),
  499. m_bToSecondTarget(false)
  500. {};
  501. PatrolGoal(Drone* pDrone, ImodelIGC* pTarget) :
  502. TargetedGoal(pDrone, pTarget, c_ctPatrol),
  503. m_vFavoriteSpot(pDrone->GetShip()->GetPosition()),
  504. m_bToSecondTarget(false)
  505. {};
  506. virtual void Update(Time now, float dt);
  507. virtual void Status(void)
  508. {
  509. Report("I'm patrolling");
  510. };
  511. protected:
  512. Vector m_vFavoriteSpot; // This is the starting point (one of two targets), the other target is m_pTarget
  513. bool m_bToSecondTarget; // Remember which way I am going right now
  514. };
  515. /*-------------------------------------------------------------------------
  516. * Class: PickupGoal
  517. *-------------------------------------------------------------------------
  518. * Purpose:
  519. * Go pickup this target. Duh. We know that we are done because that object would
  520. * not exist any more.
  521. */
  522. class PickupGoal : public TargetedGoal
  523. {
  524. public:
  525. PickupGoal (Drone* pDrone, ImodelIGC* pTarget) :
  526. TargetedGoal(pDrone,pTarget, c_ctPickup)
  527. {};
  528. virtual void Update(Time now, float dt);
  529. virtual void DoneEvent(void)
  530. {
  531. m_pDrone->Verbose("Got it");
  532. };
  533. virtual void Status(void)
  534. {
  535. Report("Attempting to pick up %s", GetModelName(m_pTarget));
  536. };
  537. };
  538. /*-------------------------------------------------------------------------
  539. * Class: RepairGoal
  540. *-------------------------------------------------------------------------
  541. * Purpose:
  542. * Get to some station to repair myself. Goal satisfied when my hull is
  543. * at full strength. This goal goes with the instincts.
  544. */
  545. class RepairGoal : public NewGotoGoal
  546. {
  547. public:
  548. RepairGoal (Drone* pDrone, ImodelIGC* pStation) :
  549. NewGotoGoal(pDrone,
  550. pStation,
  551. Waypoint::c_oEnter, 0.0f, c_ctRepair)
  552. {};
  553. virtual void Update(Time now, float dt);
  554. virtual void Status(void)
  555. {
  556. Report("Heading to %s to repair myself", GetModelName(m_pTarget));
  557. };
  558. virtual bool Done(void) // My hull has all of it's hitpoints.
  559. {
  560. return (m_pShip->GetFraction() >= 1.0f) &&
  561. (GetAmmoState(m_pShip) != c_asEmpty);
  562. };
  563. virtual void DoneEvent(void)
  564. {
  565. m_pDrone->Verbose("All better");
  566. };
  567. };
  568. /*-------------------------------------------------------------------------
  569. * Class: MaybeRepairGoal
  570. *-------------------------------------------------------------------------
  571. * Purpose:
  572. * Repair, but end if there are any enemies in the sector. Repairing just
  573. * seems like a good thing to do when nobody is around. Right now, this just
  574. * gets called from KillAnythingGoal.
  575. */
  576. class MaybeRepairGoal : public RepairGoal
  577. {
  578. public:
  579. MaybeRepairGoal(Drone *pDrone, IstationIGC* pstation) :
  580. RepairGoal(pDrone, pstation)
  581. {};
  582. virtual bool Done(void) // If we can find any enemy ships, then we're done
  583. {
  584. return (RepairGoal::Done() || FindTarget(m_pShip,
  585. c_ttEnemy | c_ttShip));
  586. };
  587. };
  588. /*-------------------------------------------------------------------------
  589. * Class: CaptureGoal
  590. *-------------------------------------------------------------------------
  591. * Purpose:
  592. * Make the target station have the same side as you. When it is an enemy
  593. * station, that means disabling it, and then docking to claim it.
  594. */
  595. class CaptureGoal : public NewGotoGoal
  596. {
  597. public:
  598. CaptureGoal (Drone *pDrone, ImodelIGC* pStation) :
  599. NewGotoGoal(pDrone, pStation)
  600. {};
  601. virtual void Update(Time now, float dt);
  602. virtual void Status(void)
  603. {
  604. Report("Attempting to capture %s", GetModelName(m_pTarget));
  605. };
  606. virtual bool Done(void) // Done if the station dies, or if it is on our side.
  607. {
  608. return (TargetedGoal::Done() || m_pTarget->GetSide() == m_pShip->GetSide());
  609. };
  610. virtual void DoneEvent(void)
  611. {
  612. if (TargetedGoal::Done())
  613. TargetedGoal::DoneEvent();
  614. else
  615. m_pDrone->Verbose("%s is on our side", GetModelName(m_pTarget));
  616. };
  617. };
  618. /*-------------------------------------------------------------------------
  619. * Class: DefendGoal
  620. *-------------------------------------------------------------------------
  621. * Purpose:
  622. * If the target is static, then I'll orbit it. Dynamic objects, I just follow.
  623. * If any enemies come too close to my defendee, then I try to destroy them.
  624. */
  625. class DefendGoal : public TargetedGoal
  626. {
  627. public:
  628. DefendGoal (Drone* pDrone, ImodelIGC* pTarget) :
  629. TargetedGoal(pDrone,pTarget, c_ctDefend),
  630. fDone(false)
  631. {
  632. if (OBJECT_IS_BAD(m_pTarget))
  633. fDone = true;
  634. };
  635. virtual void Update(Time now, float dt);
  636. virtual bool Done(void)
  637. {
  638. if (fDone) // special message if initial target is not valid
  639. {
  640. m_pDrone->Verbose("Defend target is not valid.");
  641. return true;
  642. }
  643. if (OBJECT_IS_BAD(m_pTarget)) // if we were defending something, and it died,
  644. { // then we could try to defend other stations in our sector
  645. m_pTarget = FindTarget(m_pShip,
  646. c_ttFriendly | c_ttStation | c_ttNearest);
  647. if (!m_pTarget)
  648. {
  649. return true;
  650. }
  651. m_pDrone->Verbose("I have failed, now defending %s", GetModelName(m_pTarget));
  652. }
  653. return false;
  654. };
  655. virtual void Status(void)
  656. {
  657. Report("Defending %s", GetModelName(m_pTarget));
  658. };
  659. private:
  660. bool fDone; // in case of bad initial targets
  661. };
  662. /*-------------------------------------------------------------------------
  663. * Class: ScoutGoal
  664. *-------------------------------------------------------------------------
  665. * Purpose:
  666. * If we are given a target, then start spiraling out from there. If not, spiral
  667. * around 0,0,0. Spiral out and then back in (radii based on Inner and Outer Limit vars)
  668. * Report any enemies in scan range (report each on once). Run away from enemies.
  669. */
  670. class ScoutGoal : public TargetedGoal
  671. {
  672. public:
  673. ScoutGoal (Drone* pDrone, ImodelIGC* pTarget) :
  674. TargetedGoal(pDrone,pTarget, c_ctScout),
  675. m_vmReportedEnemies(0,0),
  676. flRadIncreasePerCycle(2.0f),
  677. sCurrent(c_None),
  678. c_flOuterLimit(5000.0f),
  679. c_flInnerLimit(100.0f),
  680. radius(100.0f)
  681. {
  682. if (!OBJECT_IS_BAD(pTarget))
  683. flRadIncreasePerCycle = 0.0f;
  684. };
  685. ~ScoutGoal() // Clear our reported enemies memory
  686. {
  687. for (int i = m_vmReportedEnemies.GetCount(); i > 0; i--)
  688. {
  689. m_vmReportedEnemies[i-1]->Release();
  690. }
  691. }
  692. virtual void Update(Time now, float dt);
  693. virtual bool Done(void) // Never stop, unless told to
  694. {
  695. return false;
  696. };
  697. virtual void Status(void)
  698. {
  699. if (m_pTarget)
  700. Report("I'm scouting around %s", GetModelName(m_pTarget));
  701. else
  702. Report("I'm scouting %s", m_pShip->GetCluster()->GetName());
  703. State sOld = sCurrent; // print out state message, too
  704. SetState(c_None);
  705. SetState(sOld);
  706. };
  707. protected:
  708. bool Announce(IshipIGC* pObject) // Announce a ship. If we already announced it, then just return
  709. {
  710. // check to see if we have already reported it
  711. if (m_vmReportedEnemies.Find(pObject) != -1)
  712. return false;
  713. // if not, announce it
  714. Report("Reporting: I found %s in %s", pObject->GetName(), m_pShip->GetCluster()->GetName());
  715. // add to the list of things we have reported
  716. pObject->AddRef();
  717. m_vmReportedEnemies.PushEnd(pObject);
  718. return true;
  719. };
  720. private:
  721. float radius; // Current orbital radius
  722. TVector<IshipIGC*, DefaultEquals> m_vmReportedEnemies; // Reported enemy list
  723. float flRadIncreasePerCycle; // Amount that radius changes per cycle
  724. const float c_flOuterLimit; // Outer radius size
  725. const float c_flInnerLimit; // Inner radius size
  726. enum State // Three two states
  727. {
  728. c_Orbitting,
  729. c_Running,
  730. c_None
  731. };
  732. virtual void SetState(State sNew)
  733. {
  734. if (sNew == sCurrent)
  735. return;
  736. sCurrent = sNew;
  737. switch (sNew)
  738. {
  739. case c_Orbitting:
  740. if (m_pTarget)
  741. m_pDrone->Verbose("I'm orbitting %s, currently with radius %d", GetModelName(m_pTarget), (int) radius);
  742. else
  743. m_pDrone->Verbose("I'm scouting %s", m_pShip->GetCluster()->GetName());
  744. break;
  745. case c_Running:
  746. m_pDrone->Verbose("I'm attempting to stay away from enemy ships");
  747. break;
  748. }
  749. };
  750. State sCurrent; // Current state
  751. };
  752. /*-------------------------------------------------------------------------
  753. * Class: DisappearGoal
  754. *-------------------------------------------------------------------------
  755. * Purpose:
  756. * Some of the special characters want to go through an aleph and never come out the
  757. * other side. This is that disappearing trick.
  758. * Notes:
  759. * Rob thinks that it is really bad and incredibly annoying to be chasing a guy,
  760. * almost killing him, into an aleph. Then when you follow him through, he's not
  761. * on the other side. I think that is cool, but he hates it. He was thinking that
  762. * maybe we could only make them "disappear" if they are not being targetted at all.
  763. */
  764. class DisappearGoal : public GotoGoal
  765. {
  766. public:
  767. DisappearGoal(Drone* pDrone) : // Find the closest aleph
  768. GotoGoal(pDrone, FindTarget(pDrone->GetShip(), c_ttNeutral | c_ttWarp | c_ttNearest), 0.0f)
  769. {
  770. pDrone->Disappear(); // Set flag in the drone class
  771. if (!m_pTarget)
  772. pDrone->Die(); // If I couldn't find an aleph, then just self destruct
  773. };
  774. virtual void Status(void)
  775. {
  776. if (m_pDrone->GetDroneType() == c_dtBountyHunter)
  777. {
  778. BountyHunter* pBounty;
  779. CastTo(pBounty, m_pDrone);
  780. // Bounty hunter is ONLY doing this if his mission is accomplished. He repairs at base instead of running away
  781. Report("Mission Accomplished. %s is no more", GetModelName(pBounty->m_pTarget));
  782. }
  783. else // Right now this is just a pirate
  784. {
  785. if (m_pShip->GetFraction() <= (1.0f - m_pDrone->GetBravery())) // Either my leader chickened out, or I did
  786. {
  787. Report("Pirate guild retreating");
  788. }
  789. else // There's no more miners to kill
  790. {
  791. Report("Arggh..Jimlad, There's no bounty to be had, you scurvy nave.");
  792. }
  793. }
  794. };
  795. };
  796. /*-------------------------------------------------------------------------
  797. * Class: MimicGoal
  798. *-------------------------------------------------------------------------
  799. * Purpose:
  800. * This is only for the pirates right now. Basically, it is a hack on the
  801. * normal drone structure. The drone's goal is always to mimic, but the
  802. * mimic goal keeps a goal of it's own, and calls that update every time.
  803. * Basically, he follows the target when the target is moving, and attacks
  804. * what his "leader" or target is attacking, etc.
  805. */
  806. class MimicGoal: public TargetedGoal
  807. {
  808. public:
  809. MimicGoal(Drone *pDrone, Drone* pTarget) :
  810. TargetedGoal(pDrone, pTarget->GetShip(), c_ctMimic),
  811. m_pdTarget(pTarget),
  812. m_pGoal(NULL)
  813. {};
  814. virtual void Update(Time now, float dt);
  815. virtual void Status(void)
  816. {
  817. Report("Following %s, he's our leader", GetModelName(m_pTarget));
  818. };
  819. virtual void DoneEvent(void)
  820. {
  821. m_pDrone->Verbose("%s is gone, time for a new leader", GetModelName(m_pTarget));
  822. };
  823. protected:
  824. void SetGoal(CommandType ctype, ImodelIGC* pTarget)
  825. {
  826. if (m_pGoal && m_pGoal->GetType() == ctype && m_pGoal->GetTarget() == pTarget) // We're already doing it, done
  827. return;
  828. if (ctype == c_ctNoCommand || ctype == c_ctMimic) // Don't want to mimic a mimic (that would be bad)
  829. return;
  830. if (m_pGoal) // It's new, so clear the old goal
  831. {
  832. delete m_pGoal;
  833. m_pGoal = NULL;
  834. }
  835. if (ctype != c_ctDestroy) // Follow him, unless he is killing something
  836. {
  837. ctype = c_ctFollow;
  838. pTarget = m_pTarget;
  839. }
  840. m_pDrone->SetGoal(ctype, pTarget); // Play the goal games
  841. m_pGoal = m_pDrone->GetGoal();
  842. m_pDrone->m_goal = NULL;
  843. m_pDrone->RestoreGoal();
  844. };
  845. Drone * m_pdTarget; // The drone that you are mimicing
  846. Goal * m_pGoal; // The goal you are running to mimic
  847. };
  848. /*-------------------------------------------------------------------------
  849. * Class: FaceGoal
  850. *-------------------------------------------------------------------------
  851. * Purpose:
  852. * We just want to turn to face our target. Meant primarily for automated
  853. * client frame rate testing.
  854. */
  855. class FaceGoal : public TargetedGoal
  856. {
  857. public:
  858. FaceGoal(Drone* pDrone, ImodelIGC* pTarget) :
  859. TargetedGoal(pDrone, pTarget, c_ctFace)
  860. {};
  861. virtual void Update(Time now, float dt);
  862. virtual bool Done(void) // Can't face something in a different cluster
  863. {
  864. return (!m_pTarget || m_pTarget->GetCluster() != m_pShip->GetCluster());
  865. };
  866. virtual void Status(void)
  867. {
  868. Report("Facing %s", GetModelName(m_pTarget));
  869. };
  870. };
  871. /*-------------------------------------------------------------------------
  872. * Class: ConstructGoal
  873. *-------------------------------------------------------------------------
  874. * Purpose:
  875. * We just want to turn to face our target. Meant primarily for automated
  876. * client frame rate testing.
  877. */
  878. class ConstructGoal : public TargetedGoal
  879. {
  880. public:
  881. ConstructGoal(Drone* pDrone,
  882. IstationTypeIGC* pstationtype,
  883. IasteroidIGC* pasteroid)
  884. :
  885. TargetedGoal(pDrone, pasteroid, c_ctConstruct),
  886. m_pstationtype(pstationtype),
  887. m_doneF(false)
  888. {
  889. };
  890. virtual void Update(Time now, float dt);
  891. virtual bool Done(void) // Can't face something in a different cluster
  892. {
  893. return m_doneF && !OBJECT_IS_BAD(m_pTarget);
  894. };
  895. virtual void DoneEvent(void)
  896. {
  897. assert (!OBJECT_IS_BAD(m_pTarget));
  898. m_pDrone->SendChat(m_pstationtype->GetCompletionSound(), "%s completed.", m_pstationtype->GetName());
  899. m_pDrone->GetShip()->GetMission()->GetIgcSite()->BuildStation((IasteroidIGC*)((ImodelIGC*)m_pTarget),
  900. m_pDrone->GetShip()->GetSide(),
  901. m_pstationtype,
  902. m_tLastUpdate);
  903. //Quietly kill the ship (after nuking its parts to prevent treasure from being created)
  904. {
  905. PartLinkIGC* plink;
  906. while (plink = m_pDrone->GetShip()->GetParts()->first()) //Not ==
  907. plink->data()->Terminate();
  908. }
  909. m_pDrone->Die();
  910. };
  911. virtual void Status(void)
  912. {
  913. Report("Building %s", m_pstationtype->GetName());
  914. };
  915. private:
  916. TRef<IstationTypeIGC> m_pstationtype;
  917. bool m_doneF;
  918. };
  919. /*-------------------------------------------------------------------------
  920. * Class: TestGoal
  921. *-------------------------------------------------------------------------
  922. * Purpose:
  923. * This was meant to just cycle through all of the goals possible for that drone,
  924. * but it never got implemented completely. :( Good in theory.
  925. */
  926. class TestGoal : public Goal
  927. {
  928. public:
  929. TestGoal(Drone* pDrone) :
  930. Goal(pDrone, c_ctTest),
  931. cidCurrent(0)
  932. {};
  933. virtual void Update(Time now, float dt);
  934. virtual void Status(void)
  935. {
  936. Report("Testing");
  937. };
  938. virtual bool Done(void) // We tested all of the goals
  939. {
  940. return (cidCurrent >= m_pShip->GetMission()->GetNcommands());
  941. };
  942. virtual void DoneEvent(void)
  943. {
  944. m_pDrone->Verbose("Done with test");
  945. };
  946. private:
  947. CommandID cidCurrent; // Which goal are we on right now
  948. };
  949. #endif