REINF.CPP 31 KB

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