CnC_Remastered_Collection

Command and Conquer: Red Alert
Log | Files | Refs | README | LICENSE

REINF.CPP (26376B)


      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 
      9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 
     10 // in the hope that it will be useful, but with permitted additional restrictions 
     11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 
     12 // distributed with this program. You should have received a copy of the 
     13 // GNU General Public License along with permitted additional restrictions 
     14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
     15 
     16 /* $Header:   F:\projects\c&c\vcs\code\reinf.cpv   2.17   16 Oct 1995 16:48:58   JOE_BOSTIC  $ */
     17 /***********************************************************************************************
     18  ***             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               *** 
     19  ***********************************************************************************************
     20  *                                                                                             *
     21  *                 Project Name : Command & Conquer                                            *
     22  *                                                                                             *
     23  *                    File Name : REINF.CPP                                                    *
     24  *                                                                                             *
     25  *                   Programmer : Joe L. Bostic                                                *
     26  *                                                                                             *
     27  *                   Start Date : May 24, 1994                                                 *
     28  *                                                                                             *
     29  *                  Last Update : July 4, 1995 [JLB]                                           *
     30  *                                                                                             *
     31  *---------------------------------------------------------------------------------------------*
     32  * Functions:                                                                                  *
     33  *   Create_Air_Reinforcement -- Creates air strike reinforcement                              * 
     34  *   Create_Special_Reinforcement -- Ad hoc reinforcement handler.                             * 
     35  *   Do_Reinforcements -- Create and place a reinforcement team.                               * 
     36  * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
     37 
     38 #include	"function.h"
     39 
     40 
     41 /*********************************************************************************************** 
     42  * Do_Reinforcements -- Create and place a reinforcement team.                                 * 
     43  *                                                                                             * 
     44  *    This routine is called when a reinforcement team must be created and placed on the map.  * 
     45  *    It will create all members of the team and place them at the location determined from    * 
     46  *    the team composition. The reinforcement team should follow team orders until overriden   * 
     47  *    by AI or player intervention.                                                            * 
     48  *                                                                                             * 
     49  * INPUT:   teamtype -- Pointer to the team type to create as a reinforcement.                 * 
     50  *                                                                                             * 
     51  * OUTPUT:  Was the reinforcement successfully created and placed?                             * 
     52  *                                                                                             * 
     53  * WARNINGS:   none                                                                            * 
     54  *                                                                                             * 
     55  * HISTORY:                                                                                    * 
     56  *   05/08/1995 JLB : Created.                                                                 * 
     57  *   05/18/1995 JLB : Returns success or failure condition.                                    * 
     58  *   06/19/1995 JLB : Announces reinforcements.                                                * 
     59  *=============================================================================================*/
     60 bool Do_Reinforcements(TeamTypeClass *teamtype)
     61 {
     62 	/*
     63 	**	preform some preliminary checks for validity.
     64 	*/
     65 	if (!teamtype || !teamtype->ClassCount) return(false);
     66 
     67 	/*
     68 	**	Create the controlling team. All the objects are grouped
     69 	**	under this team control. If there are no missions for this team
     70 	**	then don't actually create the team -- it won't serve a purpose.
     71 	*/
     72 	TeamClass * team = NULL;
     73 	if (teamtype->MissionCount) {
     74 		team = new TeamClass(teamtype, HouseClass::As_Pointer(teamtype->House));
     75 		if (!team) return(false);
     76 		team->Force_Active();
     77 	}
     78 
     79 	/*
     80 	**	Determine if this team contains its own transport. In such a case, the
     81 	**	transport is used as a loaner. This is only true, if there is other
     82 	**	objects to be transport. Without such cargo objects, then the transport
     83 	**	is presumed to be the reinforcement itself and thus should not be a
     84 	**	loaner.
     85 	*/
     86 	bool okvoice = true;						// Presume ok to announce reinforcement?
     87 	bool airtransport = false;				// Transport can fly in?
     88 	bool watertransport = false;			// Transport needs a beach to land at?
     89 	bool onlytransport = true;				// Just transport is in reinforcement?
     90 	bool hastransport = false;				// Group comes with transport?
     91 	int index;
     92 	for (index=0; index < teamtype->ClassCount; index++) {
     93 		if (teamtype->Class[index]->IsTransporter || teamtype->Class[index]->What_Am_I() == RTTI_AIRCRAFTTYPE) {
     94 			hastransport = true;
     95 			if (teamtype->Class[index]->What_Am_I() == RTTI_AIRCRAFTTYPE) {
     96 				airtransport = true;
     97 			} else {
     98 				watertransport = (((UnitTypeClass const *)teamtype->Class[index])->Type == UNIT_HOVER);
     99 			}
    100 		} else {
    101 			onlytransport = false;
    102 		}
    103 	}
    104 
    105 	/*
    106 	**	Now determine how the reinforcement should be delivered. This is largely determined
    107 	**	by whether there is a transport with the reinforcements.
    108 	*/
    109 	SourceType source = SOURCE_NONE;
    110 	if (airtransport) {
    111 		source = SOURCE_AIR;
    112 	} else {
    113 
    114 		if (watertransport) {
    115 			source = SOURCE_BEACH;
    116 		} else {
    117 			
    118 			/*
    119 			**	Special case for the gunboat. It always arrives according to the shipping source.
    120 			*/
    121 			if (teamtype->Class[0]->What_Am_I() == RTTI_UNITTYPE && ((UnitTypeClass const *)teamtype->Class[0])->Type == UNIT_GUNBOAT) {
    122 				source = SOURCE_SHIPPING;
    123 			} else {
    124 				source = HouseClass::As_Pointer(teamtype->House)->Edge;
    125 			}
    126 		}
    127 	}
    128 
    129 	/*
    130 	**	If we can't determine where the reinforcement should come from, then delete it
    131 	**	and return a failure condition.
    132 	*/
    133 	if (source == SOURCE_NONE) {
    134 		if (team) delete team;
    135 		return(false);
    136 	}
    137 
    138 	/*
    139 	**	Now that the official source for the reinforcement has been determined, the 
    140 	**	objects themselves must be created.
    141 	*/
    142 	TechnoClass * transport = NULL;
    143 	TechnoClass * object = NULL;
    144 	for (index = 0; index < teamtype->ClassCount; index++) {
    145 		TechnoTypeClass const * tclass = teamtype->Class[index];
    146 
    147 		for (int sub = 0; sub < teamtype->DesiredNum[index]; sub++) {
    148 			ScenarioInit++;
    149 			FootClass * temp = (FootClass *)tclass->Create_One_Of(HouseClass::As_Pointer(teamtype->House));
    150 			ScenarioInit--;
    151 
    152 			if (temp) {
    153 
    154 				/*
    155 				**	Add the object to the team. This is true even for the transports. The one
    156 				**	exception is for the hover lander which never becomes part of the team.
    157 				*/
    158 				if (team && (temp->What_Am_I() != RTTI_UNIT || *((UnitClass*)temp) != UNIT_HOVER)) {
    159 					ScenarioInit++;
    160 					team->Add(temp);
    161 					ScenarioInit--;
    162 				}
    163 
    164 				/*
    165 				**	Build the list of transporters and passengers.
    166 				*/
    167 				if (tclass->IsTransporter && (!airtransport || tclass->What_Am_I() == RTTI_AIRCRAFTTYPE)) {
    168 
    169 					/*
    170 					**	Transports are considered loaners if they are transporting 
    171 					**	something. They are presumed to only serve as a delivery
    172 					**	agent.
    173 					*/
    174 					if (!onlytransport && temp->What_Am_I() != RTTI_UNIT) {
    175 						temp->IsALoaner = true;
    176 					}
    177 
    178 					/*
    179 					**	Link to the list of transports.
    180 					*/
    181 					temp->Next = transport;
    182 					transport = temp;
    183 				} else {
    184 
    185 					/*
    186 					**	A-10s are always considered loaners since the player should
    187 					**	never be allowed to control them.
    188 					*/
    189 					if (temp->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass *)temp) == AIRCRAFT_A10) {
    190 						temp->IsALoaner = true;
    191 					}
    192 
    193 					/*
    194 					**	Link to the list of normal objects.
    195 					*/
    196 					temp->Next = object;
    197 					object = temp;
    198 				}
    199 			}
    200 		}
    201 	}
    202 
    203 	/*
    204 	**	Bail on this reinforcement if no reinforcements could be created.
    205 	**	This is probably because the object maximum was reached.
    206 	*/
    207 	if (!object && !transport) {
    208 		if (team) delete team;
    209 		return(false);
    210 	}
    211 
    212 	/*
    213 	**	Now it is time to place the objects on the map. If there is a transport, then the
    214 	**	transported objects must be placed inside the transport at this time as well.
    215 	*/
    216 	if (transport) {
    217 		if (object) {
    218 
    219 			/*
    220 			**	For cargo planes that carry reinforcements, don't announce arrival
    221 			**	when the transport is created. The announcement will occur when the
    222 			**	transport unloads.
    223 			*/
    224 			if (transport->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass *)transport) == AIRCRAFT_CARGO) {
    225 				okvoice = false;
    226 			}
    227 
    228 			transport->Attach((FootClass *)object);
    229 		}
    230 		object = transport;
    231 	}
    232 
    233 	/*
    234 	**	Pick the location where the reinforcements appear and then place
    235 	**	them there.
    236 	*/
    237 	bool placed = false;
    238 	CELL cell = 0;
    239 	FacingType eface;
    240 	switch (source) {
    241 
    242 		case SOURCE_SHIPPING:
    243 			cell = Map.Calculated_Cell(source, teamtype->House);
    244 			object->IsALoaner = true;
    245 			if (object->Unlimbo(Cell_Coord(cell), DIR_W)) {
    246 				object->Assign_Mission(MISSION_GUARD);
    247 				object->Assign_Destination(::As_Target(XY_Cell(Map.MapCellX-1, Cell_Y(Coord_Cell(object->Coord)) )));
    248 			} else {
    249 				if (team) delete team;
    250 				delete object;
    251 				return(false);
    252 			}
    253 			break;
    254 
    255 		case SOURCE_NORTH:
    256 		case SOURCE_SOUTH:
    257 		case SOURCE_EAST:
    258 		case SOURCE_WEST: {
    259 			eface = (FacingType)(source << 1);	// Facing to enter map.
    260 
    261 			if (airtransport) ScenarioInit++;
    262 			cell = Map.Calculated_Cell(source, teamtype->House);
    263 			if (airtransport) ScenarioInit--;
    264 			CELL newcell = cell;
    265 
    266 			FootClass * o = (FootClass *)object->Next;
    267 			object->Next = 0;
    268 			bool ok = true;
    269 			while (newcell > 0 && object) {
    270 				DirType desiredfacing = Facing_Dir(eface);
    271 				if (object->What_Am_I() == RTTI_AIRCRAFT) {
    272 					desiredfacing = Random_Pick(DIR_N, DIR_MAX);
    273 				}
    274 
    275 				if (ok && object->Unlimbo(Cell_Coord(newcell), desiredfacing)) {
    276 
    277 					/*
    278 					**	If this object is part of a team, then the mission for this
    279 					**	object will be guard. The team handler will assign the proper 
    280 					**	mission that it should follow.
    281 					*/
    282 					if (object->What_Am_I() == RTTI_AIRCRAFT) {
    283 						ok = false;
    284 					} else {
    285 						if (team) {
    286 							object->Assign_Mission(MISSION_GUARD);
    287 						} else {
    288 							object->Assign_Mission(MISSION_MOVE);
    289 							object->Assign_Destination(Adjacent_Cell(newcell, eface));
    290 						}
    291 						object->Commence();
    292 					}
    293 
    294 				} else {
    295 					ok = true;
    296 					
    297 					/*
    298 					**	Could not unlimbo at location specified so find an adjacent location that it can
    299 					**	be unlimboed at. If this fails, then abort the whole placement process.
    300 					*/
    301 					FacingType adj;
    302 					for (adj = FACING_N; adj < FACING_COUNT; adj++) {
    303 						CELL trycell = Adjacent_Cell(newcell, adj);
    304 						if (!Map.In_Radar(trycell) && object->Can_Enter_Cell(trycell, adj) == MOVE_OK) {
    305 							newcell = trycell;
    306 							break;
    307 						}
    308 					}
    309 					if (adj < FACING_COUNT) continue;
    310 					newcell = -1;
    311 				}
    312 
    313 				object = o;
    314 				if (object) {
    315 					o = (FootClass *)object->Next;
    316 					object->Next = 0;
    317 				}
    318 			}
    319 
    320 			/*
    321 			**	If there are still objects that could not be placed, then delete them.
    322 			*/
    323 			if (o) {
    324 				while (o) {
    325 					FootClass * old = o;
    326 					o = (FootClass *)o->Next;
    327 					old->Next = 0;
    328 
    329 					delete old;
    330 				}
    331 
    332 			}
    333 		}
    334 		break;
    335 
    336 		/*
    337 		**	Bring out the aircraft as separate "groups" of one.
    338 		*/
    339 		case SOURCE_AIR: {
    340 			AircraftClass * thisone = (AircraftClass *)object;
    341 			TARGET target = TARGET_NONE;
    342 			while (thisone) {
    343 				AircraftClass * next = (AircraftClass *)thisone->Next;
    344 
    345 				/*
    346 				**	Find a suitable map entry location. Cargo planes will try to find a cell that
    347 				**	exactly lines up with the airfield they will unload at.
    348 				*/
    349 				COORDINATE newcoord;
    350 				long reinforcement_delay = -1;
    351 				ScenarioInit++;
    352 				newcoord = Cell_Coord(Map.Calculated_Cell(HouseClass::As_Pointer(teamtype->House)->Edge, teamtype->House));
    353 				ScenarioInit--;
    354 				if (*thisone == AIRCRAFT_CARGO) {
    355 					BuildingClass const * building = thisone->Find_Docking_Bay(STRUCT_AIRSTRIP, false);
    356 					if (building) {
    357 						COORDINATE docking_coord = building->Docking_Coord();
    358 						const int border_x = Cell_To_Lepton(Map.MapCellX + Map.MapCellWidth) | 0x80;
    359 						if (Special.ModernBalance) {
    360 							/*
    361 							** Cargo plane takes 5 seconds to reach the airstrip on Normal (1.5x legacy), or (75 / 10) seconds at speed.
    362 							** Assumes a 45ms (1000 / 45 ticks per second) service rate.
    363 							*/
    364 							const int speed = AircraftTypeClass::As_Reference(AIRCRAFT_CARGO).MaxSpeed;
    365 							int spawn_x = Coord_X(docking_coord) + ((speed * 1000 * 75) / (45 * 10));
    366 							if (spawn_x > border_x) {
    367 								reinforcement_delay = (spawn_x - border_x) / speed;
    368 								spawn_x = border_x;
    369 							}
    370 							newcoord = XY_Coord(spawn_x, Coord_Y(docking_coord));
    371 						} else {
    372 							newcoord = XY_Coord(border_x, Coord_Y(docking_coord));
    373 						}
    374 						if (teamtype->MissionCount) {
    375 							teamtype->MissionList[0].Argument = building->As_Target();
    376 						}
    377 					} 
    378 				}
    379 				thisone->Next = 0;
    380 
    381 				ScenarioInit++;
    382 				placed = thisone->Unlimbo(newcoord, DIR_W);
    383 				if (Special.ModernBalance && reinforcement_delay >= 0) {
    384 					thisone->Set_Reinforcement_Delay(reinforcement_delay);
    385 				}
    386 				ScenarioInit--;
    387 				if (placed) {
    388 					if (!team) {
    389 						if (thisone->Class->IsFixedWing) {
    390 							thisone->Assign_Mission(MISSION_HUNT);
    391 							if (*thisone == AIRCRAFT_A10) {
    392 								/*
    393 								**	Groups of A10s always go after the same target initally.
    394 								*/
    395 								if (target == TARGET_NONE) {
    396 									target = thisone->Greatest_Threat(THREAT_NORMAL);
    397 								}
    398 								thisone->Assign_Target(target);
    399 							}
    400 						} else {
    401 							if (thisone->Class->IsTransporter && thisone->Is_Something_Attached()) {
    402 								thisone->Assign_Mission(MISSION_UNLOAD);
    403 							} else {
    404 								thisone->Assign_Mission(MISSION_MOVE);
    405 							}
    406 							thisone->Assign_Destination(::As_Target(Map.Calculated_Cell(source, teamtype->House)));
    407 						}
    408 						thisone->Commence();
    409 					}
    410 				} else {
    411 					delete thisone;
    412 				}
    413 
    414 				thisone = next;
    415 			}
    416 			if (!placed && team) delete team;
    417 
    418 
    419 			/*
    420 			**	Fixes bug that can happen if the reinforcement cannot be created.
    421 			**	This prevent "phantom" teams and team types from being left around.
    422 			*/
    423 			if (GameToPlay == GAME_NORMAL && !placed) return(false);
    424 
    425 		}
    426 		break;
    427 
    428 		case SOURCE_OCEAN:
    429 		case SOURCE_BEACH:
    430 			cell = Map.Calculated_Cell(SOURCE_BEACH, teamtype->House);
    431 			if (cell) {
    432 				CELL edge = XY_Cell(Cell_X(cell), Map.MapCellY+Map.MapCellHeight);
    433 
    434 				placed = object->Unlimbo(Cell_Coord(edge), DIR_N);
    435 				if (placed) {
    436 					if (!team) {
    437 						object->IsLocked = false;
    438 						object->Assign_Mission(MISSION_UNLOAD);
    439 						object->Commence();
    440 						object->Assign_Destination(::As_Target(cell));
    441 					}
    442 				} else {
    443 					if (team) delete team;
    444 					delete object;
    445 					return(false);
    446 				}
    447 			}
    448 			break;
    449 
    450 		default:
    451 			break;
    452 	}
    453 
    454 	/*
    455 	**	Announce when the reinforcements have arrived.
    456 	*/
    457 	if (okvoice && teamtype->House == PlayerPtr->Class->House) {
    458 		Speak(VOX_REINFORCEMENTS, NULL, cell ? Cell_Coord(cell) : 0);
    459 	}
    460 
    461 	return(true);
    462 }			
    463 
    464 
    465 /*********************************************************************************************** 
    466  * Create_Special_Reinforcement -- Ad hoc reinforcement handler.                               * 
    467  *                                                                                             * 
    468  *    Use this routine to bring on a reinforcement that hasn't been anticipated by the trigger * 
    469  *    system. An example of this would be replacement harvesters or airfield ordered units.    * 
    470  *    The appropriate transport is created (if necessary) and a mission is assigned such that  * 
    471  *    the object will legally bring itself onto the playing field.                             * 
    472  *                                                                                             * 
    473  * INPUT:   house    -- The owner of this reinforcement.                                       * 
    474  *                                                                                             * 
    475  *          type     -- The object to bring on.                                                * 
    476  *                                                                                             * 
    477  *          another  -- This is reserved for the transport class in those cases where the      * 
    478  *                      transport MUST be forced to a specific type.                           * 
    479  *                                                                                             * 
    480  *          mission  -- The mission to assign this reinforcement team.                         * 
    481  *                                                                                             * 
    482  *          argument -- Optional team mission argument (usually a waypoint).                   * 
    483  *                                                                                             * 
    484  * OUTPUT:  Was the special reinforcement created without error?                               * 
    485  *                                                                                             * 
    486  * WARNINGS:   This routine will fail if a team type cannot be created.                        * 
    487  *                                                                                             * 
    488  * HISTORY:                                                                                    * 
    489  *   07/04/1995 JLB : Created.                                                                 * 
    490  *=============================================================================================*/
    491 bool Create_Special_Reinforcement(HouseClass * house, TechnoTypeClass const * type, TechnoTypeClass const * another, TeamMissionType mission, int argument)
    492 {
    493 	if (house && type) {
    494 		TeamTypeClass * team = new TeamTypeClass();
    495 
    496 		if (team) {
    497 
    498 			/*
    499 			**	If a ground based reinforcement is desired, but the edge of the map that the
    500 			**	reinforcement will arrive at is completely covered with water, then add
    501 			**	a hover lander for transport.
    502 			*/
    503 			if (!another && (type->What_Am_I() == RTTI_UNITTYPE || type->What_Am_I() == RTTI_INFANTRYTYPE)) {
    504 
    505 				/*
    506 				**	Hover lander reinforcements can only arrive from the south. Yes, this is an
    507 				**	arbitrary limitation, but that's the way it is (for now).
    508 				*/
    509 				if (house->Edge == SOURCE_SOUTH) {
    510 					bool found = false;
    511 					for (int index = Map.MapCellX; index < Map.MapCellX+Map.MapCellWidth-1; index++) {
    512 						CELL cell = XY_Cell(index, Map.MapCellY+Map.MapCellHeight);
    513 						if (Map[cell].Is_Generally_Clear() && Map[cell-MAP_CELL_W].Is_Generally_Clear()) {
    514 							found = true;
    515 							break;
    516 						}
    517 					}
    518 
    519 					/*
    520 					**	No land route was found for the reinforcement to drive itself onto the
    521 					**	map. Assign it a hover lander. This presumes that if the south edge is
    522 					**	non drivable, it will have water there instead. Risky, but is not a 
    523 					**	problem with the current C&C maps.
    524 					*/
    525 					if (!found) {
    526 						mission = TMISSION_NONE;
    527 						another = &UnitTypeClass::As_Reference(UNIT_HOVER);
    528 					}
    529 				}
    530 
    531 				if (!another) {
    532 					mission = TMISSION_MOVECELL;
    533 					argument = Map.Calculated_Cell(SOURCE_AIR, house->Class->House);
    534 				}
    535 			}
    536 
    537 			/*
    538 			**	If there is no overridden mission assign to this special reinforcement, then
    539 			**	we must assign something. If not, the reinforcement will just sit at the edge
    540 			**	of the map.
    541 			*/
    542 			if (!another && mission == TMISSION_NONE) {
    543 				mission = TMISSION_MOVECELL;
    544 				argument = Map.Calculated_Cell(SOURCE_AIR, house->Class->House);
    545 			}
    546 
    547 			/*
    548 			**	Fill in the team characteristics.
    549 			*/
    550 			strcpy((char *)&team->IniName[0], "TEMP");
    551 			team->IsReinforcable = false;
    552 			team->IsTransient = true;
    553 			team->ClassCount = 1;
    554 			team->Class[0] = type;
    555 			team->DesiredNum[0] = 1;
    556 			team->MissionCount = 1;
    557 			if (mission == TMISSION_NONE) {
    558 				if (another && (another->What_Am_I() != RTTI_UNITTYPE || ((UnitTypeClass const *)another)->Type != UNIT_HOVER)) {
    559 					team->MissionList[0].Mission	= TMISSION_UNLOAD;
    560 					team->MissionList[0].Argument = WAYPT_REINF;
    561 				}
    562 			} else {
    563 				team->MissionList[0].Mission	= mission;
    564 				team->MissionList[0].Argument = argument;
    565 			}
    566 			team->House = house->Class->House;
    567 			if (another) {
    568 				team->ClassCount++;
    569 				team->Class[1] = another;
    570 				team->DesiredNum[1] = 1;
    571 			}
    572 
    573 			bool ok = Do_Reinforcements(team);
    574 			if (!ok && GameToPlay == GAME_NORMAL) {
    575 				delete team;
    576 			}
    577 			return(ok);
    578 		}
    579 	}
    580 	return(false);
    581 }
    582 
    583 
    584 /*********************************************************************************************** 
    585  * Create_Air_Reinforcement -- Creates air strike reinforcement                                * 
    586  *                                                                                             * 
    587  *    This routine is used to launch an airstrike. It will create the necessary aircraft and   * 
    588  *    assign them to attack the target specified. This routine bypasses the normal             * 
    589  *    reinforcement logic since it doesn't need the sophistication of unloading and following  * 
    590  *    team mission lists.                                                                      * 
    591  *                                                                                             * 
    592  * INPUT:   house    -- The purpetrator of this air strike.                                    * 
    593  *                                                                                             * 
    594  *          air      -- The type of aircraft to make up this airstrike.                        * 
    595  *                                                                                             * 
    596  *          number   -- The number of aircraft in this airstrike.                              * 
    597  *                                                                                             * 
    598  *          mission  -- The mission to assign the aircraft.                                    * 
    599  *                                                                                             * 
    600  *          tarcom   -- The target to assign these aircraft.                                   * 
    601  *                                                                                             * 
    602  *          navcom   -- The navigation target to assign (if necessary).                        * 
    603  *                                                                                             * 
    604  * OUTPUT:  Returns the number of aircraft created for this airstrike.                         * 
    605  *                                                                                             * 
    606  * WARNINGS:   none                                                                            * 
    607  *                                                                                             * 
    608  * HISTORY:                                                                                    * 
    609  *   07/04/1995 JLB : Commented.                                                               * 
    610  *=============================================================================================*/
    611 int Create_Air_Reinforcement(HouseClass *house, AircraftType air, int number, MissionType mission, TARGET tarcom, TARGET navcom)
    612 {
    613 	/*
    614 	** Get a pointer to the class of the object that we are going to create.
    615 	*/
    616 	TechnoTypeClass const * type = (TechnoTypeClass *)&AircraftTypeClass::As_Reference(air);
    617 
    618 	/*
    619 	** Loop through the number of objects we are supposed to create and
    620 	** 	create and place them on the map.
    621 	*/
    622 	int sub;
    623 	for (sub = 0; sub < number; sub++) {
    624 
    625 		/*
    626 		** Create one of the required objects.  If this fails we could have
    627 		** a real problem.
    628 		*/
    629 		ScenarioInit++;
    630 		TechnoClass * obj = (TechnoClass *)type->Create_One_Of(house);
    631 		ScenarioInit--;
    632 		if (!obj) return(sub);
    633 
    634 		/*
    635 		** Flying objects always have the IsALoaner bit set.
    636 		*/
    637 		obj->IsALoaner = true;
    638 
    639 		/* 
    640 		** Find a cell for the object to come in on.  This is stolen from the
    641 		** the code that handles a SOURCE_AIR in the normal logic.
    642 		*/
    643 		SourceType source = house->Edge;
    644 		switch (source) {
    645 			case SOURCE_NORTH:
    646 			case SOURCE_EAST:
    647 			case SOURCE_SOUTH:
    648 			case SOURCE_WEST:
    649 				break;
    650 
    651 			default:
    652 				source = SOURCE_NORTH;
    653 				break;
    654 		}
    655 		CELL newcell = Map.Calculated_Cell(source, house->Class->House);
    656 
    657 		/* 
    658 		** Try and place the object onto the map.
    659 		*/
    660 		ScenarioInit++;
    661 		int placed = obj->Unlimbo(Cell_Coord(newcell), DIR_N);
    662 		ScenarioInit--;
    663 		if (placed) {
    664 
    665 			/*
    666 			** If we suceeded in placing the obj onto the map then
    667 			** now we need to give it a mission and destination.
    668 			*/
    669 			obj->Assign_Mission(mission);
    670 
    671 			/*
    672 			** If a navcom was specified then set it.
    673 			*/
    674 			if (navcom != TARGET_NONE) {
    675 				obj->Assign_Destination(navcom);
    676 			}
    677 
    678 			/*
    679 			** If a tarcom was specified then set it.
    680 			*/
    681 			if (tarcom != TARGET_NONE) {
    682 				obj->Assign_Target(tarcom);
    683 			}
    684 
    685 			/*
    686 			** Start the object into action.
    687 			*/
    688 			obj->Commence();
    689 		} else {
    690 			delete obj;
    691 			sub--;
    692 			return(sub);
    693 		}
    694 	}
    695 	return(sub);
    696 }