FOOT.CPP 102 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015
  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\foot.cpv 2.17 16 Oct 1995 16:51:42 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 : FOOT.CPP *
  26. * *
  27. * Programmer : Joe L. Bostic *
  28. * *
  29. * Start Date : April 22, 1994 *
  30. * *
  31. * Last Update : August 13, 1995 [JLB] *
  32. * *
  33. *---------------------------------------------------------------------------------------------*
  34. * Functions: *
  35. * FootClass::Active_Click_With -- Intiates attack or move according to target clicked on. *
  36. * FootClass::Active_Click_With -- Performs action as a result of left mouse click. *
  37. * FootClass::Approach_Target -- Sets the navigation computer to approach target object. *
  38. * FootClass::Assign_Destination -- Assigns specified destination to NavCom. *
  39. * FootClass::Assign_Mission -- Assign mission to foot class object. *
  40. * FootClass::Basic_Path -- Finds the basic path for a ground object. *
  41. * FootClass::Body_Facing -- Set the body rotation/facing. *
  42. * FootClass::Can_Demolish -- Checks to see if this object can be sold back. *
  43. * FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified. *
  44. * FootClass::Death_Announcement -- Announces the death of a unit. *
  45. * FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor. *
  46. * FootClass::Detach -- Detaches a target from tracking systems. *
  47. * FootClass::Detach_All -- Removes this object from the game system. *
  48. * FootClass::Enters_Building -- When unit enters a building for some reason. *
  49. * FootClass::FootClass -- Default constructor for foot class objects. *
  50. * FootClass::FootClass -- Normal constructor for the foot class object. *
  51. * FootClass::Greatest_Threat -- Fetches the greatest threat to this object. *
  52. * FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly. *
  53. * FootClass::Limbo -- Intercepts limbo event and handles FootClass processing. *
  54. * FootClass::Mark -- Unit interface to map rendering system. *
  55. * FootClass::Mission_Attack -- AI for heading towards and firing upon target. *
  56. * FootClass::Mission_Capture -- Handles the capture mission. *
  57. * FootClass::Mission_Enter -- Enter (cooperatively) mission handler. *
  58. * FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range. *
  59. * FootClass::Mission_Hunt -- Handles the default hunt order. *
  60. * FootClass::Mission_Move -- AI process for moving a vehicle to its destination. *
  61. * FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step. *
  62. * FootClass::Override_Mission -- temporarily overides a units mission *
  63. * FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition. *
  64. * FootClass::Receive_Message -- Movement related radio messages are handled here. *
  65. * FootClass::Rescue_Mission -- Calls this unit to the rescue. *
  66. * FootClass::Restore_Mission -- Restores an overidden mission *
  67. * FootClass::Sell_Back -- Causes this object to be sold back. *
  68. * FootClass::Set_Speed -- Initiate unit movement physics. *
  69. * FootClass::Sort_Y -- Determine the sort coordinate for foot class objects. *
  70. * FootClass::Start_Driver -- This starts the driver heading to the destination desired. *
  71. * FootClass::Stop_Driver -- This routine clears the driving state of the object. *
  72. * FootClass::Stun -- Prepares a ground travelling object for removal. *
  73. * FootClass::Take_Damage -- Handles taking damage to this object. *
  74. * FootClass::Unlimbo -- Unlimbos object and performs special fixups. *
  75. * FootClass::~FootClass -- Default destructor for foot class objects. *
  76. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  77. #include "function.h"
  78. /***********************************************************************************************
  79. * FootClass::FootClass -- Default constructor for foot class objects. *
  80. * *
  81. * This is the default constructor for FootClass objects. It sets the foot class values to *
  82. * their default starting settings. *
  83. * *
  84. * INPUT: none *
  85. * *
  86. * OUTPUT: none *
  87. * *
  88. * WARNINGS: none *
  89. * *
  90. * HISTORY: *
  91. * 11/23/1994 JLB : Created. *
  92. *=============================================================================================*/
  93. FootClass::FootClass(void) : Speed(0)
  94. {
  95. ArchiveTarget = TARGET_NONE;
  96. IsDriving = false;
  97. IsInitiated = false;
  98. IsPlanningToLook = false;
  99. IsDeploying = false;
  100. IsNewNavCom = false;
  101. IsFiring = false;
  102. IsRotating = false;
  103. IsUnloading = false;
  104. NavCom = TARGET_NONE;
  105. SuspendedNavCom = TARGET_NONE;
  106. Path[0] = FACING_NONE;
  107. HeadToCoord = NULL;
  108. Member = 0;
  109. Team = 0;
  110. PathDelay = 0;
  111. TryTryAgain = PATH_RETRY;
  112. if (House) {
  113. House->CurUnits++;
  114. }
  115. Group = -1;
  116. }
  117. /***********************************************************************************************
  118. * FootClass::~FootClass -- Default destructor for foot class objects. *
  119. * *
  120. * At this level of the destruction process, the house record of the number of units *
  121. * currently in inventory is decremented to reflect this units destruction. *
  122. * *
  123. * INPUT: none *
  124. * *
  125. * OUTPUT: none *
  126. * *
  127. * WARNINGS: none *
  128. * *
  129. * HISTORY: *
  130. * 01/10/1995 JLB : Created. *
  131. *=============================================================================================*/
  132. FootClass::~FootClass(void)
  133. {
  134. if (GameActive && House) {
  135. House->CurUnits--;
  136. }
  137. }
  138. /***********************************************************************************************
  139. * FootClass::FootClass -- Normal constructor for the foot class object. *
  140. * *
  141. * This is the normal constructor used when creating a foot class object. *
  142. * *
  143. * INPUT: house -- The house that owns this object. *
  144. * *
  145. * OUTPUT: none *
  146. * *
  147. * WARNINGS: none *
  148. * *
  149. * HISTORY: *
  150. * 12/29/1994 JLB : Created. *
  151. *=============================================================================================*/
  152. FootClass::FootClass(HousesType house) :
  153. TechnoClass(house),
  154. Speed(0)
  155. {
  156. ArchiveTarget = TARGET_NONE;
  157. Member = 0;
  158. Team = 0;
  159. Path[0] = FACING_NONE;
  160. NavCom = TARGET_NONE;
  161. SuspendedNavCom = TARGET_NONE;
  162. IsUnloading = false;
  163. IsDriving = false;
  164. IsInitiated = false;
  165. IsRotating = false;
  166. IsFiring = false;
  167. IsDeploying = false;
  168. IsNewNavCom = false;
  169. IsPlanningToLook = false;
  170. HeadToCoord = 0L;
  171. PathDelay = 0;
  172. Group = -1;
  173. TryTryAgain = PATH_RETRY;
  174. House->CurUnits++;
  175. }
  176. #ifdef CHEAT_KEYS
  177. /***********************************************************************************************
  178. * FootClass::Debug_Dump -- Displays the status of the FootClass to the mono monitor. *
  179. * *
  180. * This routine is used to output the current status of the foot class to the mono *
  181. * monitor. Through this display bugs may be tracked down or eliminated. *
  182. * *
  183. * INPUT: none *
  184. * *
  185. * OUTPUT: none *
  186. * *
  187. * WARNINGS: none *
  188. * *
  189. * HISTORY: *
  190. * 06/02/1994 JLB : Created. *
  191. * 07/04/1995 JLB : Handles aircraft special case. *
  192. *=============================================================================================*/
  193. void FootClass::Debug_Dump(MonoClass *mono) const
  194. {
  195. static char const * _p2c[9] = {"-","0","1","2","3","4","5","6","7"};
  196. #define Path_To_String(a) _p2c[((ABS((int)a+1))%9)]
  197. /*
  198. ** Display the common data for all objects that inherity from FootClass.
  199. */
  200. mono->Set_Cursor(63, 7);
  201. if (Team) {
  202. mono->Printf("%s(%d)", Team->Class->IniName, Teams.ID(Team));
  203. } else {
  204. mono->Printf("(none)");
  205. }
  206. mono->Set_Cursor(73, 7);mono->Printf("%04X", ArchiveTarget);
  207. mono->Set_Cursor(42, 1);mono->Printf("%04X", NavCom);
  208. mono->Set_Cursor(44, 3);mono->Printf("%d", Speed);
  209. /*
  210. ** Although aircraft inherit from FootClass, some of the variables are not
  211. ** used and thus should not be displayed.
  212. */
  213. if (What_Am_I() != RTTI_AIRCRAFT) {
  214. mono->Set_Cursor(50, 3);
  215. mono->Printf("%s%s%s%s%s%s%s%s%s%s%s%s",
  216. Path_To_String(Path[0]),
  217. Path_To_String(Path[1]),
  218. Path_To_String(Path[2]),
  219. Path_To_String(Path[3]),
  220. Path_To_String(Path[4]),
  221. Path_To_String(Path[5]),
  222. Path_To_String(Path[6]),
  223. Path_To_String(Path[7]),
  224. Path_To_String(Path[8]),
  225. Path_To_String(Path[9]),
  226. Path_To_String(Path[10]),
  227. Path_To_String(Path[11]),
  228. Path_To_String(Path[12]));
  229. mono->Set_Cursor(65, 1);mono->Printf("%08lX", Head_To_Coord());
  230. mono->Text_Print("X", 16 + (IsDeploying?2:0), 12);
  231. mono->Text_Print("X", 16 + (IsRotating?2:0), 13);
  232. mono->Text_Print("X", 16 + (IsDriving?2:0), 15);
  233. mono->Text_Print("X", 16 + (IsFiring?2:0), 14);
  234. mono->Text_Print("X", 16 + (IsPlanningToLook?2:0), 16);
  235. }
  236. TechnoClass::Debug_Dump(mono);
  237. }
  238. #endif
  239. /***********************************************************************************************
  240. * FootClass::Set_Speed -- Initiate unit movement physics. *
  241. * *
  242. * This routine is used to set a unit's velocity control structure. *
  243. * The game will then process the unit's movement during the momentum *
  244. * physics calculation. *
  245. * *
  246. * INPUT: unit -- Pointer to the unit to alter. *
  247. * *
  248. * speed -- Throttle setting (0=stop, 255=full throttle). *
  249. * *
  250. * OUTPUT: none *
  251. * *
  252. * WARNINGS: none *
  253. * *
  254. * HISTORY: *
  255. * 09/07/1992 JLB : Created. *
  256. * 09/24/1993 JLB : Revised for faster speed. *
  257. * 04/02/1994 JLB : Revised for new system. *
  258. * 04/15/1994 JLB : Converted to member function. *
  259. * 07/21/1994 JLB : Simplified. *
  260. *=============================================================================================*/
  261. void FootClass::Set_Speed(int speed)
  262. {
  263. speed &= 0xFF;
  264. ((unsigned char &)Speed) = speed;
  265. }
  266. /***********************************************************************************************
  267. * FootClass::Mark -- Unit interface to map rendering system. *
  268. * *
  269. * This routine is the interface function for units as they relate to *
  270. * the map rendering system. Whenever a unit's imagery changes, this *
  271. * function is called. *
  272. * *
  273. * INPUT: mark -- Type of image change (MARK_UP, _DOWN, _CHANGE) *
  274. * MARK_UP -- Unit is removed. *
  275. * MARK_CHANGE -- Unit alters image but doesn't move. *
  276. * MARK_DOWN -- Unit is overlaid onto existing icons. *
  277. * *
  278. * OUTPUT: bool; Did the marking operation succeed? Failure could be the result of marking *
  279. * down when it is already down, or visa versa. *
  280. * *
  281. * WARNINGS: none *
  282. * *
  283. * HISTORY: *
  284. * 09/14/1991 JLB : Created. *
  285. * 04/15/1994 JLB : Converted to member function. *
  286. * 12/23/1994 JLB : Performs low level check before processing. *
  287. *=============================================================================================*/
  288. bool FootClass::Mark(MarkType mark)
  289. {
  290. if (TechnoClass::Mark(mark)) {
  291. CELL cell = Coord_Cell(Coord);
  292. /*
  293. ** Inform the map of the refresh, occupation, and overlap
  294. ** request.
  295. */
  296. switch (mark) {
  297. case MARK_UP:
  298. Map.Pick_Up(cell, this);
  299. break;
  300. case MARK_DOWN:
  301. Map.Place_Down(cell, this);
  302. break;
  303. default:
  304. Map.Refresh_Cells(cell, Overlap_List());
  305. Map.Refresh_Cells(cell, Occupy_List());
  306. break;
  307. }
  308. return(true);
  309. }
  310. return(false);
  311. }
  312. /***********************************************************************************************
  313. * FootClass::Basic_Path -- Finds the basic path for a ground object. *
  314. * *
  315. * This is a common routine used by both infantry and other ground travelling units. It *
  316. * will fill in the unit's basic path to the NavCom destination. *
  317. * *
  318. * INPUT: none *
  319. * *
  320. * OUTPUT: bool; Was a path found? A failure to find a path means either the target cannot *
  321. * be found or the terrain prohibits the unit's movement. *
  322. * *
  323. * WARNINGS: none *
  324. * *
  325. * HISTORY: *
  326. * 10/17/1994 JLB : Created. *
  327. *=============================================================================================*/
  328. bool FootClass::Basic_Path(void)
  329. {
  330. PathType *path; // Pointer to path control structure.
  331. CELL cell;
  332. int skip_path = false;
  333. Path[0] = FACING_NONE;
  334. if (Target_Legal(NavCom)) {
  335. cell = As_Cell(NavCom);
  336. /*
  337. ** When the navigation computer is set to a location that is impassible, then
  338. ** find a nearby cell that can be entered and try to head toward that instead.
  339. ** EXCEPT when that cell is very close -- then just bail.
  340. */
  341. // IsFindPath = true;
  342. if (Can_Enter_Cell(cell) == MOVE_NO && Distance(NavCom) > 0x0300) {
  343. static int _faceadjust[8] = {0, 1, -1, 2, -2, 3, -3, 4};
  344. FacingType f2 = (FacingType)(((unsigned)::Direction(cell, Coord_Cell(Coord)))>>5);
  345. for (unsigned index = 0; index < (sizeof(_faceadjust) / sizeof(_faceadjust[0])); index++) {
  346. CELL cell2;
  347. cell2 = Adjacent_Cell(cell, (FacingType)((f2+_faceadjust[index])&0x7));
  348. if (Can_Enter_Cell(cell2, FACING_NONE) <= MOVE_CLOAK) {
  349. cell = cell2;
  350. break;
  351. }
  352. }
  353. }
  354. // IsFindPath = false;
  355. #ifdef SPECIAL
  356. if (What_Am_I() == RTTI_INFANTRY) {
  357. CELL mycell = Coord_Cell(Center_Coord());
  358. // Mark(MARK_UP);
  359. ObjectClass *obj = Map[mycell].Cell_Occupier();
  360. while (obj) {
  361. if (obj != this && obj->What_Am_I() == RTTI_INFANTRY) {
  362. InfantryClass *inf = (InfantryClass *)obj;
  363. if (inf->NavCom == NavCom && inf->Path[0] != FACING_NONE) {
  364. if (Coord_Cell(inf->Head_To_Coord()) == Coord_Cell(inf->Coord)) {
  365. Mem_Copy(&inf->Path[1], Path, sizeof(Path)-sizeof(Path[0]));
  366. } else {
  367. Mem_Copy(inf->Path, Path, sizeof(Path));
  368. }
  369. if (Path[0] != FACING_NONE) {
  370. skip_path = true;
  371. }
  372. break;
  373. }
  374. }
  375. obj = obj->Next;
  376. }
  377. // Mark(MARK_DOWN);
  378. }
  379. #endif
  380. if (!skip_path) {
  381. Mark(MARK_UP);
  382. Path[0] = FACING_NONE; // Probably not necessary, but...
  383. /*
  384. ** Try to find a path to the destination. If a failure occurs, then keep trying
  385. ** with greater determination until either a complete failure occurs, or a decent
  386. ** path was found.
  387. */
  388. bool found1=false; // Found a best path yet?
  389. PathType path1;
  390. FacingType workpath1[200]; // Staging area for path list.
  391. FacingType workpath2[200]; // Staging area for path list.
  392. MoveType maxtype = MOVE_TEMP;
  393. if (!House->IsHuman) {
  394. maxtype = MOVE_DESTROYABLE;
  395. } else {
  396. /*
  397. ** For simple movement missions by the human player, then don't
  398. ** consider friendly units as passable if close to the destination.
  399. ** This will prevent a human controlled unit from just sitting next
  400. ** to a destination just because there is another friendly unit
  401. ** occupying the destination location.
  402. */
  403. if (Mission == MISSION_MOVE && Distance(NavCom) < 0x0280) {
  404. maxtype = MOVE_DESTROYABLE;
  405. }
  406. }
  407. /*
  408. ** Determine if ANY path could be calculated by first examining the most
  409. ** aggressive case. If this fails, then no path will succeed. Further
  410. ** scanning is unnecessary.
  411. */
  412. path = Find_Path(cell, &workpath1[0], sizeof(workpath1), maxtype);
  413. if (path && path->Cost) {
  414. memcpy(&path1, path, sizeof(path1));
  415. found1 = true;
  416. /*
  417. ** Scan for the best path possible. If this succeeds, then do a simple
  418. ** comparison with the most agressive path. If they are very close, then
  419. ** go with the best (easiest) path method.
  420. */
  421. path = Find_Path(cell, &workpath2[0], sizeof(workpath2), MOVE_CLOAK);
  422. if (path && path->Cost && path->Cost < MAX((path1.Cost + (path1.Cost/2)), 3)) {
  423. memcpy(&path1, path, sizeof(path1));
  424. memcpy(workpath1, workpath2, sizeof(workpath1));
  425. } else {
  426. /*
  427. ** The easiest path method didn't result in a satisfactory path. Scan through
  428. ** the rest of the path options, looking for the best one.
  429. */
  430. for (MoveType move = MOVE_MOVING_BLOCK; move < maxtype; move++) {
  431. path = Find_Path(cell, &workpath2[0], sizeof(workpath2), move);
  432. if (path && path->Cost && path->Cost < MAX((path1.Cost + (path1.Cost/2)), 3)) {
  433. memcpy(&path1, path, sizeof(path1));
  434. memcpy(workpath1, workpath2, sizeof(workpath1));
  435. }
  436. }
  437. }
  438. }
  439. #ifdef OBSOLETE
  440. for (MoveType move = MOVE_CLOAK; move <= maxtype; move++) {
  441. if (!found1) {
  442. path = Find_Path(cell, &workpath1[0], sizeof(workpath1), move);
  443. if (path && path->Cost) {
  444. memcpy(&path1, path, sizeof(path1));
  445. found1 = true;
  446. if (path1.Cost < 5) break;
  447. }
  448. } else {
  449. path = Find_Path(cell, &workpath2[0], sizeof(workpath2), move);
  450. if (path) {
  451. if (path->Cost && path->Cost <= path1.Cost/2) {
  452. memcpy(&path1, path, sizeof(path1));
  453. memcpy(workpath1, workpath2, sizeof(workpath1));
  454. }
  455. }
  456. }
  457. }
  458. #endif
  459. /*
  460. ** If a good path was found, then record it in the object's path
  461. ** list.
  462. */
  463. if (found1) {
  464. Fixup_Path(&path1);
  465. memcpy(&Path[0], &workpath1[0], MIN(path->Length, (int)sizeof(Path)));
  466. }
  467. Mark(MARK_DOWN);
  468. }
  469. #ifdef NEVER
  470. /*
  471. ** Patch at this point to see if we are moving directly into a
  472. ** MOVE_TEMP. This allows units to bunch up at a bridge even if there
  473. ** is an enormously long way around. This also allows units to give
  474. ** up trying to move into the MOVE_TEMP using the normal movement
  475. ** retry logic.
  476. */
  477. CELL cell = Adjacent_Cell(Coord_Cell(Coord), Path[0]);
  478. if (Can_Enter_Cell(cell, FACING_NONE) == MOVEF_TEMP) {
  479. Path[0] = FACING_NONE;
  480. }
  481. #endif
  482. PathDelay = PATH_DELAY;
  483. if (Path[0] != FACING_NONE) return(true);
  484. /*
  485. ** If a basic path couldn't be determined, then abort the navigation process.
  486. */
  487. // NavCom = TARGET_NONE;
  488. Stop_Driver();
  489. }
  490. return(false);
  491. }
  492. /***********************************************************************************************
  493. * FootClass::Mission_Move -- AI process for moving a vehicle to its destination. *
  494. * *
  495. * This simple AI script handles moving the vehicle to its desired destination. Since *
  496. * simple movement is handled directly by the engine, this routine merely waits until *
  497. * the unit has reached its destination, and then causes the unit to enter idle mode. *
  498. * *
  499. * INPUT: none *
  500. * *
  501. * OUTPUT: Returns with the delay before calling this routine again. *
  502. * *
  503. * WARNINGS: none *
  504. * *
  505. * HISTORY: *
  506. * 07/18/1994 JLB : Created. *
  507. *=============================================================================================*/
  508. int FootClass::Mission_Move(void)
  509. {
  510. if (!Target_Legal(NavCom) && !IsDriving && MissionQueue == MISSION_NONE) {
  511. Enter_Idle_Mode();
  512. }
  513. if (!Target_Legal(TarCom) && !House->IsHuman) {
  514. Target_Something_Nearby(THREAT_RANGE);
  515. }
  516. return(TICKS_PER_SECOND+3);
  517. }
  518. /***********************************************************************************************
  519. * FootClass::Mission_Capture -- Handles the capture mission. *
  520. * *
  521. * Capture missions are nearly the same as normal movement missions. The only difference *
  522. * is that the final destination is handled in a special way so that it is not marked as *
  523. * impassable. This allows the object (usually infantry) the ability to walk onto the *
  524. * object and thus capture it. *
  525. * *
  526. * INPUT: none *
  527. * *
  528. * OUTPUT: Returns with the number of game ticks to delay before calling this routine. *
  529. * *
  530. * WARNINGS: none *
  531. * *
  532. * HISTORY: *
  533. * 03/19/1995 JLB : Created. *
  534. *=============================================================================================*/
  535. int FootClass::Mission_Capture(void)
  536. {
  537. if (!Target_Legal(NavCom) && !In_Radio_Contact()) {
  538. Enter_Idle_Mode();
  539. if (Map[Coord_Cell(Center_Coord())].Cell_Building()) {
  540. Scatter(0, true);
  541. }
  542. }
  543. return(TICKS_PER_SECOND-2);
  544. }
  545. /***********************************************************************************************
  546. * FootClass::Mission_Attack -- AI for heading towards and firing upon target. *
  547. * *
  548. * This AI routine handles heading to within range of the target and then firing upon *
  549. * it until it is destroyed. If the target is destroyed, then the unit will change *
  550. * missions to match its "idle mode" of operation (usually guarding). *
  551. * *
  552. * INPUT: none *
  553. * *
  554. * OUTPUT: Returns with the delay before calling this routine again. *
  555. * *
  556. * WARNINGS: none *
  557. * *
  558. * HISTORY: *
  559. * 07/18/1994 JLB : Created. *
  560. *=============================================================================================*/
  561. int FootClass::Mission_Attack(void)
  562. {
  563. if (Target_Legal(TarCom)) {
  564. Approach_Target();
  565. } else {
  566. Enter_Idle_Mode();
  567. }
  568. return(TICKS_PER_SECOND+2);
  569. }
  570. /***********************************************************************************************
  571. * FootClass::Mission_Guard -- Handles the AI for guarding in place. *
  572. * *
  573. * Units that are performing stationary guard duty use this AI process. They will sit *
  574. * still and target any enemies that get within range. *
  575. * *
  576. * INPUT: none *
  577. * *
  578. * OUTPUT: Returns with the delay before calling this routine again. *
  579. * *
  580. * WARNINGS: none *
  581. * *
  582. * HISTORY: *
  583. * 07/18/1994 JLB : Created. *
  584. *=============================================================================================*/
  585. int FootClass::Mission_Guard(void)
  586. {
  587. if (!Target_Something_Nearby(THREAT_RANGE)) {
  588. Random_Animate();
  589. }
  590. return(TICKS_PER_SECOND+Random_Picky((int)0, (int)4, (char*)NULL, (int)0));
  591. }
  592. /***********************************************************************************************
  593. * FootClass::Mission_Hunt -- Handles the default hunt order. *
  594. * *
  595. * This routine is the default hunt order for game objects. It handles searching for a *
  596. * nearby object and heading toward it. The act of targetting will cause it to attack *
  597. * the target it selects. *
  598. * *
  599. * INPUT: none *
  600. * *
  601. * OUTPUT: Returns the game tick delay before calling this routine again. *
  602. * *
  603. * WARNINGS: none *
  604. * *
  605. * HISTORY: *
  606. * 10/17/1994 JLB : Created. *
  607. *=============================================================================================*/
  608. int FootClass::Mission_Hunt(void)
  609. {
  610. if (!Target_Something_Nearby(THREAT_NORMAL)) {
  611. Random_Animate();
  612. } else {
  613. if (What_Am_I() == RTTI_INFANTRY && ((InfantryTypeClass const &)Class_Of()).Type == INFANTRY_E7) {
  614. Assign_Destination(TarCom);
  615. Assign_Mission(MISSION_CAPTURE);
  616. } else {
  617. Approach_Target();
  618. }
  619. }
  620. return(TICKS_PER_SECOND+5);
  621. }
  622. /***********************************************************************************************
  623. * FootClass::Mission_Timed_Hunt -- This is the AI process for multiplayer computer units. *
  624. * *
  625. * For multiplayer games, the computer AI can't just blitz the human players; the humans *
  626. * need a little time to set up their base, or whatever. This state just waits for *
  627. * a certain period of time, then goes into hunt mode. *
  628. * *
  629. * INPUT: none *
  630. * *
  631. * OUTPUT: Returns with the delay before calling this routine again. *
  632. * *
  633. * WARNINGS: none *
  634. * *
  635. * HISTORY: *
  636. * 07/18/1994 JLB : Created. *
  637. *=============================================================================================*/
  638. int FootClass::Mission_Timed_Hunt(void)
  639. {
  640. int rndmax;
  641. int changed = 0; // has the unit changed into Hunt mode?
  642. if (!House->IsHuman) {
  643. /*
  644. ** Jump into HUNT mode if we're supposed to Blitz, and the EndCountDown
  645. ** has expired, or if our owning house has lost more than 1/4 of its units
  646. ** (it gets mad at you)
  647. */
  648. if ( (MPlayerBlitz && House->BlitzTime==0) ||
  649. House->CurUnits < ((House->MaxUnit * 4) / 5)) {
  650. Assign_Mission(MISSION_HUNT);
  651. changed = 1;
  652. }
  653. /*
  654. ** Jump into HUNT mode on a random die roll; the computer units will periodically
  655. ** "snap out" of their daze, and begin hunting. Try to time it so that all
  656. ** units will be hunting within 10 minutes (600 calls to this routine).
  657. */
  658. if (MPlayerBases) {
  659. rndmax = 5000;
  660. } else {
  661. rndmax = 1000;
  662. }
  663. if (IRandom(0,rndmax) == 1) {
  664. Assign_Mission(MISSION_HUNT);
  665. changed = 1;
  666. }
  667. /*
  668. ** If this unit is still just sitting in Timed Hunt mode, call Guard Area
  669. ** so it doesn't just sit there stupidly.
  670. */
  671. if (!changed) {
  672. Mission_Guard_Area();
  673. }
  674. }
  675. return(TICKS_PER_SECOND+Random_Pick(0, 4)); // call me back in 1 second.
  676. }
  677. /***********************************************************************************************
  678. * FootClass::Stop_Driver -- This routine clears the driving state of the object. *
  679. * *
  680. * This is the counterpart routine to the Start_Driver function. It clears the driving *
  681. * status flags and destination coordinate record. *
  682. * *
  683. * INPUT: none *
  684. * *
  685. * OUTPUT: bool; Was driving stopped? *
  686. * *
  687. * WARNINGS: none *
  688. * *
  689. * HISTORY: *
  690. * 10/17/1994 JLB : Created. *
  691. * 12/12/1994 JLB : Greatly simplified. *
  692. *=============================================================================================*/
  693. bool FootClass::Stop_Driver(void)
  694. {
  695. if (HeadToCoord) {
  696. HeadToCoord = NULL;
  697. Set_Speed(0);
  698. IsDriving = false;
  699. return(true);
  700. }
  701. return(false);
  702. }
  703. /***********************************************************************************************
  704. * FootClass::Start_Driver -- This starts the driver heading to the destination desired. *
  705. * *
  706. * Before a unit can move it must be started by this routine. This routine handles *
  707. * reserving the cell and setting the driving flag. *
  708. * *
  709. * INPUT: headto -- The coordinate of the immediate drive destination. This is one cell *
  710. * away from the unit's current location. *
  711. * *
  712. * OUTPUT: bool; Was driving initiated? *
  713. * *
  714. * WARNINGS: none *
  715. * *
  716. * HISTORY: *
  717. * 10/17/1994 JLB : Created. *
  718. * 12/12/1994 JLB : Uses simple spot index finder. *
  719. *=============================================================================================*/
  720. bool FootClass::Start_Driver(COORDINATE &headto)
  721. {
  722. Stop_Driver();
  723. if (headto) {
  724. HeadToCoord = headto;
  725. IsDriving = true;
  726. /*
  727. ** Check for crate goodie finder here.
  728. */
  729. if (Map[Coord_Cell(headto)].Goodie_Check(this)) {
  730. return(true);
  731. }
  732. HeadToCoord = NULL;
  733. IsDriving = false;
  734. }
  735. return(false);
  736. }
  737. /***********************************************************************************************
  738. * FootClass::Sort_Y -- Determine the sort coordinate for foot class objects. *
  739. * *
  740. * This routine will determine the sort coordinate for foot class object. This coordinate *
  741. * is usually the coordinate of the object. The exception is if the object is teathered. *
  742. * In this case (presumes offloading to the north), the sorting coordinate is adjusted *
  743. * so that the object will be drawn on top of the transport unit. *
  744. * *
  745. * INPUT: none *
  746. * *
  747. * OUTPUT: Returns with the coordinate to use for sorting. *
  748. * *
  749. * WARNINGS: none *
  750. * *
  751. * HISTORY: *
  752. * 10/17/1994 JLB : Created. *
  753. * 11/04/1994 JLB : Sort value is different when unloading from aircraft. *
  754. *=============================================================================================*/
  755. COORDINATE FootClass::Sort_Y(void) const
  756. {
  757. if (IsUnloading) {
  758. return(Coord_Add(Coord, 0x01000000L));
  759. }
  760. if (In_Radio_Contact() && IsTethered && Contact_With_Whom()->What_Am_I() == RTTI_UNIT) {
  761. return(Coord_Add(Coord, 0x01000000L));
  762. }
  763. return(Coord_Add(Coord, 0x00300000L));
  764. }
  765. /***********************************************************************************************
  766. * FootClass::Stun -- Prepares a ground travelling object for removal. *
  767. * *
  768. * This routine clears the units' navigation computer in preparation for removal from the *
  769. * game. This is probably called as a result of unit destruction in combat. Clearing the *
  770. * navigation computer ensures that the normal AI process won't start it moving again while *
  771. * the object is undergoing any death animations. *
  772. * *
  773. * INPUT: none *
  774. * *
  775. * OUTPUT: none *
  776. * *
  777. * WARNINGS: none *
  778. * *
  779. * HISTORY: *
  780. * 12/23/1994 JLB : Created. *
  781. *=============================================================================================*/
  782. void FootClass::Stun(void)
  783. {
  784. Assign_Destination(TARGET_NONE);
  785. Path[0] = FACING_NONE;
  786. Stop_Driver();
  787. TechnoClass::Stun();
  788. }
  789. /***********************************************************************************************
  790. * FootClass::Approach_Target -- Sets the navigation computer to approach target object. *
  791. * *
  792. * This routine will set the navigation computer to approach the target indicated by the *
  793. * targeting computer. It is through this function that the unit nears the target so *
  794. * that weapon firing may occur. *
  795. * *
  796. * INPUT: none *
  797. * *
  798. * OUTPUT: none *
  799. * *
  800. * WARNINGS: none *
  801. * *
  802. * HISTORY: *
  803. * 05/31/1994 JLB : Created. *
  804. * 12/13/1994 JLB : Made part of TechnoClass. *
  805. * 12/22/1994 JLB : Enhanced search algorithm. *
  806. * 05/20/1995 JLB : Always approaches if the object is off the map. *
  807. *=============================================================================================*/
  808. void FootClass::Approach_Target(void)
  809. {
  810. /*
  811. ** Determine that if there is an existing target it is still legal
  812. ** and within range.
  813. */
  814. if (Target_Legal(TarCom)) {
  815. /*
  816. ** If the target is too far away then head toward it.
  817. */
  818. int maxrange = MAX(Weapon_Range(0), Weapon_Range(1));
  819. if (!Target_Legal(NavCom) && (!In_Range(TarCom) || !IsLocked)) {
  820. // if (!Target_Legal(NavCom) && (Distance(TarCom) > maxrange || !IsLocked)) {
  821. /*
  822. ** If the object that we are attacking is a building adjust the units
  823. ** max range so that people can stand far away from the buildings and
  824. ** hit them.
  825. */
  826. BuildingClass * obj = As_Building(TarCom);
  827. if (obj) {
  828. maxrange += ((obj->Class->Width() + obj->Class->Height()) * (0x100 / 4));
  829. }
  830. /*
  831. ** Adjust the max range of an infantry unit for where he is standing
  832. ** in the room.
  833. */
  834. maxrange -= 0x00B7;
  835. #ifdef OBSOLETE
  836. if (What_Am_I() == RTTI_INFANTRY) {
  837. maxrange -= 0x0111;
  838. } else {
  839. maxrange -= 0x00B7;
  840. }
  841. #endif
  842. maxrange = MAX(maxrange, 0);
  843. COORDINATE tcoord = ::As_Coord(TarCom);
  844. COORDINATE trycoord = 0;
  845. CELL tcell = Coord_Cell(tcoord);
  846. CELL trycell = tcell;
  847. DirType dir = Direction256(tcoord, Center_Coord());
  848. bool found = false;
  849. /*
  850. ** Sweep through the cells between the target and the unit, looking for
  851. ** a cell that the unit can enter but which is also within weapon range
  852. ** of the target. If after a reasonable search, no appropriate cell could
  853. ** be found, then the target will be assigned as the movement destination
  854. ** and let "the chips fall where they may."
  855. */
  856. for (int range = maxrange; range > 0x0080; range -= 0x0100) {
  857. static int _angles[] = {0, 8, -8, 16, -16, 24, -24, 32, -32, 48, -48, 64, -64};
  858. for (int index = 0; index < (sizeof(_angles)/sizeof(_angles[0])); index++) {
  859. trycoord = Coord_Move(tcoord, (DirType)(dir + _angles[index]), range);
  860. if (::Distance(trycoord, tcoord) < range) {
  861. trycell = Coord_Cell(trycoord);
  862. if (Can_Enter_Cell(trycell) <= MOVE_CLOAK && Map.In_Radar(trycell)) {
  863. found = true;
  864. break;
  865. }
  866. }
  867. }
  868. if (found) break;
  869. }
  870. /*
  871. ** If a suitable intermediate location was found, then head toward it.
  872. ** Otherwise, head toward the enemy unit directly.
  873. */
  874. if (found) {
  875. Assign_Destination(::As_Target(trycell));
  876. } else {
  877. Assign_Destination(TarCom);
  878. }
  879. }
  880. }
  881. }
  882. /***********************************************************************************************
  883. * FootClass::Mission_Guard_Area -- Causes unit to guard an area about twice weapon range. *
  884. * *
  885. * This mission routine causes the unit to scan for targets out to twice its weapon range *
  886. * from the home point. If a target was found, then it will be attacked. The unit will *
  887. * chase the target until it gets up to to its weapon range from the home position. *
  888. * In that case, it will return to home position and start scanning for another target. *
  889. * *
  890. * INPUT: none *
  891. * *
  892. * OUTPUT: Returns with time delay before calling this routine again. *
  893. * *
  894. * WARNINGS: none *
  895. * *
  896. * HISTORY: *
  897. * 12/23/1994 JLB : Created. *
  898. * 07/27/1995 JLB : Greatly simplified. *
  899. *=============================================================================================*/
  900. int FootClass::Mission_Guard_Area(void)
  901. {
  902. if (What_Am_I() == RTTI_UNIT && ((UnitClass *)this)->Class->IsToHarvest) {
  903. Assign_Mission(MISSION_HARVEST);
  904. return(1+Random_Pick(1, 10));
  905. }
  906. /*
  907. ** Ensure that the archive target is valid.
  908. */
  909. if (!Target_Legal(ArchiveTarget)) {
  910. ArchiveTarget = ::As_Target(Coord_Cell(Coord));
  911. }
  912. /*
  913. ** Make sure that the unit has not strayed too far from the home position.
  914. ** If it has, then race back to it.
  915. */
  916. int maxrange = MAX(Weapon_Range(0), Weapon_Range(1))+0x0100;
  917. if (!Target_Legal(NavCom) && (Distance(ArchiveTarget) > maxrange || (!Target_Legal(TarCom) && Distance(ArchiveTarget) > 0x0200))) {
  918. Assign_Target(TARGET_NONE);
  919. Assign_Destination(ArchiveTarget);
  920. }
  921. if (!Target_Legal(TarCom)) {
  922. COORDINATE old = Coord;
  923. Coord = As_Coord(ArchiveTarget);
  924. Target_Something_Nearby(THREAT_AREA);
  925. Coord = old;
  926. if (Target_Legal(TarCom)) return(1);
  927. } else {
  928. Approach_Target();
  929. }
  930. return(TICKS_PER_SECOND+Random_Picky((int)0, (int)4, (char*)NULL, (int)0));
  931. }
  932. /***********************************************************************************************
  933. * FootClass::Unlimbo -- Unlimbos object and performs special fixups. *
  934. * *
  935. * This routine will make sure that the home position for the foot class object gets *
  936. * reset. This is necessary since the home position may change depending on the unit's *
  937. * transition between limbo and non-limbo condition. *
  938. * *
  939. * INPUT: coord -- The coordinate to unlimbo the unit at. *
  940. * *
  941. * dir -- The initial direction to give the unit. *
  942. * *
  943. * OUTPUT: bool; Was the unit unlimboed successfully? *
  944. * *
  945. * WARNINGS: none *
  946. * *
  947. * HISTORY: *
  948. * 12/23/1994 JLB : Created. *
  949. *=============================================================================================*/
  950. bool FootClass::Unlimbo(COORDINATE coord, DirType dir)
  951. {
  952. /*
  953. ** Try to unlimbo the unit.
  954. */
  955. if (TechnoClass::Unlimbo(coord, dir)) {
  956. /*
  957. ** Mobile units are always revealed to the house that owns them.
  958. */
  959. Revealed(House);
  960. /*
  961. ** Start in a still (non-moving) state.
  962. */
  963. Path[0] = FACING_NONE;
  964. return(true);
  965. }
  966. return(false);
  967. }
  968. /***********************************************************************************************
  969. * FootClass::Assign_Mission -- Assign mission to foot class object. *
  970. * *
  971. * When a new mission is assigned, any precalculated path should be truncated. This is *
  972. * in anticipation that the new mission will result in a change of path. *
  973. * *
  974. * INPUT: order -- The new mission to assign to the unit. *
  975. * *
  976. * OUTPUT: none *
  977. * *
  978. * WARNINGS: none *
  979. * *
  980. * HISTORY: *
  981. * 12/29/1994 JLB : Created. *
  982. *=============================================================================================*/
  983. void FootClass::Assign_Mission(MissionType order)
  984. {
  985. if (What_Am_I() != RTTI_UNIT || *(UnitClass*)this != UNIT_GUNBOAT) {
  986. Path[0] = FACING_NONE;
  987. }
  988. TechnoClass::Assign_Mission(order);
  989. }
  990. /***********************************************************************************************
  991. * FootClass::Limbo -- Intercepts limbo event and handles FootClass processing. *
  992. * *
  993. * When an object of FootClass type is limboed, then it must be removed from any team *
  994. * it may be a member of. *
  995. * *
  996. * INPUT: none *
  997. * *
  998. * OUTPUT: bool; Was the object successfully limboed? *
  999. * *
  1000. * WARNINGS: none *
  1001. * *
  1002. * HISTORY: *
  1003. * 12/29/1994 JLB : Created. *
  1004. *=============================================================================================*/
  1005. bool FootClass::Limbo(void)
  1006. {
  1007. if (!IsInLimbo) {
  1008. if (Team) {
  1009. Team->Remove(this);
  1010. }
  1011. }
  1012. return(TechnoClass::Limbo());
  1013. }
  1014. /***********************************************************************************************
  1015. * FootClass::Take_Damage -- Handles taking damage to this object. *
  1016. * *
  1017. * This routine intercepts the damage assigned to this object and if this object is *
  1018. * a member of a team, it informs the team that the damage has occurred. The team may *
  1019. * change it's priority or action based on this event. *
  1020. * *
  1021. * INPUT: damage -- The damage points inflicted on the unit. *
  1022. * *
  1023. * distance -- The distance from the point of damage to the unit itself. *
  1024. * *
  1025. * warhead -- The type of damage that is inflicted. *
  1026. * *
  1027. * source -- The purpitrator of the damage. By knowing who caused the damage, *
  1028. * the team know's who to "get even with". *
  1029. * *
  1030. * OUTPUT: Returns with the result type of the damage. *
  1031. * *
  1032. * WARNINGS: none *
  1033. * *
  1034. * HISTORY: *
  1035. * 12/30/1994 JLB : Created. *
  1036. *=============================================================================================*/
  1037. ResultType FootClass::Take_Damage(int & damage, int distance, WarheadType warhead, TechnoClass * source)
  1038. {
  1039. ResultType result = TechnoClass::Take_Damage(damage, distance, warhead, source);
  1040. if (result != RESULT_NONE && Team) {
  1041. if (GameToPlay != GAME_NORMAL || (source && !House->Is_Ally(source))) {
  1042. Team->Took_Damage(this, result, source);
  1043. }
  1044. } else {
  1045. if (result != RESULT_DESTROYED) {
  1046. /*
  1047. ** Determine if the target that is current being attacked has a weapon that can
  1048. ** do harm to a ground based unit. This information is needed so that an appropriate
  1049. ** response will occur when damage is taken.
  1050. */
  1051. WeaponType weap = WEAPON_NONE;
  1052. if (As_Techno(TarCom)) {
  1053. weap = As_Techno(TarCom)->Techno_Type_Class()->Primary;
  1054. }
  1055. bool tweap = (weap != WEAPON_NONE && weap != WEAPON_NIKE);
  1056. /*
  1057. ** This ensures that if a unit is in sticky mode, then it will snap out of
  1058. ** it when it takes damage.
  1059. */
  1060. if (source && Mission == MISSION_STICKY) {
  1061. Enter_Idle_Mode();
  1062. }
  1063. /*
  1064. ** If this object is not part of a team and it can retaliate for the damage, then have
  1065. ** it try to do so. This prevents it from just sitting there and taking damage.
  1066. */
  1067. if (
  1068. source &&
  1069. !House->Is_Ally(source) &&
  1070. Techno_Type_Class()->Primary != WEAPON_NONE &&
  1071. (source->What_Am_I() != RTTI_AIRCRAFT || BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) &&
  1072. (!Target_Legal(TarCom) || ((!House->IsHuman || Special.IsSmartDefense) && (!tweap || !In_Range(TarCom)))) &&
  1073. // !Target_Legal(NavCom) &&
  1074. (Mission == MISSION_AMBUSH ||
  1075. Mission == MISSION_GUARD ||
  1076. Mission == MISSION_RESCUE ||
  1077. Mission == MISSION_GUARD_AREA ||
  1078. Mission == MISSION_ATTACK ||
  1079. Mission == MISSION_TIMED_HUNT)) {
  1080. /*
  1081. ** Assign the source of the damage as the new target. This occurs for the computer
  1082. ** controled units. For the player, this only occurs if the source of the damage
  1083. ** is within range.
  1084. */
  1085. if (!House->IsHuman) {
  1086. /*
  1087. ** If this unit is in TIMED_HUNT (multiplayer computer-controlled)
  1088. ** mode, "snap out of it" into HUNT mode; otherwise, assign
  1089. ** HUNT as the next mission through the normal mission queue.
  1090. */
  1091. if (Mission == MISSION_TIMED_HUNT) {
  1092. Set_Mission(MISSION_HUNT);
  1093. } else {
  1094. Assign_Mission(MISSION_HUNT);
  1095. }
  1096. Assign_Target(source->As_Target());
  1097. } else {
  1098. if (In_Range(source)) {
  1099. Assign_Target(source->As_Target());
  1100. } else {
  1101. /*
  1102. ** Simple retaliation cannot occur because the source of the damage
  1103. ** is too far away. If scatter logic is enabled, then scatter now.
  1104. */
  1105. if (Special.IsScatter) {
  1106. Scatter(0, true);
  1107. }
  1108. }
  1109. }
  1110. } else {
  1111. /*
  1112. ** If this object isn't doing anything important, then scatter.
  1113. */
  1114. if (!IsDriving && !Target_Legal(TarCom) && !Target_Legal(NavCom) && Special.IsScatter && What_Am_I() != RTTI_AIRCRAFT) {
  1115. Scatter(0, true);
  1116. }
  1117. }
  1118. }
  1119. }
  1120. return(result);
  1121. }
  1122. /***********************************************************************************************
  1123. * FootClass::Active_Click_With -- Intiates attack or move according to target clicked on. *
  1124. * *
  1125. * At this level, the object is known to have the ability to attack or move to the *
  1126. * target specified (in theory). Perform the attack or move as indicated. *
  1127. * *
  1128. * INPUT: target -- The target clicked upon that will precipitate action. *
  1129. * *
  1130. * OUTPUT: Returns with the type of action performed. *
  1131. * *
  1132. * WARNINGS: none *
  1133. * *
  1134. * HISTORY: *
  1135. * 01/06/1995 JLB : Created. *
  1136. *=============================================================================================*/
  1137. void FootClass::Active_Click_With(ActionType action, ObjectClass * object)
  1138. {
  1139. switch (action) {
  1140. case ACTION_GUARD_AREA:
  1141. if (Can_Player_Fire() && Can_Player_Move()) {
  1142. Player_Assign_Mission(MISSION_GUARD_AREA, object->As_Target());
  1143. }
  1144. break;
  1145. case ACTION_SELF:
  1146. Player_Assign_Mission(MISSION_UNLOAD);
  1147. break;
  1148. case ACTION_ATTACK:
  1149. if (Can_Player_Fire()) {
  1150. Player_Assign_Mission(MISSION_ATTACK, object->As_Target());
  1151. }
  1152. break;
  1153. case ACTION_ENTER:
  1154. if (Can_Player_Move() && object && object->Is_Techno() && !((RadioClass *)object)->In_Radio_Contact()) {
  1155. Player_Assign_Mission(MISSION_ENTER, TARGET_NONE, object->As_Target());
  1156. }
  1157. break;
  1158. case ACTION_CAPTURE:
  1159. if (Can_Player_Move()) {
  1160. Player_Assign_Mission(MISSION_CAPTURE, TARGET_NONE, object->As_Target());
  1161. }
  1162. break;
  1163. case ACTION_SABOTAGE:
  1164. if (Can_Player_Move()) {
  1165. Player_Assign_Mission(MISSION_SABOTAGE, TARGET_NONE, object->As_Target());
  1166. }
  1167. break;
  1168. case ACTION_NOMOVE:
  1169. case ACTION_MOVE:
  1170. if (Can_Player_Move()) {
  1171. Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, object->As_Target());
  1172. }
  1173. break;
  1174. default:
  1175. break;
  1176. }
  1177. }
  1178. /***********************************************************************************************
  1179. * FootClass::Active_Click_With -- Performs action as a result of left mouse click. *
  1180. * *
  1181. * This routine performs the action requested when the left mouse button was clicked over *
  1182. * a cell. Typically, this is just a move command. *
  1183. * *
  1184. * INPUT: action -- The predetermined action that should occur. *
  1185. * *
  1186. * cell -- The cell number that the action should occur at. *
  1187. * *
  1188. * OUTPUT: none *
  1189. * *
  1190. * WARNINGS: none *
  1191. * *
  1192. * HISTORY: *
  1193. * 01/19/1995 JLB : Created. *
  1194. *=============================================================================================*/
  1195. void FootClass::Active_Click_With(ActionType action, CELL cell)
  1196. {
  1197. switch (action) {
  1198. case ACTION_HARVEST:
  1199. Player_Assign_Mission(MISSION_HARVEST, TARGET_NONE, ::As_Target(cell));
  1200. break;
  1201. case ACTION_MOVE:
  1202. if (AllowVoice) {
  1203. COORDINATE coord = Map.Pixel_To_Coord(Get_Mouse_X(), Get_Mouse_Y());
  1204. OutList.Add(EventClass(ANIM_MOVE_FLASH, PlayerPtr->Class->House, coord));
  1205. }
  1206. // Fall into next case.
  1207. case ACTION_NOMOVE:
  1208. if (What_Am_I() != RTTI_AIRCRAFT || Map[cell].IsVisible) {
  1209. Player_Assign_Mission(MISSION_MOVE, TARGET_NONE, ::As_Target(cell));
  1210. }
  1211. break;
  1212. case ACTION_ATTACK:
  1213. Player_Assign_Mission(MISSION_ATTACK, ::As_Target(cell));
  1214. break;
  1215. }
  1216. }
  1217. /***********************************************************************************************
  1218. * FootClass::Per_Cell_Process -- Perform action based on once-per-cell condition. *
  1219. * *
  1220. * This routine is called as this object moves from cell to cell. When the center of the *
  1221. * cell is reached, check to see if any trigger should be sprung. For moving units, reduce *
  1222. * the path to the distance to the target. This forces path recalculation in an effort to *
  1223. * avoid units passing each other. *
  1224. * *
  1225. * INPUT: center -- Is this the center of the cell? *
  1226. * *
  1227. * OUTPUT: none *
  1228. * *
  1229. * WARNINGS: none *
  1230. * *
  1231. * HISTORY: *
  1232. * 05/08/1995 JLB : Created. *
  1233. * 07/08/1995 JLB : Handles generic enter trigger event. *
  1234. * 07/16/1995 JLB : If next to a scanner and cloaked, then shimmer. *
  1235. *=============================================================================================*/
  1236. void FootClass::Per_Cell_Process(bool center)
  1237. {
  1238. // if (center) {
  1239. /*
  1240. ** Clear any unloading flag if necessary.
  1241. */
  1242. IsUnloading = false;
  1243. /*
  1244. ** If adjacent to an enemy building that has the ability to reveal a stealth tank,
  1245. ** then shimmer the cloaked object.
  1246. */
  1247. if (Cloak == CLOAKED) {
  1248. for (FacingType face = FACING_N; face < FACING_COUNT; face++) {
  1249. CELL cell = Adjacent_Cell(Coord_Cell(Coord), face);
  1250. if (Map.In_Radar(cell)) {
  1251. TechnoClass const * techno = Map[cell].Cell_Techno();
  1252. if (techno && !House->Is_Ally(techno) && techno->Techno_Type_Class()->IsScanner) {
  1253. Do_Shimmer();
  1254. break;
  1255. }
  1256. }
  1257. }
  1258. }
  1259. /*
  1260. ** Shorten the path if the target is now within weapon range of this
  1261. ** unit and this unit is on an attack type mission.
  1262. */
  1263. if (What_Am_I() != RTTI_UNIT || *((UnitClass *)this) != UNIT_GUNBOAT) {
  1264. bool inrange = In_Range(TarCom);
  1265. TechnoClass const * techno = As_Techno(TarCom);
  1266. if (techno && techno->What_Am_I() != RTTI_BUILDING) {
  1267. inrange = In_Range(((FootClass const *)techno)->Likely_Coord());
  1268. }
  1269. if (Target_Legal(TarCom) && (Mission == MISSION_RESCUE || Mission == MISSION_GUARD_AREA || Mission == MISSION_ATTACK || Mission == MISSION_HUNT) && inrange) {
  1270. Assign_Destination(TARGET_NONE);
  1271. Path[0] = FACING_NONE;
  1272. }
  1273. }
  1274. /*
  1275. ** Trigger event associated with the player entering the cell.
  1276. */
  1277. TriggerClass * trigger = Map[Coord_Cell(Coord)].Get_Trigger();
  1278. if (Cloak != CLOAKED && trigger && trigger->House == Owner()) {
  1279. trigger->Spring(EVENT_PLAYER_ENTERED, Coord_Cell(Coord));
  1280. }
  1281. // }
  1282. TechnoClass::Per_Cell_Process(center);
  1283. }
  1284. /***************************************************************************
  1285. * FootClass::Override_Mission -- temporarily overides a units mission *
  1286. * *
  1287. * *
  1288. * *
  1289. * INPUT: MissionType mission - the mission we want to overide *
  1290. * TARGET tarcom - the new target we want to overide *
  1291. * TARGET navcom - the new navigation point to overide *
  1292. * *
  1293. * OUTPUT: none *
  1294. * *
  1295. * WARNINGS: If a mission is already overidden, the current mission is *
  1296. * just re-assigned. *
  1297. * *
  1298. * HISTORY: *
  1299. * 04/28/1995 PWG : Created. *
  1300. *=========================================================================*/
  1301. void FootClass::Override_Mission(MissionType mission, TARGET tarcom, TARGET navcom)
  1302. {
  1303. SuspendedNavCom = NavCom;
  1304. TechnoClass::Override_Mission(mission, tarcom, navcom);
  1305. Assign_Destination(navcom);
  1306. }
  1307. /***************************************************************************
  1308. * FootClass::Restore_Mission -- Restores an overidden mission *
  1309. * *
  1310. * INPUT: none *
  1311. * *
  1312. * OUTPUT: none *
  1313. * *
  1314. * WARNINGS: none *
  1315. * *
  1316. * HISTORY: *
  1317. * 04/28/1995 PWG : Created. *
  1318. *=========================================================================*/
  1319. bool FootClass::Restore_Mission(void)
  1320. {
  1321. if (TechnoClass::Restore_Mission()) {
  1322. Assign_Destination(SuspendedNavCom);
  1323. return(true);
  1324. }
  1325. return(false);
  1326. }
  1327. /***********************************************************************************************
  1328. * FootClass::Receive_Message -- Movement related radio messages are handled here. *
  1329. * *
  1330. * This routine handles radio message that are related to movement. These are used for *
  1331. * complex coordinated maneuvers. *
  1332. * *
  1333. * INPUT: from -- Pointer to the originator of this radio message. *
  1334. * *
  1335. * message -- The radio message that is being received. *
  1336. * *
  1337. * param -- The optional parameter (could be a movement destination). *
  1338. * *
  1339. * OUTPUT: Returns with the radio response appropriate to the message received. Usually the *
  1340. * response is RADIO_ROGER. *
  1341. * *
  1342. * WARNINGS: none *
  1343. * *
  1344. * HISTORY: *
  1345. * 05/14/1995 JLB : Created. *
  1346. *=============================================================================================*/
  1347. RadioMessageType FootClass::Receive_Message(RadioClass * from, RadioMessageType message, long & param)
  1348. {
  1349. switch (message) {
  1350. /*
  1351. ** Intercept the repair request and if this object is moving, then no repair
  1352. ** is possible.
  1353. */
  1354. case RADIO_REPAIR:
  1355. if (Target_Legal(NavCom)) return(RADIO_NEGATIVE);
  1356. break;
  1357. /*
  1358. ** Something bad has happened to the object in contact with. Abort any coordinated
  1359. ** activity with this object. Basically, ... run away! Run away!
  1360. */
  1361. case RADIO_RUN_AWAY:
  1362. if (In_Radio_Contact()) {
  1363. if (NavCom == Contact_With_Whom()->As_Target()) {
  1364. Assign_Destination(TARGET_NONE);
  1365. }
  1366. }
  1367. break;
  1368. /*
  1369. ** Checks to see if this unit needs to move somewhere. If it is already in motion,
  1370. ** then it doesn't need furthur movement instructions.
  1371. */
  1372. case RADIO_NEED_TO_MOVE:
  1373. param = (long)NavCom;
  1374. if (!Target_Legal(NavCom)) {
  1375. return(RADIO_ROGER);
  1376. }
  1377. return(RADIO_NEGATIVE);
  1378. /*
  1379. ** Radio request to move to location specified. Typically this is used
  1380. ** for complex loading and unloading missions.
  1381. */
  1382. case RADIO_MOVE_HERE:
  1383. if (NavCom != (TARGET)param) {
  1384. if (::As_Target(Coord_Cell(Coord)) == (TARGET)param) {
  1385. return(RADIO_YEA_NOW_WHAT);
  1386. } else {
  1387. if (Mission == MISSION_GUARD && MissionQueue == MISSION_NONE) {
  1388. Assign_Mission(MISSION_MOVE);
  1389. }
  1390. Assign_Destination((TARGET)param);
  1391. }
  1392. }
  1393. return(RADIO_ROGER);
  1394. /*
  1395. ** Requests if this unit is trying to cooperatively load up. Typically, this occurs
  1396. ** for passengers and when vehicles need to be repaired.
  1397. */
  1398. case RADIO_TRYING_TO_LOAD:
  1399. if (Mission == MISSION_ENTER || MissionQueue == MISSION_ENTER) {
  1400. TechnoClass::Receive_Message(from, message, param);
  1401. return(RADIO_ROGER);
  1402. }
  1403. break;
  1404. }
  1405. return(TechnoClass::Receive_Message(from, message, param));
  1406. }
  1407. /***********************************************************************************************
  1408. * FootClass::Mission_Enter -- Enter (cooperatively) mission handler. *
  1409. * *
  1410. * This mission handler will cooperatively coordinate the object to maneuver into the *
  1411. * object it is in radio contact with. This is used by infantry when they wish to load *
  1412. * into an APC as well as by vehicles when they wish to enter a repair facility. *
  1413. * *
  1414. * INPUT: none *
  1415. * *
  1416. * OUTPUT: Returns the number of game ticks before this routine should be called again. *
  1417. * *
  1418. * WARNINGS: none *
  1419. * *
  1420. * HISTORY: *
  1421. * 05/15/1995 JLB : Created. *
  1422. *=============================================================================================*/
  1423. int FootClass::Mission_Enter(void)
  1424. {
  1425. /*
  1426. ** If radio contact has not yet been established with the transport, try to
  1427. ** establish contact now.
  1428. */
  1429. if (!In_Radio_Contact()) {
  1430. TechnoClass * techno = As_Techno(ArchiveTarget);
  1431. if (!techno) techno = As_Techno(NavCom);
  1432. if (techno) {
  1433. /*
  1434. ** If the transport is already in radio contact, do nothing. Try to
  1435. ** establish radio contact later.
  1436. */
  1437. if (Transmit_Message(RADIO_HELLO, techno) != RADIO_ROGER) {
  1438. ArchiveTarget = TARGET_NONE;
  1439. Enter_Idle_Mode();
  1440. } else {
  1441. Assign_Destination(TARGET_NONE);
  1442. }
  1443. } else {
  1444. ArchiveTarget = TARGET_NONE;
  1445. Enter_Idle_Mode();
  1446. }
  1447. } else {
  1448. /*
  1449. ** Since radio contact exists with the transport, maintain a dialogue so that
  1450. ** the transport can give proper instructions to the passenger.
  1451. */
  1452. if (Transmit_Message(RADIO_DOCKING) != RADIO_ROGER) {
  1453. Transmit_Message(RADIO_OVER_OUT);
  1454. Enter_Idle_Mode();
  1455. }
  1456. }
  1457. return(TICKS_PER_SECOND/2);
  1458. }
  1459. /***********************************************************************************************
  1460. z * FootClass::Assign_Destination -- Assigns specified destination to NavCom. *
  1461. * *
  1462. * This routine will assign the specified target to the navigation computer. No legality *
  1463. * checks are performed. *
  1464. * *
  1465. * INPUT: target -- The target value to assign to the navigation computer. *
  1466. * *
  1467. * OUTPUT: none *
  1468. * *
  1469. * WARNINGS: none *
  1470. * *
  1471. * HISTORY: *
  1472. * 07/08/1995 JLB : Created. *
  1473. *=============================================================================================*/
  1474. void FootClass::Assign_Destination(TARGET target)
  1475. {
  1476. NavCom = target;
  1477. }
  1478. /***********************************************************************************************
  1479. * FootClass::Detach_All -- Removes this object from the game system. *
  1480. * *
  1481. * This routine will remove this object from the game system. This routine is called when *
  1482. * this object is about to be deleted. All other objects should no longer reference this *
  1483. * object in that case. *
  1484. * *
  1485. * INPUT: none *
  1486. * *
  1487. * OUTPUT: none *
  1488. * *
  1489. * WARNINGS: none *
  1490. * *
  1491. * HISTORY: *
  1492. * 07/08/1995 JLB : Created. *
  1493. *=============================================================================================*/
  1494. void FootClass::Detach_All(bool all)
  1495. {
  1496. if (Team) Team->Remove(this);
  1497. Team = NULL;
  1498. TechnoClass::Detach_All(all);
  1499. }
  1500. /***********************************************************************************************
  1501. * FootClass::Rescue_Mission -- Calls this unit to the rescue. *
  1502. * *
  1503. * This routine is called when the house determines that it should attack the specified *
  1504. * target. This routine will determine if it can attack the target specified and if so, *
  1505. * the amount of power it can throw at it. This returned power value is used to allow *
  1506. * intelligent distribution of retaliation. *
  1507. * *
  1508. * INPUT: target -- The target that this object just might be assigned to attack and thus *
  1509. * how much power it can bring to bear should be returned. *
  1510. * *
  1511. * OUTPUT: Returns with the amount of power that this object can bring to bear against the *
  1512. * potential target specified. *
  1513. * *
  1514. * WARNINGS: none *
  1515. * *
  1516. * HISTORY: *
  1517. * 07/08/1995 JLB : Created. *
  1518. *=============================================================================================*/
  1519. int FootClass::Rescue_Mission(TARGET tarcom)
  1520. {
  1521. /*
  1522. ** If the target specified is not legal, then it cannot be attacked. Always return
  1523. ** zero in this case.
  1524. */
  1525. if (!Target_Legal(tarcom)) return(0);
  1526. /*
  1527. ** If the unit is already assigned to destroy the tarcom then we need
  1528. ** to return a negative value which tells the computer to lower the
  1529. ** desired threat rating.
  1530. */
  1531. if (TarCom == tarcom) {
  1532. return(-Risk());
  1533. }
  1534. /*
  1535. ** If the unit is currently attacking a target that has a weapon then we
  1536. ** cannot abandon it as it will destroy us if we return to base.
  1537. */
  1538. if (Target_Legal(TarCom)) {
  1539. TechnoClass * techno = As_Techno(TarCom);
  1540. if (techno && techno->Techno_Type_Class()->Primary != WEAPON_NONE) {
  1541. return(0);
  1542. }
  1543. }
  1544. /*
  1545. ** If the unit is in a harvest mission or is currently attacking
  1546. ** something, or is not very effective, then it will be of no help
  1547. ** at all.
  1548. */
  1549. if (Team || Mission == MISSION_HARVEST || !Risk()) {
  1550. return(0);
  1551. }
  1552. /*
  1553. ** Find the distance to the target modified by the range. If the
  1554. ** the distance is 0, then things are ok.
  1555. */
  1556. int dist = Distance(tarcom) - Weapon_Range(0);
  1557. int threat = Risk() * 256;
  1558. int speed = -1;
  1559. if (dist > 0) {
  1560. /*
  1561. ** Next we need to figure out how fast the unit moves because this
  1562. ** decreases the distance penalty.
  1563. */
  1564. speed = Max((unsigned)Techno_Type_Class()->MaxSpeed, (unsigned)1);
  1565. int ratio = (speed > 0) ? Max(dist / speed, 1) : 1;
  1566. /*
  1567. ** Finally modify the threat by the distance the unit is away.
  1568. */
  1569. threat = Max(threat/ratio, 1);
  1570. }
  1571. return(threat);
  1572. }
  1573. /***********************************************************************************************
  1574. * FootClass::Death_Announcement -- Announces the death of a unit. *
  1575. * *
  1576. * This routine is called when a unit (infantry, vehicle, or aircraft) is destroyed. *
  1577. * *
  1578. * INPUT: source -- The purpetrator of this death. *
  1579. * *
  1580. * OUTPUT: none *
  1581. * *
  1582. * WARNINGS: none *
  1583. * *
  1584. * HISTORY: *
  1585. * 07/01/1995 JLB : Created. *
  1586. *=============================================================================================*/
  1587. void FootClass::Death_Announcement(TechnoClass const * source) const
  1588. {
  1589. if (IsDiscoveredByPlayer || IsOwnedByPlayer) {
  1590. if (!source || source->What_Am_I() != RTTI_INFANTRY || *((InfantryClass const *)source) != INFANTRY_RAMBO) {
  1591. if (What_Am_I() == RTTI_INFANTRY && ((InfantryTypeClass const &)Class_Of()).IsCivilian && !((InfantryClass *)this)->IsTechnician) {
  1592. if (Options.IsDeathAnnounce) Speak(VOX_DEAD_CIV);
  1593. } else {
  1594. if (House != PlayerPtr && GameToPlay != GAME_NORMAL) {
  1595. if (Options.IsDeathAnnounce) Speak(VOX_ENEMY_UNIT);
  1596. } else {
  1597. if (House == PlayerPtr || Options.IsDeathAnnounce) {
  1598. if (!Options.IsDeathAnnounce) {
  1599. Speak(VOX_UNIT_LOST);
  1600. } else {
  1601. switch (House->ActLike) {
  1602. case HOUSE_GOOD:
  1603. Speak(VOX_DEAD_GDI);
  1604. break;
  1605. case HOUSE_BAD:
  1606. Speak(VOX_DEAD_NOD);
  1607. break;
  1608. default:
  1609. break;
  1610. }
  1611. }
  1612. }
  1613. }
  1614. }
  1615. }
  1616. }
  1617. }
  1618. /***********************************************************************************************
  1619. * FootClass::Greatest_Threat -- Fetches the greatest threat to this object. *
  1620. * *
  1621. * This routine will return with the greatest threat (best target) for this object. For *
  1622. * movable ground object, they won't automatically return ANY target if this object is *
  1623. * cloaked. Otherwise, cloaking is relatively useless. *
  1624. * *
  1625. * INPUT: method -- The request method (bit flags) to use when scanning for a target. *
  1626. * *
  1627. * OUTPUT: Returns with the best target to attack. If there is no target that qualifies, then *
  1628. * TARGET_NONE is returned. *
  1629. * *
  1630. * WARNINGS: none *
  1631. * *
  1632. * HISTORY: *
  1633. * 07/08/1995 JLB : Created. *
  1634. *=============================================================================================*/
  1635. TARGET FootClass::Greatest_Threat(ThreatType method) const
  1636. {
  1637. /*
  1638. ** If this object can cloak, then it won't select a target automatically.
  1639. */
  1640. if (House->IsHuman && IsCloakable && Mission == MISSION_GUARD) {
  1641. return(TARGET_NONE);
  1642. }
  1643. if (Techno_Type_Class()->Primary != WEAPON_NONE && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Primary].Fires).IsAntiAircraft) {
  1644. method = method | THREAT_AIR;
  1645. }
  1646. if (Techno_Type_Class()->Secondary != WEAPON_NONE && BulletTypeClass::As_Reference(Weapons[Techno_Type_Class()->Secondary].Fires).IsAntiAircraft) {
  1647. method = method | THREAT_AIR;
  1648. }
  1649. return(TechnoClass::Greatest_Threat(method|THREAT_GROUND));
  1650. }
  1651. /***********************************************************************************************
  1652. * FootClass::Detach -- Detaches a target from tracking systems. *
  1653. * *
  1654. * This routine will detach the specified target from the tracking systems of this object. *
  1655. * It will be removed from the navigation computer and any queued mission record. *
  1656. * *
  1657. * INPUT: target -- The target to be removed from this object. *
  1658. * *
  1659. * all -- Is the unit really about to be eliminated? If this is true then even *
  1660. * friendly contact (i.e., radio) must be eliminated. *
  1661. * *
  1662. * OUTPUT: none *
  1663. * *
  1664. * WARNINGS: none *
  1665. * *
  1666. * HISTORY: *
  1667. * 07/18/1995 JLB : Created. *
  1668. *=============================================================================================*/
  1669. void FootClass::Detach(TARGET target, bool all)
  1670. {
  1671. TechnoClass::Detach(target, all);
  1672. if (!SpecialFlag) {
  1673. if (ArchiveTarget == target) {
  1674. ArchiveTarget = TARGET_NONE;
  1675. }
  1676. }
  1677. if (SuspendedNavCom == target) {
  1678. SuspendedNavCom = TARGET_NONE;
  1679. SuspendedMission = MISSION_NONE;
  1680. }
  1681. /*
  1682. ** If the navigation computer is assigned to the target, then the navigation
  1683. ** computer must be cleared.
  1684. */
  1685. if (NavCom == target) {
  1686. NavCom = TARGET_NONE;
  1687. Path[0] = FACING_NONE;
  1688. Restore_Mission();
  1689. }
  1690. /*
  1691. ** If targeting the specified object and this unit is obviously heading
  1692. ** toward the target to get within range, then abort the path.
  1693. */
  1694. if (TarCom == target && House->IsHuman) {
  1695. Path[0] = FACING_NONE;
  1696. }
  1697. }
  1698. /***********************************************************************************************
  1699. * FootClass::Offload_Tiberium_Bail -- Fetches the Tiberium to offload per step. *
  1700. * *
  1701. * This routine is called when a packet/package/bail of Tiberium needs to be offloaded *
  1702. * from the object. This function is overridden for those objects that can contain *
  1703. * Tiberium. *
  1704. * *
  1705. * INPUT: none *
  1706. * *
  1707. * OUTPUT: Returns with the number of credits offloaded from the object. *
  1708. * *
  1709. * WARNINGS: This routine must be called multiple times in order to completely offload the *
  1710. * Tiberium. When this routine return 0, all Tiberium has been offloaded. *
  1711. * *
  1712. * HISTORY: *
  1713. * 07/19/1995 JLB : Created. *
  1714. *=============================================================================================*/
  1715. int FootClass::Offload_Tiberium_Bail(void)
  1716. {
  1717. return(0);
  1718. }
  1719. /***********************************************************************************************
  1720. * FootClass::Can_Enter_Cell -- Checks to see if the object can enter cell specified. *
  1721. * *
  1722. * This routine examines the specified cell to see if the object can enter it. This *
  1723. * function is to be overridden for objects that could have the possibility of not being *
  1724. * allowed to enter the cell. Typical objects at the FootClass level always return *
  1725. * MOVE_OK. *
  1726. * *
  1727. * INPUT: cell -- The cell to examine. *
  1728. * *
  1729. * facing -- The direction that this cell might be entered from. *
  1730. * *
  1731. * OUTPUT: Returns with the move check result type. This will be MOVE_OK if there is not *
  1732. * blockage. There are various other values that represent other blockage types. *
  1733. * The value returned will indicatd the most severe reason why entry into the cell *
  1734. * is blocked. *
  1735. * *
  1736. * WARNINGS: none *
  1737. * *
  1738. * HISTORY: *
  1739. * 07/19/1995 JLB : Created. *
  1740. *=============================================================================================*/
  1741. MoveType FootClass::Can_Enter_Cell(CELL , FacingType) const
  1742. {
  1743. return MOVE_OK;
  1744. }
  1745. /***********************************************************************************************
  1746. * FootClass::Can_Demolish -- Checks to see if this object can be sold back. *
  1747. * *
  1748. * This routine determines if it is legal to sell the object back. A foot class object can *
  1749. * only be sold back if it is sitting on a repair bay. *
  1750. * *
  1751. * INPUT: none *
  1752. * *
  1753. * OUTPUT: Was the object successfully sold back? *
  1754. * *
  1755. * WARNINGS: none *
  1756. * *
  1757. * HISTORY: *
  1758. * 08/13/1995 JLB : Created. *
  1759. *=============================================================================================*/
  1760. bool FootClass::Can_Demolish(void) const
  1761. {
  1762. switch (What_Am_I()) {
  1763. case RTTI_UNIT:
  1764. case RTTI_AIRCRAFT:
  1765. if (In_Radio_Contact() &&
  1766. Contact_With_Whom()->What_Am_I() == RTTI_BUILDING &&
  1767. *((BuildingClass *)Contact_With_Whom()) == STRUCT_REPAIR &&
  1768. Distance(Contact_With_Whom()) < 0x0080) {
  1769. return(true);
  1770. }
  1771. break;
  1772. default:
  1773. break;
  1774. }
  1775. return(TechnoClass::Can_Demolish());
  1776. }
  1777. /***********************************************************************************************
  1778. * FootClass::Sell_Back -- Causes this object to be sold back. *
  1779. * *
  1780. * When an object is sold back, a certain amount of money is refunded to the owner and then *
  1781. * the object is removed from the game system. *
  1782. * *
  1783. * INPUT: control -- The action to perform. The only supported action is "1", which means *
  1784. * to sell back. *
  1785. * *
  1786. * OUTPUT: none *
  1787. * *
  1788. * WARNINGS: none *
  1789. * *
  1790. * HISTORY: *
  1791. * 08/13/1995 JLB : Created. *
  1792. *=============================================================================================*/
  1793. void FootClass::Sell_Back(int control)
  1794. {
  1795. if (control != 0) {
  1796. if (House == PlayerPtr) {
  1797. Sound_Effect(VOC_CASHTURN);
  1798. }
  1799. House->Refund_Money(Refund_Amount());
  1800. Stun();
  1801. Limbo();
  1802. delete this;
  1803. }
  1804. }
  1805. /***********************************************************************************************
  1806. * FootClass::Likely_Coord -- Fetches the coordinate the object will be at shortly. *
  1807. * *
  1808. * This routine comes in handy when determining where a travelling object will be at *
  1809. * when considering the amount of time it would take for a normal unit to travel one cell. *
  1810. * Using this information, an intelligent "approach target" logic can be employed. *
  1811. * *
  1812. * INPUT: none *
  1813. * *
  1814. * OUTPUT: Returns with the coordinate the object is at or soon will be. *
  1815. * *
  1816. * WARNINGS: none *
  1817. * *
  1818. * HISTORY: *
  1819. * 08/13/1995 JLB : Created. *
  1820. *=============================================================================================*/
  1821. COORDINATE FootClass::Likely_Coord(void) const
  1822. {
  1823. if (Head_To_Coord()) {
  1824. return(Head_To_Coord());
  1825. }
  1826. return(Target_Coord());
  1827. }