DRIVE.CPP 87 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213
  1. /*
  2. ** Command & Conquer(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /* $Header: F:\projects\c&c\vcs\code\drive.cpv 2.17 16 Oct 1995 16:51:16 JOE_BOSTIC $ */
  19. /***********************************************************************************************
  20. *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
  21. ***********************************************************************************************
  22. * *
  23. * Project Name : Command & Conquer *
  24. * *
  25. * File Name : DRIVE.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : April 22, 1994 *
  30. * *
  31. * Last Update : July 30, 1995 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * DriveClass::AI -- Processes unit movement and rotation. *
  36. * DriveClass::Approach_Target -- Handles approaching the target in order to attack it. *
  37. * DriveClass::Assign_Destination -- Set the unit's NavCom. *
  38. * DriveClass::Class_Of -- Fetches a reference to the class type for this object. *
  39. * DriveClass::Debug_Dump -- Displays status information to monochrome screen. *
  40. * DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction. *
  41. * DriveClass::DriveClass -- Constructor for drive class object. *
  42. * DriveClass::Exit_Map -- Give the unit a movement order to exit the map. *
  43. * DriveClass::Fixup_Path -- Adds smooth start path to normal movement path. *
  44. * DriveClass::Force_Track -- Forces the unit to use the indicated track. *
  45. * DriveClass::Lay_Track -- Handles track laying logic for the unit. *
  46. * DriveClass::Offload_Tiberium_Bail -- Offloads one Tiberium quantum from the object. *
  47. * DriveClass::Ok_To_Move -- Checks to see if this object can begin moving. *
  48. * DriveClass::Overrun_Square -- Handles vehicle overrun of a cell. *
  49. * DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell. *
  50. * DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic. *
  51. * DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell. *
  52. * DriveClass::Tiberium_Load -- Determine the Tiberium load as a percentage. *
  53. * DriveClass::While_Moving -- Processes unit movement. *
  54. * DriveClass::Mark_Track -- Marks the midpoint of the track as occupied. *
  55. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  56. #include "function.h"
  57. DriveClass::DriveClass(void) : Class(0) {};
  58. /***********************************************************************************************
  59. * DriveClass::Do_Turn -- Tries to turn the vehicle to the specified direction. *
  60. * *
  61. * This routine will set the vehicle to rotate to the direction specified. For tracked *
  62. * vehicles, it is just a simple rotation. For wheeled vehicles, it performs a series *
  63. * of short drives (three point turn) to face the desired direction. *
  64. * *
  65. * INPUT: dir -- The direction that this vehicle should face. *
  66. * *
  67. * OUTPUT: none *
  68. * *
  69. * WARNINGS: none *
  70. * *
  71. * HISTORY: *
  72. * 05/29/1995 JLB : Created. *
  73. *=============================================================================================*/
  74. void DriveClass::Do_Turn(DirType dir)
  75. {
  76. if (dir != PrimaryFacing) {
  77. /*
  78. ** Special rotation track is needed for units that
  79. ** cannot rotate in place.
  80. */
  81. if (Special.IsThreePoint && TrackNumber == -1 && Class->Speed == SPEED_WHEEL) {
  82. int facediff; // Signed difference between current and desired facing.
  83. FacingType face; // Current facing (ordinal value).
  84. facediff = PrimaryFacing.Difference(dir) >> 5;
  85. facediff = Bound(facediff, -2, 2);
  86. if (facediff) {
  87. face = Dir_Facing(PrimaryFacing);
  88. IsOnShortTrack = true;
  89. Force_Track(face*FACING_COUNT + (face + facediff), Coord);
  90. Path[0] = FACING_NONE;
  91. Set_Speed(0xFF); // Full speed.
  92. }
  93. } else {
  94. PrimaryFacing.Set_Desired(dir);
  95. if (Special.IsJurassic && AreThingiesEnabled && What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Class->IsPieceOfEight) PrimaryFacing.Set_Current(dir);
  96. }
  97. }
  98. }
  99. /***********************************************************************************************
  100. * DriveClass::Force_Track -- Forces the unit to use the indicated track. *
  101. * *
  102. * This override (nuclear bomb) style routine is to be used when a unit needs to start *
  103. * on a movement track but is outside the normal movement system. This occurs when a *
  104. * harvester starts driving off of a refinery. *
  105. * *
  106. * INPUT: track -- The track number to start on. *
  107. * *
  108. * coord -- The coordinate that the unit will end up at when the movement track *
  109. * is completed. *
  110. * *
  111. * OUTPUT: none *
  112. * *
  113. * WARNINGS: none *
  114. * *
  115. * HISTORY: *
  116. * 03/17/1995 JLB : Created. *
  117. *=============================================================================================*/
  118. void DriveClass::Force_Track(int track, COORDINATE coord)
  119. {
  120. TrackNumber = track;
  121. TrackIndex = 0;
  122. Start_Driver(coord);
  123. }
  124. /***********************************************************************************************
  125. * DriveClass::Tiberium_Load -- Determine the Tiberium load as a percentage. *
  126. * *
  127. * Use this routine to determine what the Tiberium load is (as a fixed point percentage). *
  128. * *
  129. * INPUT: none *
  130. * *
  131. * OUTPUT: Returns with the current "fullness" rating for the object. This will be 0x0000 for *
  132. * empty and 0x0100 for full. *
  133. * *
  134. * WARNINGS: none *
  135. * *
  136. * HISTORY: *
  137. * 03/17/1995 JLB : Created. *
  138. *=============================================================================================*/
  139. int DriveClass::Tiberium_Load(void) const
  140. {
  141. if (*this == UNIT_HARVESTER) {
  142. return(Cardinal_To_Fixed(UnitTypeClass::STEP_COUNT, Tiberium));
  143. }
  144. return(0x0000);
  145. }
  146. /***********************************************************************************************
  147. * DriveClass::Approach_Target -- Handles approaching the target in order to attack it. *
  148. * *
  149. * This routine will check to see if the target is infantry and it can be overrun. It will *
  150. * try to overrun the infantry rather than attack it. This only applies to computer *
  151. * controlled vehicles. If it isn't the infantry overrun case, then it falls into the *
  152. * base class for normal (complex) approach algorithm. *
  153. * *
  154. * INPUT: none *
  155. * *
  156. * OUTPUT: none *
  157. * *
  158. * WARNINGS: none *
  159. * *
  160. * HISTORY: *
  161. * 03/17/1995 JLB : Created. *
  162. * 07/12/1995 JLB : Flamethrower tanks don't overrun -- their weapon is better. *
  163. *=============================================================================================*/
  164. void DriveClass::Approach_Target(void)
  165. {
  166. /*
  167. ** Only if there is a legal target should the approach check occur.
  168. */
  169. if (!House->IsHuman && Target_Legal(TarCom) && !Target_Legal(NavCom)) {
  170. /*
  171. ** Special case:
  172. ** If this is for a unit that can crush infantry, and the target is
  173. ** infantry, AND the infantry is pretty darn close, then just try
  174. ** to drive over the infantry instead of firing on it.
  175. */
  176. TechnoClass * target = As_Techno(TarCom);
  177. if (Class->Primary != WEAPON_FLAME_TONGUE && Class->IsCrusher && Distance(TarCom) < 0x0180 && target && ((TechnoTypeClass const &)(target->Class_Of())).IsCrushable) {
  178. Assign_Destination(TarCom);
  179. return;
  180. }
  181. }
  182. /*
  183. ** In the other cases, uses the more complex "get to just within weapon range"
  184. ** algorithm.
  185. */
  186. FootClass::Approach_Target();
  187. }
  188. /***********************************************************************************************
  189. * DriveClass::Overrun_Square -- Handles vehicle overrun of a cell. *
  190. * *
  191. * This routine is called when a vehicle enters a square or when it is about to enter a *
  192. * square (controlled by parameter). When a vehicle that can crush infantry enters a *
  193. * cell that contains infantry, then the infantry will be destroyed (regardless of *
  194. * affiliation). When a vehicle threatens to overrun a square, all occupying infantry *
  195. * will attempt to get out of the way. *
  196. * *
  197. * INPUT: cell -- The cell that is, or soon will be, entered by a vehicle. *
  198. * *
  199. * threaten -- Don't kill, but just threaten to enter the cell. *
  200. * *
  201. * OUTPUT: none *
  202. * *
  203. * WARNINGS: none *
  204. * *
  205. * HISTORY: *
  206. * 01/19/1995 JLB : Created. *
  207. *=============================================================================================*/
  208. void DriveClass::Overrun_Square(CELL cell, bool threaten)
  209. {
  210. CellClass * cellptr = &Map[cell];
  211. if (Class->IsCrusher) {
  212. if (threaten) {
  213. /*
  214. ** If the cell contains infantry, then they will panic when a vehicle tries
  215. ** drive over them. Have the infantry run away instead.
  216. */
  217. if (cellptr->Flag.Composite & 0x1F) {
  218. /*
  219. ** Scattering is controlled by the game difficulty level.
  220. */
  221. if ((Special.IsDifficult || Special.IsScatter || Scenario > 8) && !Special.IsEasy) {
  222. cellptr->Incoming(0, true);
  223. }
  224. }
  225. } else {
  226. ObjectClass * object = cellptr->Cell_Occupier();
  227. int crushed = false;
  228. while (object) {
  229. if (object->Class_Of().IsCrushable && !House->Is_Ally(object) && Distance(object->Center_Coord()) < 0x80) {
  230. ObjectClass * next = object->Next;
  231. crushed = true;
  232. /*
  233. ** Record credit for the kill(s)
  234. */
  235. Sound_Effect(VOC_SQUISH2, Coord);
  236. object->Record_The_Kill(this);
  237. object->Mark(MARK_UP);
  238. object->Limbo();
  239. delete object;
  240. new OverlayClass(OVERLAY_SQUISH, Coord_Cell(Coord));
  241. object = next;
  242. } else {
  243. object = object->Next;
  244. }
  245. }
  246. if (crushed) Do_Uncloak();
  247. }
  248. }
  249. }
  250. /***********************************************************************************************
  251. * DriveClass::DriveClass -- Constructor for drive class object. *
  252. * *
  253. * This will initialize the drive class to its default state. It is called as a result *
  254. * of creating a unit. *
  255. * *
  256. * INPUT: classid -- The unit's ID class. It is passed on to the foot class constructor. *
  257. * *
  258. * OUTPUT: none *
  259. * *
  260. * WARNINGS: none *
  261. * *
  262. * HISTORY: *
  263. * 07/13/1994 JLB : Created. *
  264. *=============================================================================================*/
  265. DriveClass::DriveClass(UnitType classid, HousesType house) :
  266. Class(&UnitTypeClass::As_Reference(classid)),
  267. FootClass(house)
  268. {
  269. /*
  270. ** For two shooters, clear out the second shot flag -- it will be set the first time
  271. ** the object fires. For non two shooters, set the flag since it will never be cleared
  272. ** and the second shot flag tells the system that normal rearm times apply -- this is
  273. ** what is desired for non two shooters.
  274. */
  275. if (Class->IsTwoShooter) {
  276. IsSecondShot = false;
  277. } else {
  278. IsSecondShot = true;
  279. }
  280. IsHarvesting = false;
  281. IsTurretLockedDown = false;
  282. IsOnShortTrack = false;
  283. IsReturning = false;
  284. TrackNumber = -1;
  285. TrackIndex = 0;
  286. SpeedAccum = 0;
  287. Tiberium = 0;
  288. Strength = Class->MaxStrength;
  289. }
  290. #ifdef CHEAT_KEYS
  291. /***********************************************************************************************
  292. * DriveClass::Debug_Dump -- Displays status information to monochrome screen. *
  293. * *
  294. * This debug utility function will display the status of the drive class to the mono *
  295. * screen. It is through this information that bugs can be tracked down. *
  296. * *
  297. * INPUT: none *
  298. * *
  299. * OUTPUT: none *
  300. * *
  301. * WARNINGS: none *
  302. * *
  303. * HISTORY: *
  304. * 05/31/1994 JLB : Created. *
  305. *=============================================================================================*/
  306. void DriveClass::Debug_Dump(MonoClass *mono) const
  307. {
  308. mono->Set_Cursor(33, 7);
  309. mono->Printf("%2d:%2d", TrackNumber, TrackIndex);
  310. mono->Text_Print("X", 16 + (IsTurretLockedDown?2:0), 10);
  311. // mono->Text_Print("X", 16 + (IsOnShortTrack?2:0), 11);
  312. mono->Set_Cursor(41, 7);mono->Printf("%d", Fixed_To_Cardinal(100, Tiberium_Load()));
  313. FootClass::Debug_Dump(mono);
  314. }
  315. #endif
  316. /***********************************************************************************************
  317. * DriveClass::Exit_Map -- Give the unit a movement order to exit the map. *
  318. * *
  319. * This routine is used to assign an appropriate movement destination for the unit so that *
  320. * it will leave the map. The scripts are usually the one to call this routine when it *
  321. * is determined that the unit has fulfilled its mission and must "depart". *
  322. * *
  323. * INPUT: none *
  324. * *
  325. * OUTPUT: none *
  326. * *
  327. * WARNINGS: none *
  328. * *
  329. * HISTORY: *
  330. * 05/31/1994 JLB : Created. *
  331. *=============================================================================================*/
  332. void DriveClass::Exit_Map(void)
  333. {
  334. CELL cell; // Map exit cell number.
  335. if (*this == UNIT_HOVER && !Target_Legal(NavCom)) {
  336. /*
  337. ** Scan a swath of cells from current position to the edge of the map and if
  338. ** there is any blocking object, just wait so to try again later.
  339. */
  340. Mark(MARK_UP);
  341. for (int x = Cell_X(Coord_Cell(Center_Coord()))-1; x <= Cell_X(Coord_Cell(Center_Coord()))+1; x++) {
  342. for (int y = Cell_Y(Coord_Cell(Center_Coord()))+1; y < Map.MapCellY+Map.MapCellHeight; y++) {
  343. cell = XY_Cell(x, y);
  344. if (Map[cell].Cell_Techno()) {
  345. Mark(MARK_DOWN);
  346. return;
  347. }
  348. }
  349. }
  350. Mark(MARK_DOWN);
  351. /*
  352. ** A clear path to the map edge exists. Assign it as the navigation computer
  353. ** destination and let the transport move.
  354. */
  355. cell = XY_Cell(Cell_X(Coord_Cell(Coord)), Map.MapCellY+Map.MapCellHeight);
  356. IsReturning = true;
  357. Assign_Destination(::As_Target(cell));
  358. }
  359. }
  360. /***********************************************************************************************
  361. * DriveClass::Smooth_Turn -- Handles the low level coord calc for smooth turn logic. *
  362. * *
  363. * This routine calculates the new coordinate value needed for the *
  364. * smooth turn logic. The adjustment and flag values must be *
  365. * determined prior to entering this routine. *
  366. * *
  367. * INPUT: adj -- The adjustment coordinate as lifted from the *
  368. * correct smooth turn table. *
  369. * *
  370. * dir -- Pointer to dir for possible modification *
  371. * according to the flag bits. *
  372. * *
  373. * OUTPUT: Returns with the coordinate the unit should positioned to. *
  374. * *
  375. * WARNINGS: none *
  376. * *
  377. * HISTORY: *
  378. * 03/14/1994 JLB : Created. *
  379. * 07/13/1994 JLB : Converted to member function. *
  380. *=============================================================================================*/
  381. COORDINATE DriveClass::Smooth_Turn(COORDINATE adj, DirType *dir)
  382. {
  383. DirType workdir = *dir;
  384. int x,y;
  385. int temp;
  386. TrackControlType flags = TrackControl[TrackNumber].Flag;
  387. x = Coord_X(adj);
  388. y = Coord_Y(adj);
  389. if (flags & F_T) {
  390. temp = x;
  391. x = y;
  392. y = temp;
  393. workdir = (DirType)(DIR_W - workdir);
  394. }
  395. if (flags & F_X) {
  396. x = -x;
  397. workdir = (DirType)-workdir;
  398. }
  399. if (flags & F_Y) {
  400. y = -y;
  401. workdir = (DirType)(DIR_S - workdir);
  402. }
  403. *dir = workdir;
  404. return(XY_Coord( Coord_X(Head_To_Coord()) + x, Coord_Y(Head_To_Coord()) + y));
  405. }
  406. /***********************************************************************************************
  407. * DriveClass::Assign_Destination -- Set the unit's NavCom. *
  408. * *
  409. * This routine is used to set the unit's navigation computer to the *
  410. * specified target. Once the navigation computer is set, the unit *
  411. * will start planning and moving toward the destination. *
  412. * *
  413. * INPUT: target -- The destination target for the unit to head to. *
  414. * *
  415. * OUTPUT: none *
  416. * *
  417. * WARNINGS: none *
  418. * *
  419. * HISTORY: *
  420. * 09/07/1992 JLB : Created. *
  421. * 04/15/1994 JLB : Converted to member function. *
  422. *=============================================================================================*/
  423. void DriveClass::Assign_Destination(TARGET target)
  424. {
  425. /*
  426. ** Abort early if there is anything wrong with the parameters
  427. ** or the unit already is assigned the specified destination.
  428. */
  429. if (target == NavCom) return;
  430. #ifdef NEVER
  431. UnitClass *tunit; // Destination unit pointer.
  432. /*
  433. ** When in move mode, a map position may really indicate
  434. ** a unit to guard.
  435. */
  436. if (Is_Target_Cell(target)) {
  437. cell = As_Cell(target);
  438. tunit = Map[cell].Cell_Unit();
  439. if (tunit) {
  440. /*
  441. ** Prevent targeting of itself.
  442. */
  443. if (tunit != this) {
  444. target = tunit->As_Target();
  445. }
  446. } else {
  447. tbuilding = Map[cell].Cell_Building();
  448. if (tbuilding) {
  449. target = tbuilding->As_Target();
  450. }
  451. }
  452. }
  453. #endif
  454. /*
  455. ** For harvesting type vehicles, it might go into a dock and unload procedure
  456. ** when the harvester is full and an empty refinery is selected as a target.
  457. */
  458. BuildingClass * b = As_Building(target);
  459. /*
  460. ** Transport vehicles must tell all passengers that are about to load, that they
  461. ** cannot proceed. This is accomplished with a radio message to this effect.
  462. */
  463. //if (tunit && In_Radio_Contact() && Class->IsTransporter && Contact_With_Whom()->Is_Infantry()) {
  464. if (In_Radio_Contact() && Class->IsTransporter && Contact_With_Whom()->Is_Infantry()) {
  465. Transmit_Message(RADIO_OVER_OUT);
  466. }
  467. /*
  468. ** If the player clicked on a friendly repair facility and the repair
  469. ** facility is currently not involved with some other unit (radio or unloading).
  470. */
  471. if (b && *b == STRUCT_REPAIR) {
  472. if (b->In_Radio_Contact()) {
  473. target = 0;
  474. } else {
  475. /*
  476. ** Establish radio contact protocol. If the facility responds correctly,
  477. ** then remain in radio contact and proceed toward the desired destination.
  478. */
  479. if (Transmit_Message(RADIO_HELLO, b) == RADIO_ROGER) {
  480. /*
  481. ** Last check to make sure that the loading square is free from permanent
  482. ** occupation (such as a building).
  483. */
  484. CELL cell = Coord_Cell(b->Center_Coord()) + (MAP_CELL_W-1);
  485. if (Ground[Map[cell].Land_Type()].Cost[Class->Speed] ) {
  486. if (Transmit_Message(RADIO_DOCKING) == RADIO_ROGER) {
  487. FootClass::Assign_Destination(target);
  488. Path[0] = FACING_NONE;
  489. return;
  490. }
  491. /*
  492. ** Failure to establish a docking relationship with the refinery.
  493. ** Bail & await further instructions.
  494. */
  495. Transmit_Message(RADIO_OVER_OUT);
  496. }
  497. }
  498. }
  499. }
  500. /*
  501. ** Set the unit's navigation computer.
  502. */
  503. FootClass::Assign_Destination(target);
  504. Path[0] = FACING_NONE; // Force recalculation of path.
  505. if (!IsDriving) {
  506. Start_Of_Move();
  507. }
  508. }
  509. /***********************************************************************************************
  510. * DriveClass::While_Moving -- Processes unit movement. *
  511. * *
  512. * This routine is used to process movement for the units as they move. *
  513. * It is called many times for each cell's worth of movement. This *
  514. * routine only applies after the next cell HeadTo has been determined. *
  515. * *
  516. * INPUT: none *
  517. * *
  518. * OUTPUT: true/false; Should this routine be called again? *
  519. * *
  520. * WARNINGS: none *
  521. * *
  522. * HISTORY: *
  523. * 02/02/1992 JLB : Created. *
  524. * 04/15/1994 JLB : Converted to member function. *
  525. *=============================================================================================*/
  526. bool DriveClass::While_Moving(void)
  527. {
  528. int actual; // Working movement addition value.
  529. /*
  530. ** Perform quick legality checks.
  531. */
  532. if (!IsDriving || TrackNumber == -1 || (IsRotating && !Class->IsTurretEquipped)) {
  533. SpeedAccum = 0; // Kludge? No speed should accumulate if movement is on hold.
  534. return(false);
  535. }
  536. /*
  537. ** If enough movement has accumulated so that the unit can
  538. ** visibly move on the map, then process accordingly.
  539. ** Slow the unit down if he's carrying a flag.
  540. */
  541. if (((UnitClass *)this)->Flagged != HOUSE_NONE) {
  542. actual = SpeedAccum + Fixed_To_Cardinal(Class->MaxSpeed/2, Speed);
  543. } else {
  544. actual = SpeedAccum + Fixed_To_Cardinal(Class->MaxSpeed, Speed);
  545. }
  546. if (actual > PIXEL_LEPTON_W) {
  547. TurnTrackType const *track; // Track control pointer.
  548. TrackType const *ptr; // Pointer to coord offset values.
  549. int tracknum; // The track number being processed.
  550. FacingType nextface; // Next facing queued in path.
  551. bool adj; // Is a turn coming up?
  552. track = &TrackControl[TrackNumber];
  553. if (IsOnShortTrack) {
  554. tracknum = track->StartTrack;
  555. } else {
  556. tracknum = track->Track;
  557. }
  558. ptr = RawTracks[tracknum-1].Track;
  559. nextface = Path[0];
  560. /*
  561. ** Determine if there is a turn coming up. If there is
  562. ** a turn, then track jumping might occur.
  563. */
  564. adj = false;
  565. if (nextface != FACING_NONE && Dir_Facing(track->Facing) != nextface) {
  566. adj = true;
  567. }
  568. /*
  569. ** Skip ahead the number of track steps required (limited only
  570. ** by track length). Set the unit to the new position and
  571. ** flag the unit accordingly.
  572. */
  573. Mark(MARK_UP);
  574. while (actual > PIXEL_LEPTON_W) {
  575. COORDINATE offset;
  576. DirType dir;
  577. actual -= PIXEL_LEPTON_W;
  578. offset = ptr[TrackIndex].Offset;
  579. if (offset || !TrackIndex) {
  580. dir = ptr[TrackIndex].Facing;
  581. Coord = Smooth_Turn(offset, &dir);
  582. PrimaryFacing.Set(dir);
  583. /*
  584. ** See if "per cell" processing is necessary.
  585. */
  586. if (TrackIndex && RawTracks[tracknum-1].Cell == TrackIndex) {
  587. Per_Cell_Process(false);
  588. if (!IsActive) {
  589. return(false);
  590. }
  591. }
  592. /*
  593. ** The unit could "jump tracks". Check to see if the unit should
  594. ** do so.
  595. */
  596. if (*this != UNIT_GUNBOAT && nextface != FACING_NONE && adj && RawTracks[tracknum-1].Jump == TrackIndex && TrackIndex) {
  597. TurnTrackType const *newtrack; // Proposed jump-to track.
  598. int tnum;
  599. tnum = Dir_Facing(track->Facing)*FACING_COUNT + nextface;
  600. newtrack = &TrackControl[tnum];
  601. if (newtrack->Track && RawTracks[newtrack->Track-1].Entry) {
  602. COORDINATE c = Head_To_Coord();
  603. int oldspeed = Speed;
  604. c = Adjacent_Cell(c, nextface);
  605. switch(Can_Enter_Cell(Coord_Cell(c), nextface)) {
  606. case MOVE_OK:
  607. IsOnShortTrack = false; // Shouldn't be necessary, but...
  608. TrackNumber = tnum;
  609. track = newtrack;
  610. // Mono_Printf("**Jumping from track %d to track %d. **\n", tracknum, track->Track);Keyboard::Get();
  611. tracknum = track->Track;
  612. TrackIndex = RawTracks[tracknum-1].Entry-1; // Anticipate increment.
  613. ptr = RawTracks[tracknum-1].Track;
  614. adj = false;
  615. Stop_Driver();
  616. Per_Cell_Process(true);
  617. if (Start_Driver(c)) {
  618. Set_Speed(oldspeed);
  619. memcpy(&Path[0], &Path[1], CONQUER_PATH_MAX-1);
  620. Path[CONQUER_PATH_MAX-1] = FACING_NONE;
  621. } else {
  622. Path[0] = FACING_NONE;
  623. TrackNumber = -1;
  624. actual = 0;
  625. }
  626. break;
  627. case MOVE_CLOAK:
  628. Map[Coord_Cell(c)].Shimmer();
  629. break;
  630. case MOVE_TEMP:
  631. if (*this == UNIT_HARVESTER || !House->IsHuman) {
  632. bool old = Special.IsScatter;
  633. Special.IsScatter = true;
  634. Map[Coord_Cell(c)].Incoming(0, true);
  635. Special.IsScatter = old;
  636. }
  637. break;
  638. }
  639. }
  640. }
  641. TrackIndex++;
  642. } else {
  643. actual = 0;
  644. Coord = Head_To_Coord();
  645. Stop_Driver();
  646. TrackNumber = -1;
  647. TrackIndex = NULL;
  648. /*
  649. ** Perform "per cell" activities.
  650. */
  651. Per_Cell_Process(true);
  652. break;
  653. }
  654. }
  655. if (IsActive) {
  656. Mark(MARK_DOWN);
  657. }
  658. }
  659. /*
  660. ** Replace any remainder back into the unit's movement
  661. ** accumulator to be processed next pass.
  662. */
  663. SpeedAccum = actual;
  664. return(true);
  665. }
  666. /***********************************************************************************************
  667. * DriveClass::Per_Cell_Process -- Handles when unit finishes movement into a cell. *
  668. * *
  669. * This routine is called when a unit has mostly or completely *
  670. * entered a cell. The unit might be in the middle of a movement track *
  671. * when this routine is called. It's primary purpose is to perform *
  672. * sighting and other "per cell" activities. *
  673. * *
  674. * INPUT: center -- Is the unit safely at the center of a cell? If it is merely "close" *
  675. * to the center, then this parameter will be false. *
  676. * *
  677. * OUTPUT: none *
  678. * *
  679. * WARNINGS: none *
  680. * *
  681. * HISTORY: *
  682. * 11/03/1993 JLB : Created. *
  683. * 03/30/1994 JLB : Revamped for track system. *
  684. * 04/15/1994 JLB : Converted to member function. *
  685. * 06/18/1994 JLB : Converted to virtual function. *
  686. * 06/18/1994 JLB : Distinguishes between center and near-center conditions. *
  687. *=============================================================================================*/
  688. void DriveClass::Per_Cell_Process(bool center)
  689. {
  690. CELL cell = Coord_Cell(Coord);
  691. /*
  692. ** Check to see if it has reached its destination. If so, then clear the NavCom
  693. ** regardless of the remaining path list.
  694. */
  695. if (center && As_Cell(NavCom) == cell) {
  696. IsTurretLockedDown = false;
  697. NavCom = TARGET_NONE;
  698. Path[0] = FACING_NONE;
  699. }
  700. #ifdef NEVER
  701. /*
  702. ** A "lemon" vehicle will have a tendency to break down as
  703. ** it moves about the terrain.
  704. */
  705. if (Is_A_Lemon) {
  706. if (Random_Pick(1, 4) == 1) {
  707. Take_Damage(1);
  708. }
  709. }
  710. #endif
  711. Lay_Track();
  712. FootClass::Per_Cell_Process(center);
  713. }
  714. /***********************************************************************************************
  715. * DriveClass::Start_Of_Move -- Tries to get a unit to advance toward cell. *
  716. * *
  717. * This will try to start a unit advancing toward the cell it is *
  718. * facing. It will check for and handle legality and reserving of the *
  719. * necessary cell. *
  720. * *
  721. * INPUT: none *
  722. * *
  723. * OUTPUT: true/false; Should this routine be called again because *
  724. * initial start operation is temporarily delayed? *
  725. * *
  726. * WARNINGS: none *
  727. * *
  728. * HISTORY: *
  729. * 02/02/1992 JLB : Created. *
  730. * 10/18/1993 JLB : This should be called repeatedly until HeadTo is not NULL. *
  731. * 03/16/1994 JLB : Revamped for track logic. *
  732. * 04/15/1994 JLB : Converted to member function. *
  733. * 06/19/1995 JLB : Fixed so that it won't fire on ground unnecessarily. *
  734. * 07/13/1995 JLB : Handles bumping into cloaked objects. *
  735. *=============================================================================================*/
  736. bool DriveClass::Start_Of_Move(void)
  737. {
  738. FacingType facing; // Direction movement will commence.
  739. DirType dir; // Desired actual facing toward destination.
  740. int facediff; // Difference between current and desired facing.
  741. int speed; // Speed of unit.
  742. CELL destcell; // Cell of destination.
  743. LandType ground; // Ground unit is entering.
  744. COORDINATE dest; // Destination coordinate.
  745. facing = Path[0];
  746. if (!Target_Legal(NavCom) && facing == FACING_NONE) {
  747. IsTurretLockedDown = false;
  748. Stop_Driver();
  749. if (Mission == MISSION_MOVE) {
  750. Enter_Idle_Mode();
  751. }
  752. return(false); // Why is it calling this routine!?!
  753. }
  754. #ifdef NEVER
  755. /*
  756. ** Movement start logic can't begin until a unit that requires
  757. ** a locked down turret gets to a locked down state (i.e., the
  758. ** turret rotation stops.
  759. */
  760. if (ClassF & CLASSF_LOCKTURRET) {
  761. Set_Secondary_Facing(facing<<5);
  762. if (Is_Rotating) {
  763. return(true);
  764. }
  765. }
  766. #endif
  767. /*
  768. ** Reduce the path length if the target is a unit and the
  769. ** range to the unit is less than the precalculated path steps.
  770. */
  771. if (facing != FACING_NONE) {
  772. int dist;
  773. if (Is_Target_Unit(NavCom) || Is_Target_Infantry(NavCom)) {
  774. dist = Lepton_To_Cell(Distance(NavCom));
  775. // if (dist > CELL_LEPTON_W ||
  776. // !As_Techno(NavCom)->Techno_Type_Class()->IsCrushable ||
  777. // !Class->IsCrusher) {
  778. if (dist < CONQUER_PATH_MAX) {
  779. Path[dist] = FACING_NONE;
  780. facing = Path[0]; // Maybe needed.
  781. }
  782. // }
  783. }
  784. }
  785. /*
  786. ** If the path is invalid at this point, then generate one. If
  787. ** generating a new path fails, then abort NavCom.
  788. */
  789. if (facing == FACING_NONE) {
  790. /*
  791. ** If after a path search, there is still no valid path, then set the
  792. ** NavCom to null and let the script take care of assigning a new
  793. ** navigation target.
  794. */
  795. if (!PathDelay.Expired()) {
  796. return(false);
  797. }
  798. if (!Basic_Path()) {
  799. if (Distance(NavCom) < 0x0280 && (Mission == MISSION_MOVE || Mission == MISSION_GUARD_AREA)) {
  800. Assign_Destination(TARGET_NONE);
  801. } else {
  802. /*
  803. ** If a basic path could be found, but the immediate move destination is
  804. ** blocked by a friendly temporary blockage, then cause that blockage
  805. ** to scatter.
  806. */
  807. CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), PrimaryFacing.Current());
  808. if (Map.In_Radar(cell)) {
  809. if (Can_Enter_Cell(cell) == MOVE_TEMP) {
  810. CellClass * cellptr = &Map[cell];
  811. TechnoClass * blockage = cellptr->Cell_Techno();
  812. if (blockage && House->Is_Ally(blockage)) {
  813. bool old = Special.IsScatter;
  814. Special.IsScatter = true;
  815. cellptr->Incoming(0, true);
  816. Special.IsScatter = old;
  817. }
  818. }
  819. }
  820. if (TryTryAgain) {
  821. TryTryAgain--;
  822. } else {
  823. Assign_Destination(TARGET_NONE);
  824. if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
  825. IsNewNavCom = false;
  826. }
  827. }
  828. Stop_Driver();
  829. TrackNumber = -1;
  830. IsTurretLockedDown = false;
  831. return(false);
  832. }
  833. /*
  834. ** If a basic path could be found, but the immediate move destination is
  835. ** blocked by a friendly temporary blockage, then cause that blockage
  836. ** to scatter.
  837. */
  838. CELL cell = Adjacent_Cell(Coord_Cell(Center_Coord()), Path[0]);
  839. if (Map.In_Radar(cell)) {
  840. if (Can_Enter_Cell(cell) == MOVE_TEMP) {
  841. CellClass * cellptr = &Map[cell];
  842. TechnoClass * blockage = cellptr->Cell_Techno();
  843. if (blockage && House->Is_Ally(blockage)) {
  844. bool old = Special.IsScatter;
  845. Special.IsScatter = true;
  846. cellptr->Incoming(0, true);
  847. Special.IsScatter = old;
  848. }
  849. }
  850. }
  851. TryTryAgain = PATH_RETRY;
  852. facing = Path[0];
  853. }
  854. if (Class->IsLockTurret || !Class->IsTurretEquipped) {
  855. IsTurretLockedDown = true;
  856. }
  857. #ifdef NEVER
  858. /*
  859. ** If the turret needs to match the body's facing before
  860. ** movement can occur, then start it's rotation and
  861. ** don't start a movement track until it is aligned.
  862. */
  863. if (!Ok_To_Move(BodyFacing)) {
  864. return(true);
  865. }
  866. #endif
  867. /*
  868. ** Determine the coordinate of the next cell to move into.
  869. */
  870. dest = Adjacent_Cell(Coord, facing);
  871. dir = Facing_Dir(facing);
  872. /*
  873. ** Set the facing correctly if it isn't already correct. This
  874. ** means starting a rotation track if necessary.
  875. */
  876. facediff = PrimaryFacing.Difference(dir);
  877. if (facediff) {
  878. /*
  879. ** Request a change of facing.
  880. */
  881. Do_Turn(dir);
  882. return(true);
  883. } else {
  884. /* NOTE: Beyond this point, actual track assignment can begin.
  885. **
  886. ** If the cell to move into is impassable (probably for some unexpected
  887. ** reason), then abort the path list and set the speed to zero. The
  888. ** next time this routine is called, a new path will be generated.
  889. */
  890. destcell = Coord_Cell(dest);
  891. Mark(MARK_UP);
  892. MoveType cando = Can_Enter_Cell(destcell, facing);
  893. Mark(MARK_DOWN);
  894. if (cando != MOVE_OK) {
  895. if (Mission == MISSION_MOVE && House->IsHuman && Distance(NavCom) < 0x0200) {
  896. Assign_Destination(TARGET_NONE);
  897. }
  898. /*
  899. ** If a temporary friendly object is blocking the path, then cause it to
  900. ** get out of the way.
  901. */
  902. if (cando == MOVE_TEMP) {
  903. bool old = Special.IsScatter;
  904. Special.IsScatter = true;
  905. Map[destcell].Incoming(0, true);
  906. Special.IsScatter = old;
  907. }
  908. /*
  909. ** If a cloaked object is blocking, then shimmer the cell.
  910. */
  911. if (cando == MOVE_CLOAK) {
  912. Map[destcell].Shimmer();
  913. }
  914. Stop_Driver();
  915. if (cando != MOVE_MOVING_BLOCK) {
  916. Path[0] = FACING_NONE; // Path is blocked!
  917. }
  918. /*
  919. ** If blocked by a moving block then just exit start of move and
  920. ** try again next tick.
  921. */
  922. if (cando == MOVE_DESTROYABLE) {
  923. if (Map[destcell].Cell_Object()) {
  924. if (!House->Is_Ally(Map[destcell].Cell_Object())) {
  925. Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
  926. }
  927. } else {
  928. if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
  929. Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
  930. }
  931. }
  932. } else {
  933. if (IsNewNavCom) Sound_Effect(VOC_SCOLD);
  934. }
  935. IsNewNavCom = false;
  936. TrackNumber = -1;
  937. return(true);
  938. }
  939. /*
  940. ** Determine the speed that the unit can travel to the desired square.
  941. */
  942. ground = Map[destcell].Land_Type();
  943. speed = Ground[ground].Cost[Class->Speed];
  944. if (!speed) speed = 128;
  945. #ifdef NEVER
  946. /*
  947. ** Set the jiggle flag if the terrain would cause the unit
  948. ** to jiggle when travelled over.
  949. */
  950. BaseF &= ~BASEF_JIGGLE;
  951. if (Ground[ground].Jiggle) {
  952. BaseF |= BASEF_JIGGLE;
  953. }
  954. #endif
  955. /*
  956. ** A damaged unit has a reduced speed.
  957. */
  958. if ((Class->MaxStrength>>1) > Strength) {
  959. speed -= (speed>>2); // Three quarters speed.
  960. }
  961. if ((speed != Speed)/* || !SpeedAdd*/) {
  962. Set_Speed(speed); // Full speed.
  963. }
  964. /*
  965. ** Adjust speed depending on distance to ultimate movement target. The
  966. ** further away the target is, the faster the vehicle will travel.
  967. */
  968. int dist = Distance(NavCom);
  969. if (dist < 0x0200) {
  970. speed = Fixed_To_Cardinal(speed, 0x00A0);
  971. } else {
  972. if (dist < 0x0700) {
  973. speed = Fixed_To_Cardinal(speed, 0x00D0);
  974. }
  975. }
  976. /*
  977. ** Reserve the destination cell so that it won't become
  978. ** occupied AS this unit is moving into it.
  979. */
  980. if (cando != MOVE_OK) {
  981. Path[0] = FACING_NONE; // Path is blocked!
  982. TrackNumber = -1;
  983. dest = NULL;
  984. } else {
  985. Overrun_Square(Coord_Cell(dest), true);
  986. /*
  987. ** Determine which track to use (based on recorded path).
  988. */
  989. FacingType nextface = Path[1];
  990. if (nextface == FACING_NONE) nextface = facing;
  991. IsOnShortTrack = false;
  992. TrackNumber = facing * FACING_COUNT + nextface;
  993. if (TrackControl[TrackNumber].Track == 0) {
  994. Path[0] = FACING_NONE;
  995. TrackNumber = -1;
  996. return(true);
  997. } else {
  998. if (TrackControl[TrackNumber].Flag & F_D) {
  999. /*
  1000. ** If the middle cell of a two cell track contains a crate,
  1001. ** the check for goodies before movement starts.
  1002. */
  1003. if (!Map[destcell].Goodie_Check(this)) {
  1004. cando = MOVE_NO;
  1005. } else {
  1006. dest = Adjacent_Cell(dest, nextface);
  1007. destcell = Coord_Cell(dest);
  1008. cando = Can_Enter_Cell(destcell);
  1009. }
  1010. if (cando != MOVE_OK) {
  1011. /*
  1012. ** If a temporary friendly object is blocking the path, then cause it to
  1013. ** get out of the way.
  1014. */
  1015. if (cando == MOVE_TEMP) {
  1016. bool old = Special.IsScatter;
  1017. Special.IsScatter = true;
  1018. Map[destcell].Incoming(0, true);
  1019. Special.IsScatter = old;
  1020. }
  1021. /*
  1022. ** If a cloaked object is blocking, then shimmer the cell.
  1023. */
  1024. if (cando == MOVE_CLOAK) {
  1025. Map[destcell].Shimmer();
  1026. }
  1027. Path[0] = FACING_NONE; // Path is blocked!
  1028. TrackNumber = -1;
  1029. dest = NULL;
  1030. if (cando == MOVE_DESTROYABLE) {
  1031. if (Map[destcell].Cell_Object()) {
  1032. if (!House->Is_Ally(Map[destcell].Cell_Object())) {
  1033. Override_Mission(MISSION_ATTACK, Map[destcell].Cell_Object()->As_Target(), TARGET_NONE);
  1034. }
  1035. } else {
  1036. if (Map[destcell].Overlay != OVERLAY_NONE && OverlayTypeClass::As_Reference(Map[destcell].Overlay).IsWall) {
  1037. Override_Mission(MISSION_ATTACK, ::As_Target(destcell), TARGET_NONE);
  1038. }
  1039. }
  1040. IsNewNavCom = false;
  1041. TrackIndex = 0;
  1042. return(true);
  1043. }
  1044. } else {
  1045. memcpy(&Path[0], &Path[2], CONQUER_PATH_MAX-2);
  1046. Path[CONQUER_PATH_MAX-2] = FACING_NONE;
  1047. IsPlanningToLook = true;
  1048. }
  1049. } else {
  1050. memcpy(&Path[0], &Path[1], CONQUER_PATH_MAX-1);
  1051. }
  1052. Path[CONQUER_PATH_MAX-1] = FACING_NONE;
  1053. }
  1054. }
  1055. IsNewNavCom = false;
  1056. TrackIndex = 0;
  1057. if (!Start_Driver(dest)) {
  1058. TrackNumber = -1;
  1059. Path[0] = FACING_NONE;
  1060. Set_Speed(0);
  1061. }
  1062. }
  1063. return(false);
  1064. }
  1065. /***********************************************************************************************
  1066. * DriveClass::AI -- Processes unit movement and rotation. *
  1067. * *
  1068. * This routine is used to process unit movement and rotation. It *
  1069. * functions autonomously from the script system. Thus, once a unit *
  1070. * is give rotation command or movement path, it will follow this *
  1071. * until specifically instructed to stop. The advantage of this *
  1072. * method is that it allows smooth movement of units, faster game *
  1073. * execution, and reduced script complexity (since actual movement *
  1074. * dynamics need not be controlled directly by the scripts). *
  1075. * *
  1076. * INPUT: none *
  1077. * *
  1078. * OUTPUT: none *
  1079. * *
  1080. * WARNINGS: This routine relies on the process control bits for the *
  1081. * specified unit (for speed reasons). Thus, only setting *
  1082. * movement, rotation, or path list will the unit perform *
  1083. * any physics. *
  1084. * *
  1085. * HISTORY: *
  1086. * 09/26/1993 JLB : Created. *
  1087. * 04/15/1994 JLB : Converted to member function. *
  1088. *=============================================================================================*/
  1089. void DriveClass::AI(void)
  1090. {
  1091. FootClass::AI();
  1092. /*
  1093. ** If the unit is following a track, then continue
  1094. ** to do so -- mindlessly.
  1095. */
  1096. if (TrackNumber != -1) {
  1097. /*
  1098. ** Perform the movement accumulation.
  1099. */
  1100. While_Moving();
  1101. if (!IsActive) return;
  1102. if (TrackNumber == -1 && (Target_Legal(NavCom) || Path[0] != FACING_NONE)) {
  1103. Start_Of_Move();
  1104. While_Moving();
  1105. if (!IsActive) return;
  1106. }
  1107. } else {
  1108. /*
  1109. ** For tracked units that are rotating in place, perform the rotation now.
  1110. */
  1111. if ((Class->Speed == SPEED_FLOAT || Class->Speed == SPEED_HOVER || Class->Speed == SPEED_TRACK || (Class->Speed == SPEED_WHEEL && !Special.IsThreePoint)) && PrimaryFacing.Is_Rotating()) {
  1112. if (PrimaryFacing.Rotation_Adjust(Class->ROT)) {
  1113. Mark(MARK_CHANGE);
  1114. }
  1115. if (!IsRotating) {
  1116. Per_Cell_Process(true);
  1117. if (!IsActive) return;
  1118. }
  1119. } else {
  1120. /*
  1121. ** The unit has no track to follow, but if there
  1122. ** is a navigation target or a remaining path,
  1123. ** then start on a new track.
  1124. */
  1125. if (Mission != MISSION_GUARD || NavCom != TARGET_NONE) {
  1126. if (Target_Legal(NavCom) || Path[0] != FACING_NONE) {
  1127. Start_Of_Move();
  1128. While_Moving();
  1129. if (!IsActive) return;
  1130. } else {
  1131. Stop_Driver();
  1132. }
  1133. }
  1134. }
  1135. }
  1136. }
  1137. /***********************************************************************************************
  1138. * DriveClass::Fixup_Path -- Adds smooth start path to normal movement path. *
  1139. * *
  1140. * This routine modifies the path of the specified unit so that it *
  1141. * will not start out with a rotation. This is necessary for those *
  1142. * vehicles that have difficulty with rotating in place. Typically, *
  1143. * this includes wheeled vehicles. *
  1144. * *
  1145. * INPUT: unit -- Pointer to the unit to adjust. *
  1146. * *
  1147. * path -- Pointer to path structure. *
  1148. * *
  1149. * OUTPUT: none *
  1150. * *
  1151. * WARNINGS: Only units that require a fixup get modified. The *
  1152. * modification only occurs, if there is a legal path to *
  1153. * do so. *
  1154. * *
  1155. * HISTORY: *
  1156. * 04/03/1994 JLB : Created. *
  1157. * 04/06/1994 JLB : Uses path structure. *
  1158. * 04/10/1994 JLB : Diagonal smooth turn added. *
  1159. * 04/15/1994 JLB : Converted to member function. *
  1160. *=============================================================================================*/
  1161. void DriveClass::Fixup_Path(PathType *path)
  1162. {
  1163. FacingType stage[6]={FACING_N,FACING_N,FACING_N,FACING_N,FACING_N,FACING_N}; // Prefix path elements.
  1164. int facediff; // The facing difference value (0..4 | 0..-4).
  1165. static FacingType _path[4][6] = {
  1166. {(FacingType)2,(FacingType)0,(FacingType)2,(FacingType)0,(FacingType)0,(FacingType)0},
  1167. {(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
  1168. {(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
  1169. {(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
  1170. };
  1171. static FacingType _dpath[4][6] = {
  1172. {(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0,(FacingType)0},
  1173. {(FacingType)3,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)0,(FacingType)0},
  1174. {(FacingType)4,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0},
  1175. {(FacingType)5,(FacingType)0,(FacingType)2,(FacingType)2,(FacingType)1,(FacingType)0}
  1176. };
  1177. int index;
  1178. int counter; // Path addition
  1179. FacingType *ptr; // Path list pointer.
  1180. FacingType *ptr2; // Copy of new path list pointer.
  1181. FacingType nextpath; // Next path value.
  1182. CELL cell; // Working cell value.
  1183. bool ok;
  1184. /*
  1185. ** Verify that the unit is valid and there is a path problem to resolve.
  1186. */
  1187. if (!path || path->Command[0] == FACING_NONE) {
  1188. return;
  1189. }
  1190. /*
  1191. ** Only wheeled vehicles need a path fixup -- to avoid 3 point turns.
  1192. */
  1193. if (!Special.IsThreePoint || Class->Speed != SPEED_WHEEL) {
  1194. return;
  1195. }
  1196. /*
  1197. ** If the original path starts in the same direction as the unit, then
  1198. ** there is no problem to resolve -- abort.
  1199. */
  1200. facediff = PrimaryFacing.Difference((DirType)(path->Command[0]<<5)) >> 5;
  1201. if (!facediff) return;
  1202. if (Dir_Facing(PrimaryFacing) & FACING_NE) {
  1203. ptr = &_dpath[(FacingType)ABS((int)facediff)-FACING_NE][1]; // Pointer to path adjust list.
  1204. counter = (int)_dpath[(FacingType)ABS((int)facediff)-FACING_NE][0]; // Number of path adjusts.
  1205. } else {
  1206. ptr = &_path[(FacingType)ABS((int)facediff)-FACING_NE][1]; // Pointer to path adjust list.
  1207. counter = (int)_path[(FacingType)ABS((int)facediff)-FACING_NE][0]; // Number of path adjusts.
  1208. }
  1209. ptr2 = ptr;
  1210. ok = true; // Presume adjustment is all ok.
  1211. cell = Coord_Cell(Coord); // Starting cell.
  1212. nextpath = Dir_Facing(PrimaryFacing); // Starting path.
  1213. for (index = 0; index < counter; index++) {
  1214. /*
  1215. ** Determine next path element and add it to the
  1216. ** working path list.
  1217. */
  1218. if (facediff > 0) {
  1219. nextpath = nextpath + *ptr++;
  1220. } else {
  1221. nextpath = nextpath - *ptr++;
  1222. }
  1223. stage[index] = nextpath;
  1224. cell = Adjacent_Cell(cell, nextpath);
  1225. //cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));
  1226. /*
  1227. ** If it can't enter this cell, then abort the path
  1228. ** building operation without adjusting the unit's
  1229. ** path.
  1230. */
  1231. if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
  1232. ok = false;
  1233. break;
  1234. }
  1235. }
  1236. /*
  1237. ** If veering to the left was not successful, then try veering
  1238. ** to the right. This only makes sense if the vehicle is trying
  1239. ** to turn 180 degrees.
  1240. */
  1241. if (!ok && ABS(facediff) == 4) {
  1242. ptr = ptr2; // Pointer to path adjust list.
  1243. facediff = -facediff;
  1244. ok = true; // Presume adjustment is all ok.
  1245. cell = Coord_Cell(Coord); // Starting cell.
  1246. nextpath = Dir_Facing(PrimaryFacing); // Starting path.
  1247. for (index = 0; index < counter; index++) {
  1248. /*
  1249. ** Determine next path element and add it to the
  1250. ** working path list.
  1251. */
  1252. if (facediff > 0) {
  1253. nextpath = nextpath + *ptr++;
  1254. } else {
  1255. nextpath = nextpath - *ptr++;
  1256. }
  1257. stage[index] = nextpath;
  1258. cell = Coord_Cell(Adjacent_Cell(Cell_Coord(cell), nextpath));
  1259. /*
  1260. ** If it can't enter this cell, then abort the path
  1261. ** building operation without adjusting the unit's
  1262. ** path.
  1263. */
  1264. if (Can_Enter_Cell(cell, nextpath) != MOVE_OK) {
  1265. ok = false;
  1266. break;
  1267. }
  1268. }
  1269. }
  1270. /*
  1271. ** If a legal path addition was created, then install it in place
  1272. ** of the first path value. The initial path entry is to be replaced
  1273. ** with a sequence of path entries that create smooth turning.
  1274. */
  1275. if (ok) {
  1276. if (path->Length <= 1) {
  1277. movmem(&stage[0], path->Command, MAX(counter, 1));
  1278. path->Length = counter;
  1279. } else {
  1280. /*
  1281. ** Optimize the transition path step from the smooth turn
  1282. ** first part as it joins with the rest of the normal
  1283. ** path. The normal prefix path steps are NOT to be optimized.
  1284. */
  1285. if (counter) {
  1286. counter--;
  1287. path->Command[0] = stage[counter];
  1288. Optimize_Moves(path, MOVE_OK);
  1289. }
  1290. /*
  1291. ** If there is more than one prefix path element, then
  1292. ** insert the rest now.
  1293. */
  1294. if (counter) {
  1295. movmem(&path->Command[0], &path->Command[counter], 40-counter);
  1296. movmem(&stage[0], &path->Command[0], counter);
  1297. path->Length += counter;
  1298. }
  1299. }
  1300. path->Command[path->Length] = FACING_NONE;
  1301. }
  1302. }
  1303. /***********************************************************************************************
  1304. * DriveClass::Lay_Track -- Handles track laying logic for the unit. *
  1305. * *
  1306. * This routine handles the track laying for the unit. This entails examining the unit's *
  1307. * current location as well as the direction and whether this unit is allowed to lay *
  1308. * tracks in the first place. *
  1309. * *
  1310. * INPUT: none *
  1311. * *
  1312. * OUTPUT: none *
  1313. * *
  1314. * WARNINGS: none *
  1315. * *
  1316. * HISTORY: *
  1317. * 05/28/1994 JLB : Created. *
  1318. *=============================================================================================*/
  1319. void DriveClass::Lay_Track(void)
  1320. {
  1321. #ifdef NEVER
  1322. static IconCommandType *_trackdirs[8] = {
  1323. TrackN_S,
  1324. TrackNE_SW,
  1325. TrackE_W,
  1326. TrackNW_SE,
  1327. TrackN_S,
  1328. TrackNE_SW,
  1329. TrackE_W,
  1330. TrackNW_SE
  1331. };
  1332. if (!(ClassF & CLASSF_TRACKS)) return;
  1333. Icon_Install(Coord_Cell(Coord), _trackdirs[Facing_To_8(BodyFacing)]);
  1334. #endif
  1335. }
  1336. /***********************************************************************************************
  1337. * DriveClass::Mark_Track -- Marks the midpoint of the track as occupied. *
  1338. * *
  1339. * This routine will ensure that the midpoint (if any) of the track that the unit is *
  1340. * following, will be marked according to the mark type specified. *
  1341. * *
  1342. * INPUT: headto -- The head to coordinate. *
  1343. * *
  1344. * type -- The type of marking to perform. *
  1345. * *
  1346. * OUTPUT: none *
  1347. * *
  1348. * WARNINGS: none *
  1349. * *
  1350. * HISTORY: *
  1351. * 07/30/1995 JLB : Created. *
  1352. *=============================================================================================*/
  1353. void DriveClass::Mark_Track(COORDINATE headto, MarkType type)
  1354. {
  1355. int value;
  1356. if (type == MARK_UP) {
  1357. value = false;
  1358. } else {
  1359. value = true;
  1360. }
  1361. if (headto) {
  1362. if (!IsOnShortTrack && TrackNumber != -1) {
  1363. /*
  1364. ** If we have not passed the per cell process point we need
  1365. ** to deal with it.
  1366. */
  1367. int tracknum = TrackControl[TrackNumber].Track;
  1368. if (tracknum) {
  1369. TrackType const * ptr = RawTracks[tracknum - 1].Track;
  1370. int cellidx = RawTracks[tracknum - 1].Cell;
  1371. if (cellidx > -1) {
  1372. DirType dir = ptr[cellidx].Facing;
  1373. if (TrackIndex < cellidx && cellidx != -1) {
  1374. COORDINATE offset = Smooth_Turn(ptr[cellidx].Offset, &dir);
  1375. Map[Coord_Cell(offset)].Flag.Occupy.Vehicle = value;
  1376. }
  1377. }
  1378. }
  1379. }
  1380. Map[Coord_Cell(headto)].Flag.Occupy.Vehicle = value;
  1381. }
  1382. }
  1383. /***********************************************************************************************
  1384. * DriveClass::Offload_Tiberium_Bail -- Offloads one Tiberium quantum from the object. *
  1385. * *
  1386. * This routine will offload one Tiberium packet/quantum/bail from the object. Multiple *
  1387. * calls to this routine are needed in order to fully offload all Tiberium. *
  1388. * *
  1389. * INPUT: none *
  1390. * *
  1391. * OUTPUT: Returns with the number of credits offloaded for the one call. If zero is returned,*
  1392. * then this indicates that all Tiberium has been offloaded. *
  1393. * *
  1394. * WARNINGS: none *
  1395. * *
  1396. * HISTORY: *
  1397. * 07/19/1995 JLB : Created. *
  1398. *=============================================================================================*/
  1399. int DriveClass::Offload_Tiberium_Bail(void)
  1400. {
  1401. if (Tiberium) {
  1402. Tiberium--;
  1403. if (House->IsHuman) {
  1404. return(UnitTypeClass::FULL_LOAD_CREDITS/UnitTypeClass::STEP_COUNT);
  1405. }
  1406. return(UnitTypeClass::FULL_LOAD_CREDITS+(UnitTypeClass::FULL_LOAD_CREDITS/3)/UnitTypeClass::STEP_COUNT);
  1407. }
  1408. return(0);
  1409. }
  1410. /***********************************************************************************************
  1411. * DriveClass::Ok_To_Move -- Checks to see if this object can begin moving. *
  1412. * *
  1413. * This routine is used to verify that this object is allowed to move. Some objects can *
  1414. * be temporarily occupied and thus cannot move until the situation permits. *
  1415. * *
  1416. * INPUT: direction -- The direction that movement would be desired. *
  1417. * *
  1418. * OUTPUT: Can the unit move in the direction specified? *
  1419. * *
  1420. * WARNINGS: none *
  1421. * *
  1422. * HISTORY: *
  1423. * 07/29/1995 JLB : Created. *
  1424. *=============================================================================================*/
  1425. bool DriveClass::Ok_To_Move(DirType ) const
  1426. {
  1427. return true;
  1428. }
  1429. /***********************************************************************************************
  1430. * DriveClass::Class_Of -- Fetches a reference to the class type for this object. *
  1431. * *
  1432. * This routine will fetch a reference to the TypeClass of this object. *
  1433. * *
  1434. * INPUT: none *
  1435. * *
  1436. * OUTPUT: Returns with reference to the type class of this object. *
  1437. * *
  1438. * WARNINGS: none *
  1439. * *
  1440. * HISTORY: *
  1441. * 07/29/1995 JLB : Created. *
  1442. *=============================================================================================*/
  1443. ObjectTypeClass const & DriveClass::Class_Of(void) const
  1444. {
  1445. return *Class;
  1446. }
  1447. /***************************************************************************
  1448. ** Smooth turn track tables. These are coordinate offsets from the center
  1449. ** of the destination cell. These are the raw tracks that are modified
  1450. ** by negating the X and Y portions as necessary. Also for reverse travelling
  1451. ** direction, the track list can be processed backward.
  1452. **
  1453. ** Track 1 = N
  1454. ** Track 2 = NE
  1455. ** Track 3 = N->NE 45 deg (double path consumption)
  1456. ** Track 4 = N->E 90 deg (double path consumption)
  1457. ** Track 5 = NE->SE 90 deg (double path consumption)
  1458. ** Track 6 = NE->N 45 deg (double path consumption)
  1459. ** Track 7 = N->NE (facing change only)
  1460. ** Track 8 = NE->E (facing change only)
  1461. ** Track 9 = N->E (facing change only)
  1462. ** Track 10= NE->SE (facing change only)
  1463. ** Track 11= back up into refinery
  1464. ** Track 12= drive out of refinery
  1465. */
  1466. #pragma warn -ias
  1467. DriveClass::TrackType const DriveClass::Track1[24] = {
  1468. {0x00F50000L,(DirType)0},
  1469. {0x00EA0000L,(DirType)0},
  1470. {0x00DF0000L,(DirType)0},
  1471. {0x00D40000L,(DirType)0},
  1472. {0x00C90000L,(DirType)0},
  1473. {0x00BE0000L,(DirType)0},
  1474. {0x00B30000L,(DirType)0},
  1475. {0x00A80000L,(DirType)0},
  1476. {0x009D0000L,(DirType)0},
  1477. {0x00920000L,(DirType)0},
  1478. {0x00870000L,(DirType)0},
  1479. {0x007C0000L,(DirType)0}, // Track jump check here.
  1480. {0x00710000L,(DirType)0},
  1481. {0x00660000L,(DirType)0},
  1482. {0x005B0000L,(DirType)0},
  1483. {0x00500000L,(DirType)0},
  1484. {0x00450000L,(DirType)0},
  1485. {0x003A0000L,(DirType)0},
  1486. {0x002F0000L,(DirType)0},
  1487. {0x00240000L,(DirType)0},
  1488. {0x00190000L,(DirType)0},
  1489. {0x000E0000L,(DirType)0},
  1490. {0x00030000L,(DirType)0},
  1491. {0x00000000L,(DirType)0}
  1492. };
  1493. DriveClass::TrackType const DriveClass::Track2[] = {
  1494. {0x00F8FF08L,(DirType)32},
  1495. {0x00F0FF10L,(DirType)32},
  1496. {0x00E8FF18L,(DirType)32},
  1497. {0x00E0FF20L,(DirType)32},
  1498. {0x00D8FF28L,(DirType)32},
  1499. {0x00D0FF30L,(DirType)32},
  1500. {0x00C8FF38L,(DirType)32},
  1501. {0x00C0FF40L,(DirType)32},
  1502. {0x00B8FF48L,(DirType)32},
  1503. {0x00B0FF50L,(DirType)32},
  1504. {0x00A8FF58L,(DirType)32},
  1505. {0x00A0FF60L,(DirType)32},
  1506. {0x0098FF68L,(DirType)32},
  1507. {0x0090FF70L,(DirType)32},
  1508. {0x0088FF78L,(DirType)32},
  1509. {0x0080FF80L,(DirType)32}, // Track jump check here.
  1510. {0x0078FF88L,(DirType)32},
  1511. {0x0070FF90L,(DirType)32},
  1512. {0x0068FF98L,(DirType)32},
  1513. {0x0060FFA0L,(DirType)32},
  1514. {0x0058FFA8L,(DirType)32},
  1515. {0x0050FFB0L,(DirType)32},
  1516. {0x0048FFB8L,(DirType)32},
  1517. {0x0040FFC0L,(DirType)32},
  1518. {0x0038FFC8L,(DirType)32},
  1519. {0x0030FFD0L,(DirType)32},
  1520. {0x0028FFD8L,(DirType)32},
  1521. {0x0020FFE0L,(DirType)32},
  1522. {0x0018FFE8L,(DirType)32},
  1523. {0x0010FFF0L,(DirType)32},
  1524. {0x0008FFF8L,(DirType)32},
  1525. {0x00000000L,(DirType)32}
  1526. };
  1527. DriveClass::TrackType const DriveClass::Track3[] = {
  1528. {0x01F5FF00L,(DirType)0},
  1529. {0x01EAFF00L,(DirType)0},
  1530. {0x01DFFF00L,(DirType)0},
  1531. {0x01D4FF00L,(DirType)0},
  1532. {0x01C9FF00L,(DirType)0},
  1533. {0x01BEFF00L,(DirType)0},
  1534. {0x01B3FF00L,(DirType)0},
  1535. {0x01A8FF00L,(DirType)0},
  1536. {0x019DFF00L,(DirType)0},
  1537. {0x0192FF00L,(DirType)0},
  1538. {0x0187FF00L,(DirType)0},
  1539. {0x0180FF00L,(DirType)0},
  1540. {0x0175FF00L,(DirType)0}, // Jump entry point here.
  1541. {0x016BFF00L,(DirType)0},
  1542. {0x0160FF02L,(DirType)1},
  1543. {0x0155FF04L,(DirType)3},
  1544. {0x014CFF06L,(DirType)4},
  1545. {0x0141FF08L,(DirType)5},
  1546. {0x0137FF0BL,(DirType)7},
  1547. {0x012EFF0FL,(DirType)8},
  1548. {0x0124FF13L,(DirType)9},
  1549. {0x011AFF17L,(DirType)11},
  1550. {0x0110FF1BL,(DirType)12},
  1551. {0x0107FF1FL,(DirType)13}, // Center cell processing here.
  1552. {0x00FCFF24L,(DirType)15},
  1553. {0x00F3FF28L,(DirType)16},
  1554. {0x00ECFF2CL,(DirType)17},
  1555. {0x00E0FF32L,(DirType)19},
  1556. {0x00D7FF36L,(DirType)20},
  1557. {0x00CFFF3DL,(DirType)21},
  1558. {0x00C6FF42L,(DirType)23},
  1559. {0x00BAFF49L,(DirType)24},
  1560. {0x00B0FF4DL,(DirType)25},
  1561. {0x00A8FF58L,(DirType)27},
  1562. {0x00A0FF60L,(DirType)28},
  1563. {0x0098FF68L,(DirType)29},
  1564. {0x0090FF70L,(DirType)31},
  1565. {0x0088FF78L,(DirType)32},
  1566. {0x0080FF80L,(DirType)32}, // Track jump check here.
  1567. {0x0078FF88L,(DirType)32},
  1568. {0x0070FF90L,(DirType)32},
  1569. {0x0068FF98L,(DirType)32},
  1570. {0x0060FFA0L,(DirType)32},
  1571. {0x0058FFA8L,(DirType)32},
  1572. {0x0050FFB0L,(DirType)32},
  1573. {0x0048FFB8L,(DirType)32},
  1574. {0x0040FFC0L,(DirType)32},
  1575. {0x0038FFC8L,(DirType)32},
  1576. {0x0030FFD0L,(DirType)32},
  1577. {0x0028FFD8L,(DirType)32},
  1578. {0x0020FFE0L,(DirType)32},
  1579. {0x0018FFE8L,(DirType)32},
  1580. {0x0010FFF0L,(DirType)32},
  1581. {0x0008FFF8L,(DirType)32},
  1582. {0x00000000L,(DirType)32}
  1583. };
  1584. DriveClass::TrackType const DriveClass::Track4[] = {
  1585. {0x00F5FF00L,(DirType)0},
  1586. {0x00EBFF00L,(DirType)0},
  1587. {0x00E0FF00L,(DirType)0},
  1588. {0x00D5FF00L,(DirType)0},
  1589. {0x00CBFF01L,(DirType)0},
  1590. {0x00C0FF03L,(DirType)0},
  1591. {0x00B5FF05L,(DirType)1},
  1592. {0x00ABFF07L,(DirType)1},
  1593. {0x00A0FF0AL,(DirType)2},
  1594. {0x0095FF0DL,(DirType)3},
  1595. {0x008BFF10L,(DirType)4},
  1596. {0x0080FF14L,(DirType)5}, // Track entry here.
  1597. {0x0075FF18L,(DirType)8},
  1598. {0x006DFF1CL,(DirType)12},
  1599. {0x0063FF22L,(DirType)16},
  1600. {0x005AFF25L,(DirType)20},
  1601. {0x0052FF2BL,(DirType)23},
  1602. {0x0048FF32L,(DirType)27},
  1603. {0x0040FF37L,(DirType)32},
  1604. {0x0038FF3DL,(DirType)36},
  1605. {0x0030FF46L,(DirType)39},
  1606. {0x002BFF4FL,(DirType)43},
  1607. {0x0024FF58L,(DirType)47},
  1608. {0x0020FF60L,(DirType)51},
  1609. {0x001BFF6DL,(DirType)54},
  1610. {0x0017FF79L,(DirType)57},
  1611. {0x0014FF82L,(DirType)60}, // Track jump here.
  1612. {0x0011FF8FL,(DirType)62},
  1613. {0x000DFF98L,(DirType)63},
  1614. {0x0009FFA2L,(DirType)64},
  1615. {0x0006FFACL,(DirType)64},
  1616. {0x0004FFB5L,(DirType)66},
  1617. {0x0003FFC0L,(DirType)64},
  1618. {0x0002FFCBL,(DirType)64},
  1619. {0x0001FFD5L,(DirType)64},
  1620. {0x0000FFE0L,(DirType)64},
  1621. {0x0000FFEBL,(DirType)64},
  1622. {0x0000FFF5L,(DirType)64},
  1623. {0x00000000L,(DirType)64}
  1624. };
  1625. DriveClass::TrackType const DriveClass::Track5[] = {
  1626. {0xFFF8FE08L,(DirType)32},
  1627. {0xFFF0FE10L,(DirType)32},
  1628. {0xFFE8FE18L,(DirType)32},
  1629. {0xFFE0FE20L,(DirType)32},
  1630. {0xFFD8FE28L,(DirType)32},
  1631. {0xFFD0FE30L,(DirType)32},
  1632. {0xFFC8FE38L,(DirType)32},
  1633. {0xFFC0FE40L,(DirType)32},
  1634. {0xFFB8FE48L,(DirType)32},
  1635. {0xFFB0FE50L,(DirType)32},
  1636. {0xFFA8FE58L,(DirType)32},
  1637. {0xFFA0FE60L,(DirType)32},
  1638. {0xFF98FE68L,(DirType)32},
  1639. {0xFF90FE70L,(DirType)32},
  1640. {0xFF88FE78L,(DirType)32},
  1641. {0xFF80FE80L,(DirType)32}, // Track entry here.
  1642. {0xFF78FE88L,(DirType)32},
  1643. {0xFF71FE90L,(DirType)32},
  1644. {0xFF6AFE97L,(DirType)32},
  1645. {0xFF62FE9FL,(DirType)32},
  1646. {0xFF5AFEA8L,(DirType)32},
  1647. {0xFF53FEB0L,(DirType)35},
  1648. {0xFF4BFEB7L,(DirType)38},
  1649. {0xFF44FEBEL,(DirType)41},
  1650. {0xFF3EFEC4L,(DirType)44},
  1651. {0xFF39FECEL,(DirType)47},
  1652. {0xFF34FED8L,(DirType)50},
  1653. {0xFF30FEE0L,(DirType)53},
  1654. {0xFF2DFEEBL,(DirType)56},
  1655. {0xFF2CFEF5L,(DirType)59},
  1656. {0xFF2BFF00L,(DirType)62},
  1657. {0xFF2CFF0BL,(DirType)66},
  1658. {0xFF2DFF15L,(DirType)69},
  1659. {0xFF30FF1FL,(DirType)72},
  1660. {0xFF34FF28L,(DirType)75},
  1661. {0xFF39FF30L,(DirType)78},
  1662. {0xFF3EFF3AL,(DirType)81},
  1663. {0xFF44FF44L,(DirType)84},
  1664. {0xFF4BFF4BL,(DirType)87},
  1665. {0xFF53FF50L,(DirType)90},
  1666. {0xFF5AFF58L,(DirType)93},
  1667. {0xFF62FF60L,(DirType)96},
  1668. {0xFF6AFF68L,(DirType)96},
  1669. {0xFF71FF70L,(DirType)96},
  1670. {0xFF78FF78L,(DirType)96},
  1671. {0xFF80FF80L,(DirType)96}, // Track jump check here.
  1672. {0xFF88FF88L,(DirType)96},
  1673. {0xFF90FF90L,(DirType)96},
  1674. {0xFF98FF98L,(DirType)96},
  1675. {0xFFA0FFA0L,(DirType)96},
  1676. {0xFFA8FFA8L,(DirType)96},
  1677. {0xFFB0FFB0L,(DirType)96},
  1678. {0xFFB8FFB8L,(DirType)96},
  1679. {0xFFC0FFC0L,(DirType)96},
  1680. {0xFFC8FFC8L,(DirType)96},
  1681. {0xFFD0FFD0L,(DirType)96},
  1682. {0xFFD8FFD8L,(DirType)96},
  1683. {0xFFE0FFE0L,(DirType)96},
  1684. {0xFFE8FFE8L,(DirType)96},
  1685. {0xFFF0FFF0L,(DirType)96},
  1686. {0xFFF8FFF8L,(DirType)96},
  1687. {0x00000000L,(DirType)96}
  1688. };
  1689. DriveClass::TrackType const DriveClass::Track6[] = {
  1690. {0x0100FE00L,(DirType)32},
  1691. {0x00F8FE08L,(DirType)32},
  1692. {0x00F0FE10L,(DirType)32},
  1693. {0x00E8FE18L,(DirType)32},
  1694. {0x00E0FE20L,(DirType)32},
  1695. {0x00D8FE28L,(DirType)32},
  1696. {0x00D0FE30L,(DirType)32},
  1697. {0x00C8FE38L,(DirType)32},
  1698. {0x00C0FE40L,(DirType)32},
  1699. {0x00B8FE48L,(DirType)32},
  1700. {0x00B0FE50L,(DirType)32},
  1701. {0x00A8FE58L,(DirType)32},
  1702. {0x00A0FE60L,(DirType)32},
  1703. {0x0098FE68L,(DirType)32},
  1704. {0x0090FE70L,(DirType)32},
  1705. {0x0088FE78L,(DirType)32},
  1706. {0x0080FE80L,(DirType)32}, // Jump entry point here.
  1707. {0x0078FE88L,(DirType)32},
  1708. {0x0070FE90L,(DirType)32},
  1709. {0x0068FE98L,(DirType)32},
  1710. {0x0060FEA0L,(DirType)32},
  1711. {0x0058FEA8L,(DirType)32},
  1712. {0x0055FEAEL,(DirType)32},
  1713. {0x004EFEB8L,(DirType)35},
  1714. {0x0048FEC0L,(DirType)37},
  1715. {0x0042FEC9L,(DirType)40},
  1716. {0x003BFED2L,(DirType)43},
  1717. {0x0037FEDAL,(DirType)45},
  1718. {0x0032FEE3L,(DirType)48},
  1719. {0x002BFEEBL,(DirType)51},
  1720. {0x0026FEF5L,(DirType)53},
  1721. {0x0022FEFEL,(DirType)56},
  1722. {0x001CFF08L,(DirType)59},
  1723. {0x0019FF12L,(DirType)61},
  1724. {0x0015FF1BL,(DirType)64},
  1725. {0x0011FF26L,(DirType)64},
  1726. {0x000EFF30L,(DirType)64},
  1727. {0x000BFF39L,(DirType)64},
  1728. {0x0009FF43L,(DirType)64},
  1729. {0x0007FF4EL,(DirType)64},
  1730. {0x0005FF57L,(DirType)64},
  1731. {0x0003FF62L,(DirType)64},
  1732. {0x0001FF6DL,(DirType)64},
  1733. {0x0000FF77L,(DirType)64},
  1734. {0x0000FF80L,(DirType)64}, // Track jump check here.
  1735. {0x0000FF8BL,(DirType)64},
  1736. {0x0000FF95L,(DirType)64},
  1737. {0x0000FFA0L,(DirType)64},
  1738. {0x0000FFABL,(DirType)64},
  1739. {0x0000FFB5L,(DirType)64},
  1740. {0x0000FFC0L,(DirType)64},
  1741. {0x0000FFCBL,(DirType)64},
  1742. {0x0000FFD5L,(DirType)64},
  1743. {0x0000FFE0L,(DirType)64},
  1744. {0x0000FFEBL,(DirType)64},
  1745. {0x0000FFF5L,(DirType)64},
  1746. {0x00000000L,(DirType)64}
  1747. };
  1748. DriveClass::TrackType const DriveClass::Track7[] = {
  1749. {0x0006FFFFL,(DirType)0},
  1750. {0x000CFFFEL,(DirType)4},
  1751. {0x0011FFFCL,(DirType)8},
  1752. {0x0018FFFAL,(DirType)12},
  1753. {0x001FFFF6L,(DirType)16},
  1754. {0x0024FFF3L,(DirType)19},
  1755. {0x002BFFF0L,(DirType)22},
  1756. {0x0030FFFDL,(DirType)23},
  1757. {0x0035FFEBL,(DirType)24},
  1758. {0x0038FFE8L,(DirType)25},
  1759. {0x003CFFE6L,(DirType)26},
  1760. {0x0040FFE3L,(DirType)27},
  1761. {0x0043FFE0L,(DirType)28},
  1762. {0x0046FFDDL,(DirType)29},
  1763. {0x0043FFDFL,(DirType)30},
  1764. {0x0040FFE1L,(DirType)30},
  1765. {0x003CFFE3L,(DirType)30},
  1766. {0x0038FFE5L,(DirType)30},
  1767. {0x0035FFE7L,(DirType)31},
  1768. {0x0030FFE9L,(DirType)31},
  1769. {0x002BFFEBL,(DirType)31},
  1770. {0x0024FFEDL,(DirType)31},
  1771. {0x001FFFF1L,(DirType)31},
  1772. {0x0018FFF4L,(DirType)32},
  1773. {0x0011FFF7L,(DirType)32},
  1774. {0x000CFFFAL,(DirType)32},
  1775. {0x0006FFFDL,(DirType)32},
  1776. {0x00000000L,(DirType)32}
  1777. };
  1778. DriveClass::TrackType const DriveClass::Track8[] = {
  1779. {0x0003FFFCL,(DirType)32},
  1780. {0x0006FFF7L,(DirType)36},
  1781. {0x000AFFF1L,(DirType)40},
  1782. {0x000CFFEBL,(DirType)44},
  1783. {0x000DFFE4L,(DirType)46},
  1784. {0x000EFFDCL,(DirType)48},
  1785. {0x000FFFD5L,(DirType)50},
  1786. {0x0010FFD0L,(DirType)52},
  1787. {0x0011FFC9L,(DirType)54},
  1788. {0x0012FFC2L,(DirType)56},
  1789. {0x0011FFC0L,(DirType)58},
  1790. {0x0010FFC2L,(DirType)60},
  1791. {0x000EFFC9L,(DirType)62},
  1792. {0x000CFFCFL,(DirType)64},
  1793. {0x000AFFD5L,(DirType)64},
  1794. {0x0008FFDAL,(DirType)64},
  1795. {0x0006FFE2L,(DirType)64},
  1796. {0x0004FFE9L,(DirType)64},
  1797. {0x0002FFEFL,(DirType)64},
  1798. {0x0001FFF5L,(DirType)64},
  1799. {0x0000FFF9L,(DirType)64},
  1800. {0x00000000L,(DirType)64}
  1801. };
  1802. DriveClass::TrackType const DriveClass::Track9[] = {
  1803. {0xFFF50002L,(DirType)0},
  1804. {0xFFEB0004L,(DirType)2},
  1805. {0xFFE00006L,(DirType)4},
  1806. {0xFFD50009L,(DirType)6},
  1807. {0xFFCE000CL,(DirType)9},
  1808. {0xFFC8000FL,(DirType)11},
  1809. {0xFFC00012L,(DirType)13},
  1810. {0xFFB80015L,(DirType)16},
  1811. {0xFFC00012L,(DirType)18},
  1812. {0xFFC8000EL,(DirType)20},
  1813. {0xFFCE000AL,(DirType)22},
  1814. {0xFFD50004L,(DirType)24},
  1815. {0xFFDE0000L,(DirType)26},
  1816. {0xFFE9FFF8L,(DirType)28},
  1817. {0xFFEEFFF2L,(DirType)30},
  1818. {0xFFF5FFEBL,(DirType)32},
  1819. {0xFFFDFFE1L,(DirType)34},
  1820. {0x0002FFD8L,(DirType)36},
  1821. {0x0007FFD2L,(DirType)39},
  1822. {0x000BFFCBL,(DirType)41},
  1823. {0x0010FFC5L,(DirType)43},
  1824. {0x0013FFBEL,(DirType)45},
  1825. {0x0015FFB7L,(DirType)48},
  1826. {0x0013FFBEL,(DirType)50},
  1827. {0x0011FFC5L,(DirType)52},
  1828. {0x000BFFCCL,(DirType)54},
  1829. {0x0008FFD4L,(DirType)56},
  1830. {0x0005FFDFL,(DirType)58},
  1831. {0x0003FFEBL,(DirType)62},
  1832. {0x0001FFF5L,(DirType)64},
  1833. {0x00000000L,(DirType)64}
  1834. };
  1835. DriveClass::TrackType const DriveClass::Track10[] = {
  1836. {0xFFF6000BL,(DirType)32},
  1837. {0xFFF00015L,(DirType)37},
  1838. {0xFFEB0020L,(DirType)42},
  1839. {0xFFE9002BL,(DirType)47},
  1840. {0xFFE50032L,(DirType)52},
  1841. {0xFFE30038L,(DirType)57},
  1842. {0xFFE00040L,(DirType)60},
  1843. {0xFFE20038L,(DirType)62},
  1844. {0xFFE40032L,(DirType)64},
  1845. {0xFFE5002AL,(DirType)68},
  1846. {0xFFE6001EL,(DirType)70},
  1847. {0xFFE70015L,(DirType)72},
  1848. {0xFFE8000BL,(DirType)74},
  1849. {0xFFE90000L,(DirType)76},
  1850. {0xFFE8FFF5L,(DirType)78},
  1851. {0xFFE7FFEBL,(DirType)80},
  1852. {0xFFE6FFE0L,(DirType)82},
  1853. {0xFFE5FFD5L,(DirType)84},
  1854. {0xFFE4FFCEL,(DirType)86},
  1855. {0xFFE2FFC5L,(DirType)88},
  1856. {0xFFE0FFC0L,(DirType)90},
  1857. {0xFFE3FFC5L,(DirType)92},
  1858. {0xFFE5FFCEL,(DirType)94},
  1859. {0xFFE9FFD5L,(DirType)95},
  1860. {0xFFEBFFE0L,(DirType)96},
  1861. {0xFFF0FFEBL,(DirType)96},
  1862. {0xFFF6FFF5L,(DirType)96},
  1863. {0x00000000L,(DirType)96}
  1864. };
  1865. DriveClass::TrackType const DriveClass::Track11[] = {
  1866. {0x01000000L,DIR_SW},
  1867. {0x00F30008L,DIR_SW},
  1868. {0x00E50010L,DIR_SW_X1},
  1869. {0x00D60018L,DIR_SW_X1},
  1870. {0x00C80020L,DIR_SW_X1},
  1871. {0x00B90028L,DIR_SW_X1},
  1872. {0x00AB0030L,DIR_SW_X2},
  1873. {0x009C0038L,DIR_SW_X2},
  1874. {0x008D0040L,DIR_SW_X2},
  1875. {0x007F0048L,DIR_SW_X2},
  1876. {0x00710050L,DIR_SW_X2},
  1877. {0x00640058L,DIR_SW_X2},
  1878. {0x00550060L,DIR_SW_X2},
  1879. {0x00000000L,DIR_SW_X2}
  1880. };
  1881. DriveClass::TrackType const DriveClass::Track12[] = {
  1882. {0xFF550060L,DIR_SW_X2},
  1883. {0xFF640058L,DIR_SW_X2},
  1884. {0xFF710050L,DIR_SW_X2},
  1885. {0xFF7F0048L,DIR_SW_X2},
  1886. {0xFF8D0040L,DIR_SW_X2},
  1887. {0xFF9C0038L,DIR_SW_X2},
  1888. {0xFFAB0030L,DIR_SW_X2},
  1889. {0xFFB90028L,DIR_SW_X1},
  1890. {0xFFC80020L,DIR_SW_X1},
  1891. {0xFFD60018L,DIR_SW_X1},
  1892. {0xFFE50010L,DIR_SW_X1},
  1893. {0xFFF30008L,DIR_SW},
  1894. {0x00000000L,DIR_SW}
  1895. };
  1896. /*
  1897. ** Drive out of weapon's factory.
  1898. */
  1899. DriveClass::TrackType const DriveClass::Track13[] = {
  1900. {XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
  1901. {XYP_COORD(10,-21),(DirType)(DIR_SW-10)},
  1902. {XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
  1903. {XYP_COORD(10,-20),(DirType)(DIR_SW-10)},
  1904. {XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
  1905. {XYP_COORD(9,-18),(DirType)(DIR_SW-10)},
  1906. {XYP_COORD(9,-17),(DirType)(DIR_SW-10)},
  1907. {XYP_COORD(8,-16),(DirType)(DIR_SW-10)},
  1908. {XYP_COORD(8,-15),(DirType)(DIR_SW-10)},
  1909. {XYP_COORD(7,-14),(DirType)(DIR_SW-10)},
  1910. {XYP_COORD(7,-13),(DirType)(DIR_SW-10)},
  1911. {XYP_COORD(6,-12),(DirType)(DIR_SW-10)},
  1912. {XYP_COORD(6,-11),(DirType)(DIR_SW-10)},
  1913. {XYP_COORD(5,-10),(DirType)(DIR_SW-10)},
  1914. {XYP_COORD(5,-9),(DirType)(DIR_SW-10)},
  1915. {XYP_COORD(4,-8),(DirType)(DIR_SW-10)},
  1916. {XYP_COORD(4,-7),(DirType)(DIR_SW-10)},
  1917. {XYP_COORD(3,-6),(DirType)(DIR_SW-10)},
  1918. {XYP_COORD(3,-5),(DirType)(DIR_SW-9)},
  1919. {XYP_COORD(2,-4),(DirType)(DIR_SW-7)},
  1920. {XYP_COORD(2,-3),(DirType)(DIR_SW-5)},
  1921. {XYP_COORD(1,-2),(DirType)(DIR_SW-3)},
  1922. {XYP_COORD(1,-1),(DirType)(DIR_SW-1)},
  1923. {0x00000000L,DIR_SW}
  1924. };
  1925. /*
  1926. ** There are a limited basic number of tracks that a vehicle can follow. These
  1927. ** are they. Each track can be interpreted differently but this is controlled
  1928. ** by the TrackControl structure elaborated elsewhere.
  1929. */
  1930. DriveClass::RawTrackType const DriveClass::RawTracks[13] = {
  1931. {Track1, -1, 0, -1},
  1932. {Track2, -1, 0, -1},
  1933. {Track3, 37, 12, 22},
  1934. {Track4, 26, 11, 19},
  1935. {Track5, 45, 15, 31},
  1936. {Track6, 44, 16, 27},
  1937. {Track7, -1, 0, -1},
  1938. {Track8, -1, 0, -1},
  1939. {Track9, -1, 0, -1},
  1940. {Track10, -1, 0, -1},
  1941. {Track11, -1, 0, -1},
  1942. {Track12, -1, 0, -1},
  1943. {Track13, -1, 0, -1}
  1944. };
  1945. /***************************************************************************
  1946. ** Smooth turning control table. Given two directions in a path list, this
  1947. ** table determines which track to use and what modifying operations need
  1948. ** be performed on the track data.
  1949. */
  1950. DriveClass::TurnTrackType const DriveClass::TrackControl[67] = {
  1951. {1, 0, DIR_N, F_}, // 0-0
  1952. {3, 7, DIR_NE, F_D}, // 0-1 (raw chart)
  1953. {4, 9, DIR_E, F_D}, // 0-2 (raw chart)
  1954. {0, 0, DIR_SE, F_}, // 0-3 !
  1955. {0, 0, DIR_S, F_}, // 0-4 !
  1956. {0, 0, DIR_SW, F_}, // 0-5 !
  1957. {4, 9, DIR_W, (DriveClass::TrackControlType)(F_X|F_D)}, // 0-6
  1958. {3, 7, DIR_NW, (DriveClass::TrackControlType)(F_X|F_D)}, // 0-7
  1959. {6, 8, DIR_N, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 1-0
  1960. {2, 0, DIR_NE, F_}, // 1-1 (raw chart)
  1961. {6, 8, DIR_E, F_D}, // 1-2 (raw chart)
  1962. {5, 10, DIR_SE, F_D}, // 1-3 (raw chart)
  1963. {0, 0, DIR_S, F_}, // 1-4 !
  1964. {0, 0, DIR_SW, F_}, // 1-5 !
  1965. {0, 0, DIR_W, F_}, // 1-6 !
  1966. {5, 10, DIR_NW, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 1-7
  1967. {4, 9, DIR_N, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 2-0
  1968. {3, 7, DIR_NE, (DriveClass::TrackControlType)(F_T|F_X|F_Y|F_D)}, // 2-1
  1969. {1, 0, DIR_E, (DriveClass::TrackControlType)(F_T|F_X)}, // 2-2
  1970. {3, 7, DIR_SE, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 2-3
  1971. {4, 9, DIR_S, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 2-4
  1972. {0, 0, DIR_SW, F_}, // 2-5 !
  1973. {0, 0, DIR_W, F_}, // 2-6 !
  1974. {0, 0, DIR_NW, F_}, // 2-7 !
  1975. {0, 0, DIR_N, F_}, // 3-0 !
  1976. {5, 10, DIR_NE, (DriveClass::TrackControlType)(F_Y|F_D)}, // 3-1
  1977. {6, 8, DIR_E, (DriveClass::TrackControlType)(F_Y|F_D)}, // 3-2
  1978. {2, 0, DIR_SE, F_Y}, // 3-3
  1979. {6, 8, DIR_S, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 3-4
  1980. {5, 10, DIR_SW, (DriveClass::TrackControlType)(F_T|F_X|F_D)}, // 3-5
  1981. {0, 0, DIR_W, F_}, // 3-6 !
  1982. {0, 0, DIR_NW, F_}, // 3-7 !
  1983. {0, 0, DIR_N, F_}, // 4-0 !
  1984. {0, 0, DIR_NE, F_}, // 4-1 !
  1985. {4, 9, DIR_E, (DriveClass::TrackControlType)(F_Y|F_D)}, // 4-2
  1986. {3, 7, DIR_SE, (DriveClass::TrackControlType)(F_Y|F_D)}, // 4-3
  1987. {1, 0, DIR_S, F_Y}, // 4-4
  1988. {3, 7, DIR_SW, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 4-5
  1989. {4, 9, DIR_W, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 4-6
  1990. {0, 0, DIR_NW, F_}, // 4-7 !
  1991. {0, 0, DIR_N, F_}, // 5-0 !
  1992. {0, 0, DIR_NE, F_}, // 5-1 !
  1993. {0, 0, DIR_E, F_}, // 5-2 !
  1994. {5, 10, DIR_SE, (DriveClass::TrackControlType)(F_T|F_D)}, // 5-3
  1995. {6, 8, DIR_S, (DriveClass::TrackControlType)(F_T|F_D)}, // 5-4
  1996. {2, 0, DIR_SW, F_T}, // 5-5
  1997. {6, 8, DIR_W, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 5-6
  1998. {5, 10, DIR_NW, (DriveClass::TrackControlType)(F_X|F_Y|F_D)}, // 5-7
  1999. {4, 9, DIR_N, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 6-0
  2000. {0, 0, DIR_NE, F_}, // 6-1 !
  2001. {0, 0, DIR_E, F_}, // 6-2 !
  2002. {0, 0, DIR_SE, F_}, // 6-3 !
  2003. {4, 9, DIR_S, (DriveClass::TrackControlType)(F_T|F_D)}, // 6-4
  2004. {3, 7, DIR_SW, (DriveClass::TrackControlType)(F_T|F_D)}, // 6-5
  2005. {1, 0, DIR_W, F_T}, // 6-6
  2006. {3, 7, DIR_NW, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 6-7
  2007. {6, 8, DIR_N, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 7-0
  2008. {5, 10, DIR_NE, (DriveClass::TrackControlType)(F_T|F_Y|F_D)}, // 7-1
  2009. {0, 0, DIR_E, F_}, // 7-2 !
  2010. {0, 0, DIR_SE, F_}, // 7-3 !
  2011. {0, 0, DIR_S, F_}, // 7-4 !
  2012. {5, 10, DIR_SW, (DriveClass::TrackControlType)(F_X|F_D)}, // 7-5
  2013. {6, 8, DIR_W, (DriveClass::TrackControlType)(F_X|F_D)}, // 7-6
  2014. {2, 0, DIR_NW, F_X}, // 7-7
  2015. {11, 11, DIR_SW, F_}, // Backup harvester into refinery.
  2016. {12, 12, DIR_SW_X2, F_}, // Drive back into refinery.
  2017. {13, 13, DIR_SW, F_} // Drive out of weapons factory.
  2018. };