750 lines
31 KiB
C++
750 lines
31 KiB
C++
//
|
|
// Copyright 2020 Electronic Arts Inc.
|
|
//
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is free
|
|
// software: you can redistribute it and/or modify it under the terms of
|
|
// the GNU General Public License as published by the Free Software Foundation,
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
|
|
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
|
|
// in the hope that it will be useful, but with permitted additional restrictions
|
|
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
|
|
// distributed with this program. You should have received a copy of the
|
|
// GNU General Public License along with permitted additional restrictions
|
|
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
|
|
|
|
/* $Header: /CounterStrike/REINF.CPP 1 3/03/97 10:25a Joe_bostic $ */
|
|
/***********************************************************************************************
|
|
*** 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 ***
|
|
***********************************************************************************************
|
|
* *
|
|
* Project Name : Command & Conquer *
|
|
* *
|
|
* File Name : REINF.CPP *
|
|
* *
|
|
* Programmer : Joe L. Bostic *
|
|
* *
|
|
* Start Date : May 24, 1994 *
|
|
* *
|
|
* Last Update : July 26, 1996 [JLB] *
|
|
* *
|
|
*---------------------------------------------------------------------------------------------*
|
|
* Functions: *
|
|
* Create_Air_Reinforcement -- Creates air strike reinforcement *
|
|
* Create_Special_Reinforcement -- Ad hoc reinforcement handler. *
|
|
* Do_Reinforcements -- Create and place a reinforcement team. *
|
|
* _Consists_Only_Of_Infantry -- Determine if this group consists only of infantry. *
|
|
* _Create_Group -- Create a group given team specification. *
|
|
* _Pop_Group_Out_Of_Object -- Process popping the group out of the object. *
|
|
* _Who_Can_Pop_Out_Of -- Find a suitable host for these reinforcements. *
|
|
* _Need_To_Take -- Examines unit to determine if it should be confiscated. *
|
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
|
|
|
#include "function.h"
|
|
|
|
|
|
/***********************************************************************************************
|
|
* _Pop_Group_Out_Of_Object -- Process popping the group out of the object. *
|
|
* *
|
|
* This routine will cause the group to pop out of the object specified. *
|
|
* *
|
|
* INPUT: group -- Pointer to the first object in the group to be popped out. *
|
|
* *
|
|
* object -- Pointer to the object that the group is to pop out of. *
|
|
* *
|
|
* OUTPUT: bool; Was the group popped out of the specified object? *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/25/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
static bool _Pop_Group_Out_Of_Object(FootClass * group, TechnoClass * object)
|
|
{
|
|
assert(group != NULL && object != NULL);
|
|
int quantity = 0;
|
|
|
|
/*
|
|
** Take every infantry member of this group and detach it from the group list
|
|
** and then make it pop out of the candidate source.
|
|
*/
|
|
while (group != NULL) {
|
|
TechnoClass * todo = group;
|
|
group = (FootClass *)(ObjectClass *)group->Next;
|
|
todo->Next = NULL;
|
|
|
|
switch (object->What_Am_I()) {
|
|
|
|
/*
|
|
** The infantry just walks out of a building.
|
|
*/
|
|
case RTTI_BUILDING:
|
|
if (object->Exit_Object(todo) != 2) {
|
|
delete todo;
|
|
} else {
|
|
++quantity;
|
|
}
|
|
break;
|
|
|
|
/*
|
|
** Infantry get attached to transport vehicles and then unload.
|
|
*/
|
|
case RTTI_UNIT:
|
|
case RTTI_VESSEL:
|
|
case RTTI_AIRCRAFT:
|
|
object->Attach((FootClass *)todo);
|
|
object->Assign_Mission(MISSION_UNLOAD);
|
|
++quantity;
|
|
break;
|
|
|
|
default:
|
|
delete todo;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return (quantity != 0);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* _Need_To_Take -- Examines unit to determine if it should be confiscated. *
|
|
* *
|
|
* The unit is examined and if the owning house needs to confiscate it, then this routine *
|
|
* will return TRUE. In other cases, the unit should be left to its own devices. *
|
|
* *
|
|
* INPUT: unit -- Pointer to the object to examine. *
|
|
* *
|
|
* OUTPUT: bool; Should the object be confiscated by the player so that it becomes one of *
|
|
* his normal game objects? *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/26/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
bool _Need_To_Take(AircraftClass const * air)
|
|
{
|
|
if (*air == AIRCRAFT_YAK || *air == AIRCRAFT_MIG) {
|
|
int deficit = air->House->Get_Quantity(STRUCT_AIRSTRIP);
|
|
// int deficit = air->House->Get_Quantity(STRUCT_AIRSTRIP) - (air->House->Get_Quantity(AIRCRAFT_YAK)+air->House->Get_Quantity(AIRCRAFT_MIG));
|
|
|
|
/*
|
|
** Loop through all aircraft and subtract all the ones that are NOT loaners.
|
|
*/
|
|
for (int index = 0; index < Aircraft.Count(); index++) {
|
|
AircraftClass const * airptr = Aircraft.Ptr(index);
|
|
if ((*airptr == AIRCRAFT_YAK || *airptr == AIRCRAFT_MIG) && airptr->IsOwnedByPlayer && !airptr->IsALoaner && airptr != air) {
|
|
deficit -= 1;
|
|
if (deficit == 0) break;
|
|
}
|
|
}
|
|
|
|
if (deficit > 0) return(true);
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* _Create_Group -- Create a group given team specification. *
|
|
* *
|
|
* This routine will create all members of the group as specified by the team type. *
|
|
* *
|
|
* INPUT: teamtype -- Pointer to the team type that specifies what objects should be *
|
|
* created in this group. *
|
|
* *
|
|
* OUTPUT: Returns with a pointer to the first member of the group created. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/25/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
static FootClass * _Create_Group(TeamTypeClass const * teamtype)
|
|
{
|
|
assert(teamtype != NULL);
|
|
|
|
TeamClass * team = new TeamClass(teamtype);
|
|
if (team != NULL) {
|
|
team->Force_Active();
|
|
}
|
|
|
|
bool hasunload = false;
|
|
for (int tm = 0; tm < teamtype->MissionCount; tm++) {
|
|
if (teamtype->MissionList[tm].Mission == TMISSION_UNLOAD) {
|
|
hasunload = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Now that the official source for the reinforcement has been determined, the
|
|
** objects themselves must be created.
|
|
*/
|
|
FootClass * transport = NULL;
|
|
FootClass * object = NULL;
|
|
for (int index = 0; index < teamtype->ClassCount; index++) {
|
|
TechnoTypeClass const * tclass = teamtype->Members[index].Class;
|
|
|
|
for (int sub = 0; sub < teamtype->Members[index].Quantity; sub++) {
|
|
ScenarioInit++;
|
|
FootClass * temp = (FootClass *)tclass->Create_One_Of(HouseClass::As_Pointer(teamtype->House));
|
|
ScenarioInit--;
|
|
|
|
if (temp != NULL) {
|
|
|
|
/*
|
|
** Add the member to the team.
|
|
*/
|
|
if (team != NULL) {
|
|
ScenarioInit++;
|
|
bool ok = team->Add(temp);
|
|
//Mono_Printf("Added to team = %d.\n", ok);Keyboard->Get();
|
|
|
|
ScenarioInit--;
|
|
temp->IsInitiated = true;
|
|
}
|
|
|
|
if (temp->What_Am_I() == RTTI_AIRCRAFT && !_Need_To_Take((AircraftClass const *)temp)) {
|
|
temp->IsALoaner = true;
|
|
}
|
|
|
|
/*
|
|
** Build the list of transporters and passengers.
|
|
*/
|
|
if (tclass->Max_Passengers() > 0) {
|
|
|
|
/*
|
|
** Link to the list of transports.
|
|
*/
|
|
temp->Next = transport;
|
|
transport = temp;
|
|
|
|
} else {
|
|
|
|
/*
|
|
** Link to the list of normal objects.
|
|
*/
|
|
temp->Next = object;
|
|
object = temp;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
** If the group consists of transports and normal objects, then assign the normal
|
|
** objects to be passengers on the transport.
|
|
*/
|
|
if (transport != NULL && object != NULL) {
|
|
transport->Attach(object);
|
|
|
|
/*
|
|
** HACK ALERT! If the this team has an unload mission, then flag the transport
|
|
** as a loaner so that it will exit from the map when the unload process is
|
|
** complete, but only if the transport is an aircraft type.
|
|
*/
|
|
if (hasunload && (transport->What_Am_I() == RTTI_AIRCRAFT || transport->What_Am_I() == RTTI_VESSEL)) {
|
|
transport->IsALoaner = true;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** For JUST transport helicopters, consider the loaner a gift if there are
|
|
** no passengers.
|
|
*/
|
|
if (transport != NULL && object == NULL && transport->What_Am_I() == RTTI_AIRCRAFT && *((AircraftClass *)transport) == AIRCRAFT_TRANSPORT) {
|
|
transport->IsALoaner = false;
|
|
}
|
|
|
|
if (transport == 0 && object == 0) {
|
|
if (team != NULL) delete team;
|
|
return(NULL);
|
|
}
|
|
|
|
/*
|
|
** If this group consists only of non-transport object, then just return with a pointer
|
|
** to the first member of the group.
|
|
*/
|
|
if (transport == NULL) {
|
|
return(object);
|
|
}
|
|
|
|
return(transport);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* _Consists_Only_Of_Infantry -- Determine if this group consists only of infantry. *
|
|
* *
|
|
* Use this to determine if the specified group only contains infantry. Such a reinforcement*
|
|
* group is a candidate for popping out of a building or transport vehicle rather than *
|
|
* driving/walking/sailing/flying onto the map under its own power. *
|
|
* *
|
|
* INPUT: first -- Pointer to the first object in the group to examine. *
|
|
* *
|
|
* OUTPUT: bool; Is the entire group composed of infantry type units? *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/25/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
static bool _Consists_Only_Of_Infantry(FootClass const * first)
|
|
{
|
|
while (first != NULL) {
|
|
if (first->What_Am_I() != RTTI_INFANTRY) {
|
|
return(false);
|
|
}
|
|
first = (FootClass const *)((ObjectClass *)first->Next);
|
|
}
|
|
return(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* _Who_Can_Pop_Out_Of -- Find a suitable host for these reinforcements. *
|
|
* *
|
|
* This routine is used to scan nearby locations to determine if there is a suitable host *
|
|
* for these reinforcements to "pop out of" (apologies to Aliens). Typical hosts include *
|
|
* buildings and transport vehicles (of any kind). *
|
|
* *
|
|
* INPUT: origin -- The cell that should be scanned from. Only this location and immediate *
|
|
* adjacent locations will be scanned. *
|
|
* *
|
|
* OUTPUT: Returns with a pointer to a suitable host. If none could be found then NULL is *
|
|
* returned. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 06/25/1996 JLB : Created. *
|
|
*=============================================================================================*/
|
|
static TechnoClass * _Who_Can_Pop_Out_Of(CELL origin)
|
|
{
|
|
CellClass * cellptr = &Map[origin];
|
|
TechnoClass * candidate = NULL;
|
|
|
|
for (int f = -1; f < 8; f++) {
|
|
CellClass * ptr = cellptr;
|
|
if (f != -1) {
|
|
ptr = ptr->Adjacent_Cell(FacingType(f));
|
|
if (!ptr) continue;
|
|
}
|
|
|
|
BuildingClass * building = ptr->Cell_Building();
|
|
if (building && building->Strength > 0) {
|
|
candidate = building;
|
|
}
|
|
|
|
UnitClass * unit = ptr->Cell_Unit();
|
|
if (unit && unit->Strength && unit->Class->Max_Passengers() > 0) {
|
|
return(unit);
|
|
}
|
|
}
|
|
return(candidate);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Do_Reinforcements -- Create and place a reinforcement team. *
|
|
* *
|
|
* This routine is called when a reinforcement team must be created and placed on the map. *
|
|
* It will create all members of the team and place them at the location determined from *
|
|
* the team composition. The reinforcement team should follow team orders until overridden *
|
|
* by AI or player intervention. *
|
|
* *
|
|
* INPUT: teamtype -- Pointer to the team type to create as a reinforcement. *
|
|
* *
|
|
* OUTPUT: Was the reinforcement successfully created and placed? *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 05/08/1995 JLB : Created. *
|
|
* 05/18/1995 JLB : Returns success or failure condition. *
|
|
* 06/19/1995 JLB : Announces reinforcements. *
|
|
* 02/15/1996 JLB : Recognizes team reinforcement location. *
|
|
*=============================================================================================*/
|
|
bool Do_Reinforcements(TeamTypeClass const * teamtype)
|
|
{
|
|
assert(teamtype != 0);
|
|
|
|
/*
|
|
** perform some preliminary checks for validity.
|
|
*/
|
|
if (!teamtype || !teamtype->ClassCount) return(false);
|
|
|
|
/*
|
|
** HACK ALERT!
|
|
** Give this team an attack waypoint mission that will attack the waypoint location of this
|
|
** team if there are no team missions previously assigned.
|
|
*/
|
|
if (teamtype->MissionCount == 0) {
|
|
TeamTypeClass * tt = (TeamTypeClass *)teamtype;
|
|
tt->MissionCount = 1;
|
|
tt->MissionList[0].Mission = TMISSION_ATT_WAYPT;
|
|
tt->MissionList[0].Data.Value = teamtype->Origin;
|
|
}
|
|
|
|
FootClass * object = _Create_Group(teamtype);
|
|
|
|
|
|
//Mono_Printf("%d-%s (object=%p, team=%d).\n", __LINE__, __FILE__, object, object->Team.Is_Valid());Keyboard->Get();
|
|
|
|
|
|
/*
|
|
** Bail on this reinforcement if no reinforcements could be created.
|
|
** This is probably because the object maximum was reached.
|
|
*/
|
|
if (!object) {
|
|
return(false);
|
|
}
|
|
|
|
/*
|
|
** Special case code to handle infantry types that run from a building. This presumes
|
|
** that infantry are never a transport (which is safe to do).
|
|
*/
|
|
if (object != NULL && teamtype->Origin != -1 && _Consists_Only_Of_Infantry(object)) {
|
|
|
|
/*
|
|
** Search for an object that these infantry can pop out of.
|
|
*/
|
|
TechnoClass * candidate = _Who_Can_Pop_Out_Of(Scen.Waypoint[teamtype->Origin]);
|
|
|
|
if (candidate != NULL) {
|
|
return(_Pop_Group_Out_Of_Object(object, candidate));
|
|
}
|
|
}
|
|
|
|
/*
|
|
** The reinforcements must be delivered the old fashioned way -- by moving onto the
|
|
** map using their own power. First order of business is to determine where they
|
|
** should arrive from.
|
|
*/
|
|
SourceType source = HouseClass::As_Pointer(teamtype->House)->Control.Edge;
|
|
if (source == SOURCE_NONE) {
|
|
source = SOURCE_NORTH;
|
|
}
|
|
|
|
/*
|
|
** Pick the location where the reinforcements appear and then place
|
|
** them there.
|
|
*/
|
|
bool placed = false;
|
|
|
|
FacingType eface = (FacingType)(source << 1); // Facing to enter map.
|
|
|
|
CELL cell = Map.Calculated_Cell(source, teamtype->Origin, -1, object->Techno_Type_Class()->Speed);
|
|
#ifdef FIXIT_ANTS
|
|
/*
|
|
** For the ants, they will pop out of the ant hill directly.
|
|
*/
|
|
if (teamtype->Origin != -1 && object->What_Am_I() == RTTI_UNIT &&
|
|
(*((UnitClass*)object) == UNIT_ANT1 ||
|
|
*((UnitClass*)object) == UNIT_ANT2 ||
|
|
*((UnitClass*)object) == UNIT_ANT3)) {
|
|
CELL newcell = Scen.Waypoint[teamtype->Origin];
|
|
if (newcell != -1) {
|
|
if (Map[newcell].TType == TEMPLATE_HILL01) {
|
|
cell = newcell;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
CELL newcell = cell;
|
|
|
|
FootClass * o = (FootClass *)(ObjectClass *)object->Next;
|
|
object->Next = 0;
|
|
bool okvoice = false;
|
|
while (newcell > 0 && object != NULL) {
|
|
DirType desiredfacing = Facing_Dir(eface);
|
|
if (object->What_Am_I() == RTTI_AIRCRAFT) {
|
|
desiredfacing = Random_Pick(DIR_N, DIR_MAX);
|
|
}
|
|
|
|
ScenarioInit++;
|
|
if (object->Unlimbo(Cell_Coord(newcell), desiredfacing)) {
|
|
okvoice = true;
|
|
|
|
/*
|
|
** If this object is part of a team, then the mission for this
|
|
** object will be guard. The team handler will assign the proper
|
|
** mission that it should follow.
|
|
*/
|
|
if (object->What_Am_I() != RTTI_AIRCRAFT) {
|
|
object->Assign_Mission(MISSION_GUARD);
|
|
object->Commence();
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
** Could not unlimbo at location specified so find an adjacent location that it can
|
|
** be unlimboed at. If this fails, then abort the whole placement process.
|
|
*/
|
|
FacingType adj;
|
|
for (adj = FACING_N; adj < FACING_COUNT; adj++) {
|
|
CELL trycell = Adjacent_Cell(newcell, adj);
|
|
if (!Map.In_Radar(trycell) && object->Can_Enter_Cell(trycell, adj) == MOVE_OK) {
|
|
newcell = trycell;
|
|
break;
|
|
}
|
|
}
|
|
if (adj < FACING_COUNT) continue;
|
|
newcell = 0;
|
|
}
|
|
ScenarioInit--;
|
|
|
|
object = o;
|
|
if (object != NULL) {
|
|
o = (FootClass *)(ObjectClass *)object->Next;
|
|
object->Next = 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** If there are still objects that could not be placed, then delete them.
|
|
*/
|
|
if (o != NULL) {
|
|
while (o != NULL) {
|
|
FootClass * old = o;
|
|
o = (FootClass *)(ObjectClass *)o->Next;
|
|
old->Next = 0;
|
|
|
|
delete old;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Announce when the reinforcements have arrived.
|
|
*/
|
|
if (okvoice && teamtype->House == PlayerPtr->Class->House) {
|
|
Speak(VOX_REINFORCEMENTS, NULL, newcell ? Cell_Coord(newcell) : 0);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Create_Special_Reinforcement -- Ad hoc reinforcement handler. *
|
|
* *
|
|
* Use this routine to bring on a reinforcement that hasn't been anticipated by the trigger *
|
|
* system. An example of this would be replacement harvesters or airfield ordered units. *
|
|
* The appropriate transport is created (if necessary) and a mission is assigned such that *
|
|
* the object will legally bring itself onto the playing field. *
|
|
* *
|
|
* INPUT: house -- The owner of this reinforcement. *
|
|
* *
|
|
* type -- The object to bring on. *
|
|
* *
|
|
* another -- This is reserved for the transport class in those cases where the *
|
|
* transport MUST be forced to a specific type. *
|
|
* *
|
|
* mission -- The mission to assign this reinforcement team. *
|
|
* *
|
|
* argument -- Optional team mission argument (usually a waypoint). *
|
|
* *
|
|
* OUTPUT: Was the special reinforcement created without error? *
|
|
* *
|
|
* WARNINGS: This routine will fail if a team type cannot be created. *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/04/1995 JLB : Created. *
|
|
*=============================================================================================*/
|
|
bool Create_Special_Reinforcement(HouseClass * house, TechnoTypeClass const * type, TechnoTypeClass const * another, TeamMissionType mission, int argument)
|
|
{
|
|
assert(house != 0);
|
|
assert(type != 0);
|
|
|
|
if (house && type) {
|
|
TeamTypeClass * team = new TeamTypeClass();
|
|
|
|
if (team) {
|
|
|
|
/*
|
|
** If there is no overridden mission assign to this special reinforcement, then
|
|
** we must assign something. If not, the reinforcement will just sit at the edge
|
|
** of the map.
|
|
*/
|
|
if (!another && mission == TMISSION_NONE) {
|
|
mission = TMISSION_MOVECELL;
|
|
argument = Map.Calculated_Cell(house->Control.Edge);
|
|
}
|
|
|
|
/*
|
|
** Fill in the team characteristics.
|
|
*/
|
|
strcpy((char *)&team->IniName[0], "TEMP");
|
|
team->IsReinforcable = false;
|
|
team->IsTransient = true;
|
|
team->ClassCount = 1;
|
|
team->Members[0].Class = type;
|
|
team->Members[0].Quantity = 1;
|
|
team->MissionCount = 1;
|
|
if (mission == TMISSION_NONE) {
|
|
team->MissionList[0].Mission = TMISSION_UNLOAD;
|
|
team->MissionList[0].Data.Value = WAYPT_REINF;
|
|
} else {
|
|
team->MissionList[0].Mission = mission;
|
|
team->MissionList[0].Data.Value = argument;
|
|
}
|
|
team->House = house->Class->House;
|
|
if (another) {
|
|
team->ClassCount++;
|
|
team->Members[1].Class = another;
|
|
team->Members[1].Quantity = 1;
|
|
}
|
|
|
|
bool ok = Do_Reinforcements(team);
|
|
if (!ok) delete team;
|
|
return(ok);
|
|
}
|
|
}
|
|
return(false);
|
|
}
|
|
|
|
|
|
/***********************************************************************************************
|
|
* Create_Air_Reinforcement -- Creates air strike reinforcement *
|
|
* *
|
|
* This routine is used to launch an airstrike. It will create the necessary aircraft and *
|
|
* assign them to attack the target specified. This routine bypasses the normal *
|
|
* reinforcement logic since it doesn't need the sophistication of unloading and following *
|
|
* team mission lists. *
|
|
* *
|
|
* INPUT: house -- The perpetrator of this air strike. *
|
|
* *
|
|
* air -- The type of aircraft to make up this airstrike. *
|
|
* *
|
|
* number -- The number of aircraft in this airstrike. *
|
|
* *
|
|
* mission -- The mission to assign the aircraft. *
|
|
* *
|
|
* tarcom -- The target to assign these aircraft. *
|
|
* *
|
|
* navcom -- The navigation target to assign (if necessary). *
|
|
* *
|
|
* OUTPUT: Returns the number of aircraft created for this airstrike. *
|
|
* *
|
|
* WARNINGS: none *
|
|
* *
|
|
* HISTORY: *
|
|
* 07/04/1995 JLB : Commented. *
|
|
*=============================================================================================*/
|
|
int Create_Air_Reinforcement(HouseClass * house, AircraftType air, int number, MissionType mission, TARGET tarcom, TARGET navcom, InfantryType passenger)
|
|
{
|
|
assert(house != 0);
|
|
assert((unsigned)air < AIRCRAFT_COUNT);
|
|
assert(number != 0);
|
|
assert((unsigned)mission < MISSION_COUNT);
|
|
/*
|
|
** Get a pointer to the class of the object that we are going to create.
|
|
*/
|
|
TechnoTypeClass const * type = (TechnoTypeClass *)&AircraftTypeClass::As_Reference(air);
|
|
|
|
/*
|
|
** Abort the airstrike if Tanya is the passenger and she's dead.
|
|
*/
|
|
if (passenger == INFANTRY_TANYA && IsTanyaDead) {
|
|
number = 0;
|
|
}
|
|
|
|
/*
|
|
** Loop through the number of objects we are supposed to create and
|
|
** create and place them on the map.
|
|
*/
|
|
int sub;
|
|
for (sub = 0; sub < number; sub++) {
|
|
|
|
/*
|
|
** Create one of the required objects. If this fails we could have
|
|
** a real problem.
|
|
*/
|
|
ScenarioInit++;
|
|
TechnoClass * obj = (TechnoClass *)type->Create_One_Of(house);
|
|
ScenarioInit--;
|
|
if (!obj) return(sub);
|
|
|
|
/*
|
|
** Flying objects always have the IsALoaner bit set.
|
|
*/
|
|
obj->IsALoaner = true;
|
|
|
|
/*
|
|
** Find a cell for the object to come in on. This is stolen from the
|
|
** the code that handles a SOURCE_AIR in the normal logic.
|
|
*/
|
|
SourceType source = house->Control.Edge;
|
|
switch (source) {
|
|
case SOURCE_NORTH:
|
|
case SOURCE_EAST:
|
|
case SOURCE_SOUTH:
|
|
case SOURCE_WEST:
|
|
break;
|
|
|
|
default:
|
|
source = SOURCE_NORTH;
|
|
break;
|
|
}
|
|
CELL newcell = Map.Calculated_Cell(source, -1, -1, SPEED_WINGED);
|
|
|
|
/*
|
|
** Try and place the object onto the map.
|
|
*/
|
|
ScenarioInit++;
|
|
int placed = obj->Unlimbo(Cell_Coord(newcell), DIR_N);
|
|
ScenarioInit--;
|
|
if (placed) {
|
|
|
|
/*
|
|
** If we succeeded in placing the obj onto the map then
|
|
** now we need to give it a mission and destination.
|
|
*/
|
|
obj->Assign_Mission(mission);
|
|
|
|
/*
|
|
** If a navcom was specified then set it.
|
|
*/
|
|
if (navcom != TARGET_NONE) {
|
|
obj->Assign_Destination(navcom);
|
|
}
|
|
|
|
/*
|
|
** If a tarcom was specified then set it.
|
|
*/
|
|
if (tarcom != TARGET_NONE) {
|
|
obj->Assign_Target(tarcom);
|
|
}
|
|
|
|
/*
|
|
** Assign generic passenger value here. This value is used to determine
|
|
** if this aircraft should drop parachute reinforcements.
|
|
*/
|
|
if (obj->What_Am_I() == RTTI_AIRCRAFT) {
|
|
AircraftClass * aircraft = (AircraftClass *)obj;
|
|
if (passenger != INFANTRY_NONE) {
|
|
aircraft->Passenger = passenger;
|
|
}
|
|
// if (Passenger == INFANTRY_TANYA) {
|
|
// aircraft->Ammo = 1;
|
|
//aircraft->AttacksRemaining = 1;
|
|
// }
|
|
}
|
|
|
|
/*
|
|
** Start the object into action.
|
|
*/
|
|
obj->Commence();
|
|
} else {
|
|
delete obj;
|
|
sub--;
|
|
return(sub);
|
|
}
|
|
}
|
|
return(sub);
|
|
}
|