REINF.CPP 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. //
  2. // Copyright 2020 Electronic Arts Inc.
  3. //
  4. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
  5. // software: you can redistribute it and/or modify it under the terms of
  6. // the GNU General Public License as published by the Free Software Foundation,
  7. // either version 3 of the License, or (at your option) any later version.
  8. // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
  9. // in the hope that it will be useful, but with permitted additional restrictions
  10. // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
  11. // distributed with this program. You should have received a copy of the
  12. // GNU General Public License along with permitted additional restrictions
  13. // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
  14. /* $Header: /CounterStrike/REINF.CPP 1 3/03/97 10:25a Joe_bostic $ */
  15. /***********************************************************************************************
  16. *** 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 ***
  17. ***********************************************************************************************
  18. * *
  19. * Project Name : Command & Conquer *
  20. * *
  21. * File Name : REINF.CPP *
  22. * *
  23. * Programmer : Joe L. Bostic *
  24. * *
  25. * Start Date : May 24, 1994 *
  26. * *
  27. * Last Update : July 26, 1996 [JLB] *
  28. * *
  29. *---------------------------------------------------------------------------------------------*
  30. * Functions: *
  31. * Create_Air_Reinforcement -- Creates air strike reinforcement *
  32. * Create_Special_Reinforcement -- Ad hoc reinforcement handler. *
  33. * Do_Reinforcements -- Create and place a reinforcement team. *
  34. * _Consists_Only_Of_Infantry -- Determine if this group consists only of infantry. *
  35. * _Create_Group -- Create a group given team specification. *
  36. * _Pop_Group_Out_Of_Object -- Process popping the group out of the object. *
  37. * _Who_Can_Pop_Out_Of -- Find a suitable host for these reinforcements. *
  38. * _Need_To_Take -- Examines unit to determine if it should be confiscated. *
  39. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  40. #include "function.h"
  41. /***********************************************************************************************
  42. * _Pop_Group_Out_Of_Object -- Process popping the group out of the object. *
  43. * *
  44. * This routine will cause the group to pop out of the object specified. *
  45. * *
  46. * INPUT: group -- Pointer to the first object in the group to be popped out. *
  47. * *
  48. * object -- Pointer to the object that the group is to pop out of. *
  49. * *
  50. * OUTPUT: bool; Was the group popped out of the specified object? *
  51. * *
  52. * WARNINGS: none *
  53. * *
  54. * HISTORY: *
  55. * 06/25/1996 JLB : Created. *
  56. *=============================================================================================*/
  57. static bool _Pop_Group_Out_Of_Object(FootClass * group, TechnoClass * object)
  58. {
  59. assert(group != NULL && object != NULL);
  60. int quantity = 0;
  61. /*
  62. ** Take every infantry member of this group and detach it from the group list
  63. ** and then make it pop out of the candidate source.
  64. */
  65. while (group != NULL) {
  66. TechnoClass * todo = group;
  67. group = (FootClass *)(ObjectClass *)group->Next;
  68. todo->Next = NULL;
  69. switch (object->What_Am_I()) {
  70. /*
  71. ** The infantry just walks out of a building.
  72. */
  73. case RTTI_BUILDING:
  74. if (object->Exit_Object(todo) != 2) {
  75. delete todo;
  76. } else {
  77. ++quantity;
  78. }
  79. break;
  80. /*
  81. ** Infantry get attached to transport vehicles and then unload.
  82. */
  83. case RTTI_UNIT:
  84. case RTTI_VESSEL:
  85. case RTTI_AIRCRAFT:
  86. object->Attach((FootClass *)todo);
  87. object->Assign_Mission(MISSION_UNLOAD);
  88. ++quantity;
  89. break;
  90. default:
  91. delete todo;
  92. break;
  93. }
  94. }
  95. return (quantity != 0);
  96. }
  97. /***********************************************************************************************
  98. * _Need_To_Take -- Examines unit to determine if it should be confiscated. *
  99. * *
  100. * The unit is examined and if the owning house needs to confiscate it, then this routine *
  101. * will return TRUE. In other cases, the unit should be left to its own devices. *
  102. * *
  103. * INPUT: unit -- Pointer to the object to examine. *
  104. * *
  105. * OUTPUT: bool; Should the object be confiscated by the player so that it becomes one of *
  106. * his normal game objects? *
  107. * *
  108. * WARNINGS: none *
  109. * *
  110. * HISTORY: *
  111. * 07/26/1996 JLB : Created. *
  112. *=============================================================================================*/
  113. bool _Need_To_Take(AircraftClass const * air)
  114. {
  115. if (*air == AIRCRAFT_YAK || *air == AIRCRAFT_MIG) {
  116. int deficit = air->House->Get_Quantity(STRUCT_AIRSTRIP);
  117. // int deficit = air->House->Get_Quantity(STRUCT_AIRSTRIP) - (air->House->Get_Quantity(AIRCRAFT_YAK)+air->House->Get_Quantity(AIRCRAFT_MIG));
  118. /*
  119. ** Loop through all aircraft and subtract all the ones that are NOT loaners.
  120. */
  121. for (int index = 0; index < Aircraft.Count(); index++) {
  122. AircraftClass const * airptr = Aircraft.Ptr(index);
  123. if ((*airptr == AIRCRAFT_YAK || *airptr == AIRCRAFT_MIG) && airptr->IsOwnedByPlayer && !airptr->IsALoaner && airptr != air) {
  124. deficit -= 1;
  125. if (deficit == 0) break;
  126. }
  127. }
  128. if (deficit > 0) return(true);
  129. }
  130. return(false);
  131. }
  132. /***********************************************************************************************
  133. * _Create_Group -- Create a group given team specification. *
  134. * *
  135. * This routine will create all members of the group as specified by the team type. *
  136. * *
  137. * INPUT: teamtype -- Pointer to the team type that specifies what objects should be *
  138. * created in this group. *
  139. * *
  140. * OUTPUT: Returns with a pointer to the first member of the group created. *
  141. * *
  142. * WARNINGS: none *
  143. * *
  144. * HISTORY: *
  145. * 06/25/1996 JLB : Created. *
  146. *=============================================================================================*/
  147. static FootClass * _Create_Group(TeamTypeClass const * teamtype)
  148. {
  149. assert(teamtype != NULL);
  150. TeamClass * team = new TeamClass(teamtype);
  151. if (team != NULL) {
  152. team->Force_Active();
  153. }
  154. bool hasunload = false;
  155. for (int tm = 0; tm < teamtype->MissionCount; tm++) {
  156. if (teamtype->MissionList[tm].Mission == TMISSION_UNLOAD) {
  157. hasunload = true;
  158. break;
  159. }
  160. }
  161. /*
  162. ** Now that the official source for the reinforcement has been determined, the
  163. ** objects themselves must be created.
  164. */
  165. FootClass * transport = NULL;
  166. FootClass * object = NULL;
  167. for (int index = 0; index < teamtype->ClassCount; index++) {
  168. TechnoTypeClass const * tclass = teamtype->Members[index].Class;
  169. for (int sub = 0; sub < teamtype->Members[index].Quantity; sub++) {
  170. ScenarioInit++;
  171. FootClass * temp = (FootClass *)tclass->Create_One_Of(HouseClass::As_Pointer(teamtype->House));
  172. ScenarioInit--;
  173. if (temp != NULL) {
  174. /*
  175. ** Add the member to the team.
  176. */
  177. if (team != NULL) {
  178. ScenarioInit++;
  179. bool ok = team->Add(temp);
  180. //Mono_Printf("Added to team = %d.\n", ok);Keyboard->Get();
  181. ScenarioInit--;
  182. temp->IsInitiated = true;
  183. }
  184. if (temp->What_Am_I() == RTTI_AIRCRAFT && !_Need_To_Take((AircraftClass const *)temp)) {
  185. temp->IsALoaner = true;
  186. }
  187. /*
  188. ** Build the list of transporters and passengers.
  189. */
  190. if (tclass->Max_Passengers() > 0) {
  191. /*
  192. ** Link to the list of transports.
  193. */
  194. temp->Next = transport;
  195. transport = temp;
  196. } else {
  197. /*
  198. ** Link to the list of normal objects.
  199. */
  200. temp->Next = object;
  201. object = temp;
  202. }
  203. }
  204. }
  205. }
  206. /*
  207. ** If the group consists of transports and normal objects, then assign the normal
  208. ** objects to be passengers on the transport.
  209. */
  210. if (transport != NULL && object != NULL) {
  211. transport->Attach(object);
  212. /*
  213. ** HACK ALERT! If the this team has an unload mission, then flag the transport
  214. ** as a loaner so that it will exit from the map when the unload process is
  215. ** complete, but only if the transport is an aircraft type.
  216. */
  217. if (hasunload && (transport->What_Am_I() == RTTI_AIRCRAFT || transport->What_Am_I() == RTTI_VESSEL)) {
  218. transport->IsALoaner = true;
  219. }
  220. }
  221. /*
  222. ** For JUST transport helicopters, consider the loaner a gift if there are
  223. ** no passengers.
  224. */
  225. if (transport != NULL && object == NULL && transport->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass *)transport) == AIRCRAFT_TRANSPORT) {
  226. transport->IsALoaner = false;
  227. }
  228. if (transport == 0 && object == 0) {
  229. if (team != NULL) delete team;
  230. return(NULL);
  231. }
  232. /*
  233. ** If this group consists only of non-transport object, then just return with a pointer
  234. ** to the first member of the group.
  235. */
  236. if (transport == NULL) {
  237. return(object);
  238. }
  239. return(transport);
  240. }
  241. /***********************************************************************************************
  242. * _Consists_Only_Of_Infantry -- Determine if this group consists only of infantry. *
  243. * *
  244. * Use this to determine if the specified group only contains infantry. Such a reinforcement*
  245. * group is a candidate for popping out of a building or transport vehicle rather than *
  246. * driving/walking/sailing/flying onto the map under its own power. *
  247. * *
  248. * INPUT: first -- Pointer to the first object in the group to examine. *
  249. * *
  250. * OUTPUT: bool; Is the entire group composed of infantry type units? *
  251. * *
  252. * WARNINGS: none *
  253. * *
  254. * HISTORY: *
  255. * 06/25/1996 JLB : Created. *
  256. *=============================================================================================*/
  257. static bool _Consists_Only_Of_Infantry(FootClass const * first)
  258. {
  259. while (first != NULL) {
  260. if (first->What_Am_I() != RTTI_INFANTRY) {
  261. return(false);
  262. }
  263. first = (FootClass const *)((ObjectClass *)first->Next);
  264. }
  265. return(true);
  266. }
  267. /***********************************************************************************************
  268. * _Who_Can_Pop_Out_Of -- Find a suitable host for these reinforcements. *
  269. * *
  270. * This routine is used to scan nearby locations to determine if there is a suitable host *
  271. * for these reinforcements to "pop out of" (apologies to Aliens). Typical hosts include *
  272. * buildings and transport vehicles (of any kind). *
  273. * *
  274. * INPUT: origin -- The cell that should be scanned from. Only this location and immediate *
  275. * adjacent locations will be scanned. *
  276. * *
  277. * OUTPUT: Returns with a pointer to a suitable host. If none could be found then NULL is *
  278. * returned. *
  279. * *
  280. * WARNINGS: none *
  281. * *
  282. * HISTORY: *
  283. * 06/25/1996 JLB : Created. *
  284. *=============================================================================================*/
  285. static TechnoClass * _Who_Can_Pop_Out_Of(CELL origin)
  286. {
  287. CellClass * cellptr = &Map[origin];
  288. TechnoClass * candidate = NULL;
  289. for (int f = -1; f < 8; f++) {
  290. CellClass * ptr = cellptr;
  291. if (f != -1) {
  292. ptr = ptr->Adjacent_Cell(FacingType(f));
  293. if (!ptr) continue;
  294. }
  295. BuildingClass * building = ptr->Cell_Building();
  296. if (building && building->Strength > 0) {
  297. candidate = building;
  298. }
  299. UnitClass * unit = ptr->Cell_Unit();
  300. if (unit && unit->Strength && unit->Class->Max_Passengers() > 0) {
  301. return(unit);
  302. }
  303. }
  304. return(candidate);
  305. }
  306. /***********************************************************************************************
  307. * Do_Reinforcements -- Create and place a reinforcement team. *
  308. * *
  309. * This routine is called when a reinforcement team must be created and placed on the map. *
  310. * It will create all members of the team and place them at the location determined from *
  311. * the team composition. The reinforcement team should follow team orders until overridden *
  312. * by AI or player intervention. *
  313. * *
  314. * INPUT: teamtype -- Pointer to the team type to create as a reinforcement. *
  315. * *
  316. * OUTPUT: Was the reinforcement successfully created and placed? *
  317. * *
  318. * WARNINGS: none *
  319. * *
  320. * HISTORY: *
  321. * 05/08/1995 JLB : Created. *
  322. * 05/18/1995 JLB : Returns success or failure condition. *
  323. * 06/19/1995 JLB : Announces reinforcements. *
  324. * 02/15/1996 JLB : Recognizes team reinforcement location. *
  325. *=============================================================================================*/
  326. bool Do_Reinforcements(TeamTypeClass const * teamtype)
  327. {
  328. assert(teamtype != 0);
  329. /*
  330. ** perform some preliminary checks for validity.
  331. */
  332. if (!teamtype || !teamtype->ClassCount) return(false);
  333. /*
  334. ** HACK ALERT!
  335. ** Give this team an attack waypoint mission that will attack the waypoint location of this
  336. ** team if there are no team missions previously assigned.
  337. */
  338. if (teamtype->MissionCount == 0) {
  339. TeamTypeClass * tt = (TeamTypeClass *)teamtype;
  340. tt->MissionCount = 1;
  341. tt->MissionList[0].Mission = TMISSION_ATT_WAYPT;
  342. tt->MissionList[0].Data.Value = teamtype->Origin;
  343. }
  344. FootClass * object = _Create_Group(teamtype);
  345. //Mono_Printf("%d-%s (object=%p, team=%d).\n", __LINE__, __FILE__, object, object->Team.Is_Valid());Keyboard->Get();
  346. /*
  347. ** Bail on this reinforcement if no reinforcements could be created.
  348. ** This is probably because the object maximum was reached.
  349. */
  350. if (!object) {
  351. return(false);
  352. }
  353. /*
  354. ** Special case code to handle infantry types that run from a building. This presumes
  355. ** that infantry are never a transport (which is safe to do).
  356. */
  357. if (object != NULL && teamtype->Origin != -1 && _Consists_Only_Of_Infantry(object)) {
  358. /*
  359. ** Search for an object that these infantry can pop out of.
  360. */
  361. TechnoClass * candidate = _Who_Can_Pop_Out_Of(Scen.Waypoint[teamtype->Origin]);
  362. if (candidate != NULL) {
  363. return(_Pop_Group_Out_Of_Object(object, candidate));
  364. }
  365. }
  366. /*
  367. ** The reinforcements must be delivered the old fashioned way -- by moving onto the
  368. ** map using their own power. First order of business is to determine where they
  369. ** should arrive from.
  370. */
  371. SourceType source = HouseClass::As_Pointer(teamtype->House)->Control.Edge;
  372. if (source == SOURCE_NONE) {
  373. source = SOURCE_NORTH;
  374. }
  375. /*
  376. ** Pick the location where the reinforcements appear and then place
  377. ** them there.
  378. */
  379. bool placed = false;
  380. FacingType eface = (FacingType)(source << 1); // Facing to enter map.
  381. CELL cell = Map.Calculated_Cell(source, teamtype->Origin, -1, object->Techno_Type_Class()->Speed);
  382. #ifdef FIXIT_ANTS
  383. /*
  384. ** For the ants, they will pop out of the ant hill directly.
  385. */
  386. if (teamtype->Origin != -1 && object->What_Am_I() == RTTI_UNIT &&
  387. (*((UnitClass*)object) == UNIT_ANT1 ||
  388. *((UnitClass*)object) == UNIT_ANT2 ||
  389. *((UnitClass*)object) == UNIT_ANT3)) {
  390. CELL newcell = Scen.Waypoint[teamtype->Origin];
  391. if (newcell != -1) {
  392. if (Map[newcell].TType == TEMPLATE_HILL01) {
  393. cell = newcell;
  394. }
  395. }
  396. }
  397. #endif
  398. CELL newcell = cell;
  399. FootClass * o = (FootClass *)(ObjectClass *)object->Next;
  400. object->Next = 0;
  401. bool okvoice = false;
  402. while (newcell > 0 && object != NULL) {
  403. DirType desiredfacing = Facing_Dir(eface);
  404. if (object->What_Am_I() == RTTI_AIRCRAFT) {
  405. desiredfacing = Random_Pick(DIR_N, DIR_MAX);
  406. }
  407. ScenarioInit++;
  408. if (object->Unlimbo(Cell_Coord(newcell), desiredfacing)) {
  409. okvoice = true;
  410. /*
  411. ** If this object is part of a team, then the mission for this
  412. ** object will be guard. The team handler will assign the proper
  413. ** mission that it should follow.
  414. */
  415. if (object->What_Am_I() != RTTI_AIRCRAFT) {
  416. object->Assign_Mission(MISSION_GUARD);
  417. object->Commence();
  418. }
  419. } else {
  420. /*
  421. ** Could not unlimbo at location specified so find an adjacent location that it can
  422. ** be unlimboed at. If this fails, then abort the whole placement process.
  423. */
  424. FacingType adj;
  425. for (adj = FACING_N; adj < FACING_COUNT; adj++) {
  426. CELL trycell = Adjacent_Cell(newcell, adj);
  427. if (!Map.In_Radar(trycell) && object->Can_Enter_Cell(trycell, adj) == MOVE_OK) {
  428. newcell = trycell;
  429. break;
  430. }
  431. }
  432. if (adj < FACING_COUNT) continue;
  433. newcell = 0;
  434. }
  435. ScenarioInit--;
  436. object = o;
  437. if (object != NULL) {
  438. o = (FootClass *)(ObjectClass *)object->Next;
  439. object->Next = 0;
  440. }
  441. }
  442. /*
  443. ** If there are still objects that could not be placed, then delete them.
  444. */
  445. if (o != NULL) {
  446. while (o != NULL) {
  447. FootClass * old = o;
  448. o = (FootClass *)(ObjectClass *)o->Next;
  449. old->Next = 0;
  450. delete old;
  451. }
  452. }
  453. /*
  454. ** Announce when the reinforcements have arrived.
  455. */
  456. if (okvoice && teamtype->House == PlayerPtr->Class->House) {
  457. Speak(VOX_REINFORCEMENTS, NULL, newcell ? Cell_Coord(newcell) : 0);
  458. }
  459. return(true);
  460. }
  461. /***********************************************************************************************
  462. * Create_Special_Reinforcement -- Ad hoc reinforcement handler. *
  463. * *
  464. * Use this routine to bring on a reinforcement that hasn't been anticipated by the trigger *
  465. * system. An example of this would be replacement harvesters or airfield ordered units. *
  466. * The appropriate transport is created (if necessary) and a mission is assigned such that *
  467. * the object will legally bring itself onto the playing field. *
  468. * *
  469. * INPUT: house -- The owner of this reinforcement. *
  470. * *
  471. * type -- The object to bring on. *
  472. * *
  473. * another -- This is reserved for the transport class in those cases where the *
  474. * transport MUST be forced to a specific type. *
  475. * *
  476. * mission -- The mission to assign this reinforcement team. *
  477. * *
  478. * argument -- Optional team mission argument (usually a waypoint). *
  479. * *
  480. * OUTPUT: Was the special reinforcement created without error? *
  481. * *
  482. * WARNINGS: This routine will fail if a team type cannot be created. *
  483. * *
  484. * HISTORY: *
  485. * 07/04/1995 JLB : Created. *
  486. *=============================================================================================*/
  487. bool Create_Special_Reinforcement(HouseClass * house, TechnoTypeClass const * type, TechnoTypeClass const * another, TeamMissionType mission, int argument)
  488. {
  489. assert(house != 0);
  490. assert(type != 0);
  491. if (house && type) {
  492. TeamTypeClass * team = new TeamTypeClass();
  493. if (team) {
  494. /*
  495. ** If there is no overridden mission assign to this special reinforcement, then
  496. ** we must assign something. If not, the reinforcement will just sit at the edge
  497. ** of the map.
  498. */
  499. if (!another && mission == TMISSION_NONE) {
  500. mission = TMISSION_MOVECELL;
  501. argument = Map.Calculated_Cell(house->Control.Edge);
  502. }
  503. /*
  504. ** Fill in the team characteristics.
  505. */
  506. strcpy((char *)&team->IniName[0], "TEMP");
  507. team->IsReinforcable = false;
  508. team->IsTransient = true;
  509. team->ClassCount = 1;
  510. team->Members[0].Class = type;
  511. team->Members[0].Quantity = 1;
  512. team->MissionCount = 1;
  513. if (mission == TMISSION_NONE) {
  514. team->MissionList[0].Mission = TMISSION_UNLOAD;
  515. team->MissionList[0].Data.Value = WAYPT_REINF;
  516. } else {
  517. team->MissionList[0].Mission = mission;
  518. team->MissionList[0].Data.Value = argument;
  519. }
  520. team->House = house->Class->House;
  521. if (another) {
  522. team->ClassCount++;
  523. team->Members[1].Class = another;
  524. team->Members[1].Quantity = 1;
  525. }
  526. bool ok = Do_Reinforcements(team);
  527. if (!ok) delete team;
  528. return(ok);
  529. }
  530. }
  531. return(false);
  532. }
  533. /***********************************************************************************************
  534. * Create_Air_Reinforcement -- Creates air strike reinforcement *
  535. * *
  536. * This routine is used to launch an airstrike. It will create the necessary aircraft and *
  537. * assign them to attack the target specified. This routine bypasses the normal *
  538. * reinforcement logic since it doesn't need the sophistication of unloading and following *
  539. * team mission lists. *
  540. * *
  541. * INPUT: house -- The perpetrator of this air strike. *
  542. * *
  543. * air -- The type of aircraft to make up this airstrike. *
  544. * *
  545. * number -- The number of aircraft in this airstrike. *
  546. * *
  547. * mission -- The mission to assign the aircraft. *
  548. * *
  549. * tarcom -- The target to assign these aircraft. *
  550. * *
  551. * navcom -- The navigation target to assign (if necessary). *
  552. * *
  553. * OUTPUT: Returns the number of aircraft created for this airstrike. *
  554. * *
  555. * WARNINGS: none *
  556. * *
  557. * HISTORY: *
  558. * 07/04/1995 JLB : Commented. *
  559. *=============================================================================================*/
  560. int Create_Air_Reinforcement(HouseClass * house, AircraftType air, int number, MissionType mission, TARGET tarcom, TARGET navcom, InfantryType passenger)
  561. {
  562. assert(house != 0);
  563. assert((unsigned)air < AIRCRAFT_COUNT);
  564. assert(number != 0);
  565. assert((unsigned)mission < MISSION_COUNT);
  566. /*
  567. ** Get a pointer to the class of the object that we are going to create.
  568. */
  569. TechnoTypeClass const * type = (TechnoTypeClass *)&AircraftTypeClass::As_Reference(air);
  570. /*
  571. ** Abort the airstrike if Tanya is the passenger and she's dead.
  572. */
  573. if (passenger == INFANTRY_TANYA && IsTanyaDead) {
  574. number = 0;
  575. }
  576. /*
  577. ** Loop through the number of objects we are supposed to create and
  578. ** create and place them on the map.
  579. */
  580. int sub;
  581. for (sub = 0; sub < number; sub++) {
  582. /*
  583. ** Create one of the required objects. If this fails we could have
  584. ** a real problem.
  585. */
  586. ScenarioInit++;
  587. TechnoClass * obj = (TechnoClass *)type->Create_One_Of(house);
  588. ScenarioInit--;
  589. if (!obj) return(sub);
  590. /*
  591. ** Flying objects always have the IsALoaner bit set.
  592. */
  593. obj->IsALoaner = true;
  594. /*
  595. ** Find a cell for the object to come in on. This is stolen from the
  596. ** the code that handles a SOURCE_AIR in the normal logic.
  597. */
  598. SourceType source = house->Control.Edge;
  599. switch (source) {
  600. case SOURCE_NORTH:
  601. case SOURCE_EAST:
  602. case SOURCE_SOUTH:
  603. case SOURCE_WEST:
  604. break;
  605. default:
  606. source = SOURCE_NORTH;
  607. break;
  608. }
  609. CELL newcell = Map.Calculated_Cell(source, -1, -1, SPEED_WINGED);
  610. /*
  611. ** Try and place the object onto the map.
  612. */
  613. ScenarioInit++;
  614. int placed = obj->Unlimbo(Cell_Coord(newcell), DIR_N);
  615. ScenarioInit--;
  616. if (placed) {
  617. /*
  618. ** If we succeeded in placing the obj onto the map then
  619. ** now we need to give it a mission and destination.
  620. */
  621. obj->Assign_Mission(mission);
  622. /*
  623. ** If a navcom was specified then set it.
  624. */
  625. if (navcom != TARGET_NONE) {
  626. obj->Assign_Destination(navcom);
  627. }
  628. /*
  629. ** If a tarcom was specified then set it.
  630. */
  631. if (tarcom != TARGET_NONE) {
  632. obj->Assign_Target(tarcom);
  633. }
  634. /*
  635. ** Assign generic passenger value here. This value is used to determine
  636. ** if this aircraft should drop parachute reinforcements.
  637. */
  638. if (obj->What_Am_I() == RTTI_AIRCRAFT) {
  639. AircraftClass * aircraft = (AircraftClass *)obj;
  640. if (passenger != INFANTRY_NONE) {
  641. aircraft->Passenger = passenger;
  642. }
  643. // if (Passenger == INFANTRY_TANYA) {
  644. // aircraft->Ammo = 1;
  645. //aircraft->AttacksRemaining = 1;
  646. // }
  647. }
  648. /*
  649. ** Start the object into action.
  650. */
  651. obj->Commence();
  652. } else {
  653. delete obj;
  654. sub--;
  655. return(sub);
  656. }
  657. }
  658. return(sub);
  659. }