| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075 |
- //
- // 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/TEAM.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 : TEAM.CPP *
- * *
- * Programmer : Joe L. Bostic *
- * *
- * Start Date : 12/11/94 *
- * *
- * Last Update : August 27, 1996 [JLB] *
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * TeamClass::AI -- Process team logic. *
- * TeamClass::Add -- Adds specified object to team. *
- * TeamClass::Assign_Mission_Target -- Sets teams mission target and clears old target *
- * TeamClass::Calc_Center -- Determines average location of team members. *
- * TeamClass::Can_Add -- Determines if the specified object can be added to team. *
- * TeamClass::Control -- Updates control on a member unit. *
- * TeamClass::Coordinate_Attack -- Handles coordinating a team attack. *
- * TeamClass::Coordinate_Conscript -- Gives orders to new recruit. *
- * TeamClass::Coordinate_Do -- Handles the team performing specified mission. *
- * TeamClass::Coordinate_Move -- Handles team movement coordination. *
- * TeamClass::Coordinate_Regroup -- Handles team idling (regrouping). *
- * TeamClass::Debug_Dump -- Displays debug information about the team. *
- * TeamClass::Detach -- Removes specified target from team tracking. *
- * TeamClass::Fetch_A_Leader -- Looks for a suitable leader member of the team. *
- * TeamClass::Has_Entered_Map -- Determines if the entire team has entered the map. *
- * TeamClass::Init -- Initializes the team objects for scenario preparation. *
- * TeamClass::Is_A_Member -- Tests if a unit is a member of a team *
- * TeamClass::Is_Leaving_Map -- Checks if team is in process of leaving the map *
- * TeamClass::Lagging_Units -- Finds and orders any lagging units to catch up. *
- * TeamClass::Recruit -- Attempts to recruit members to the team for the given index ID. *
- * TeamClass::Remove -- Removes the specified object from the team. *
- * TeamClass::Scan_Limit -- Force all members of the team to have limited scan range. *
- * TeamClass::Suspend_Teams -- Suspends activity for low priority teams *
- * TeamClass::TMision_Patrol -- Handles patrolling from one location to another. *
- * TeamClass::TMission_Attack -- Perform the team attack mission command. *
- * TeamClass::TMission_Follow -- Perform the "follow friendlies" team command. *
- * TeamClass::TMission_Formation -- Process team formation change command. *
- * TeamClass::TMission_Invulnerable -- Makes the entire team invulnerable for a period of tim*
- * TeamClass::TMission_Load -- Tells the team to load onto the transport now. *
- * TeamClass::TMission_Loop -- Causes the team mission processor to jump to new location. *
- * TeamClass::TMission_Set_Global -- Performs a set global flag operation. *
- * TeamClass::TMission_Spy -- Perform the team spy mission. *
- * TeamClass::TMission_Unload -- Tells the team to unload passengers now. *
- * TeamClass::TeamClass -- Constructor for the team object type. *
- * TeamClass::Took_Damage -- Informs the team when the team member takes damage. *
- * TeamClass::operator delete -- Deallocates a team object. *
- * TeamClass::operator new -- Allocates a team object. *
- * TeamClass::~TeamClass -- Team object destructor. *
- * _Is_It_Breathing -- Checks to see if unit is an active team member. *
- * _Is_It_Playing -- Determines if unit is active and an initiated team member. *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "function.h"
- #include "mission.h"
- /***********************************************************************************************
- * _Is_It_Breathing -- Checks to see if unit is an active team member. *
- * *
- * A unit could be a team member, but not be active. Such a case would occur when a *
- * reinforcement team is inside a transport. It could also occur if a unit is in the *
- * process of dying. Call this routine to ensure that the specified unit is a will and *
- * able participant in the team. *
- * *
- * INPUT: object -- Pointer to the unit/infantry/aircraft that is to be checked. *
- * *
- * OUTPUT: bool; Is the specified unit active and able to be given commands by the team? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 03/11/1996 JLB : Created. *
- *=============================================================================================*/
- static inline bool _Is_It_Breathing(FootClass const * object)
- {
- /*
- ** If the object is not present or appears to be dead, then it
- ** certainly isn't an active member of the team.
- */
- if (object == NULL || !object->IsActive || object->Strength == 0) return(false);
- /*
- ** If the object is in limbo, then it isn't an active team member either. However, if the
- ** scenario init flag is on, then it is probably a reinforcement issue or scenario
- ** creation situation. In such a case, the members are considered active because they need to
- ** be given special orders and treatment.
- */
- if (!ScenarioInit && object->IsInLimbo) return(false);
- /*
- ** Nothing eliminated this object from being considered an active member of the team (i.e.,
- ** "breathing"), then return that it is ok.
- */
- return(true);
- }
- /***********************************************************************************************
- * _Is_It_Playing -- Determines if unit is active and an initiated team member. *
- * *
- * Use this routine to determine if the specified unit is an active participant of the *
- * team. When a unit is first recruited to the team, it must travel to the team's location *
- * before it can become an active player. Call this routine to determine if the specified *
- * unit can be considered an active player. *
- * *
- * INPUT: object -- Pointer to the object that is to be checked to see if it is an *
- * active player. *
- * *
- * OUTPUT: bool; Is the specified unit an active, living, initiated member of the team? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 03/11/1996 JLB : Created. *
- *=============================================================================================*/
- static inline bool _Is_It_Playing(FootClass const * object)
- {
- /*
- ** If the object is not active, then it certainly can be a participating member of the
- ** team.
- */
- if (!_Is_It_Breathing(object)) return(false);
- /*
- ** Only members that have been "Initiated" are considered "playing" participants of the
- ** team. This results in the team members that are racing to regroup with the team (i.e.,
- ** not initiated), will continue to catch up to the team even while the initiated team members
- ** carry out their team specific orders.
- */
- if (!object->IsInitiated && object->What_Am_I() != RTTI_AIRCRAFT) return(false);
- /*
- ** If it reaches this point, then nothing appears to disqualify the specified object from
- ** being considered an active playing member of the team. In this case, return that
- ** information.
- */
- return(true);
- }
- #ifdef CHEAT_KEYS
- /***********************************************************************************************
- * TeamClass::Debug_Dump -- Displays debug information about the team. *
- * *
- * This routine will display information about the team. This is useful for debugging *
- * purposes. *
- * *
- * INPUT: mono -- Pointer to the monochrome screen that the debugging information will *
- * be displayed on. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 03/11/1996 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Debug_Dump(MonoClass * mono) const
- {
- mono->Set_Cursor(1, 20);mono->Printf("%8.8s", Class->IniName);
- mono->Set_Cursor(10, 20);mono->Printf("%3d", Total);
- mono->Set_Cursor(17, 20);mono->Printf("%3d", Quantity[Class->ID]);
- if (CurrentMission != -1) {
- mono->Set_Cursor(1, 22);
- mono->Printf("%-29s", Class->MissionList[CurrentMission].Description(CurrentMission));
- }
- mono->Set_Cursor(40, 20);mono->Printf("%-10s", FormationName[Formation]);
- mono->Set_Cursor(22, 20);mono->Printf("%08X", Zone);
- mono->Set_Cursor(31, 20);mono->Printf("%08X", Target);
- mono->Fill_Attrib(53, 20, 12, 1, IsUnderStrength ? MonoClass::INVERSE : MonoClass::NORMAL);
- mono->Fill_Attrib(53, 21, 12, 1, IsFullStrength ? MonoClass::INVERSE : MonoClass::NORMAL);
- mono->Fill_Attrib(53, 22, 12, 1, IsHasBeen ? MonoClass::INVERSE : MonoClass::NORMAL);
- mono->Fill_Attrib(66, 20, 12, 1, IsMoving ? MonoClass::INVERSE : MonoClass::NORMAL);
- mono->Fill_Attrib(66, 21, 12, 1, IsForcedActive ? MonoClass::INVERSE : MonoClass::NORMAL);
- mono->Fill_Attrib(66, 22, 12, 1, IsReforming ? MonoClass::INVERSE : MonoClass::NORMAL);
- }
- #endif
- /***********************************************************************************************
- * TeamClass::Init -- Initializes the team objects for scenario preparation. *
- * *
- * This routine clears out the team object array in preparation for starting a new *
- * scenario. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Init(void)
- {
- Teams.Free_All();
- }
- /***********************************************************************************************
- * TeamClass::operator new -- Allocates a team object. *
- * *
- * This routine will allocate a team object from the team object pool. *
- * *
- * INPUT: size -- The size of the requested allocation. *
- * *
- * OUTPUT: Returns with a pointer to the freshly allocated team object. If an allocation *
- * could not be made, then NULL is returned. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/21/1995 JLB : Created. *
- *=============================================================================================*/
- void * TeamClass::operator new(size_t)
- {
- void * ptr = Teams.Allocate();
- if (ptr != NULL) {
- ((TeamClass *)ptr)->Set_Active();
- }
- return(ptr);
- }
- /***********************************************************************************************
- * TeamClass::operator delete -- Deallocates a team object. *
- * *
- * This routine will return a team object to the team object pool. *
- * *
- * INPUT: ptr -- Pointer to the team object to deallocate. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/21/1995 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::operator delete(void * ptr)
- {
- if (ptr != NULL) {
- ((TeamClass *)ptr)->IsActive = false;
- }
- Teams.Free((TeamClass *)ptr);
- }
- /***********************************************************************************************
- * TeamClass::~TeamClass -- Team object destructor. *
- * *
- * This routine is called when a team object is destroyed. It handles updating the total *
- * number count for this team object type. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/21/1995 JLB : Created. *
- * 07/04/1996 JLB : Keeps trigger if trigger still attached to objects. *
- *=============================================================================================*/
- TeamClass::~TeamClass(void)
- {
- if (GameActive && Class.Is_Valid()) {
- while (Member != NULL) {
- Remove(Member);
- }
- Class->Number--;
- /*
- ** When the team dies, any trigger associated with it, dies as well. This will only occur
- ** if there are no other objects linked to this trigger. Only player reinforcement
- ** members that broke off of the team earlier will have this occur.
- */
- if (Trigger.Is_Valid()) {
- if (Trigger->AttachCount == 0) {
- delete (TriggerClass *)Trigger;
- }
- Trigger = NULL;
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::TeamClass -- Constructor for the team object type. *
- * *
- * This routine is called when the team object is created. *
- * *
- * INPUT: type -- Pointer to the team type to make this team object from. *
- * *
- * owner -- The owner of this team. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 09/21/1995 JLB : Created. *
- *=============================================================================================*/
- TeamClass::TeamClass(TeamTypeClass const * type, HouseClass * owner) :
- AbstractClass(RTTI_TEAM, Teams.ID(this)),
- Class((TeamTypeClass *)type),
- House(owner),
- IsForcedActive(false),
- IsHasBeen(false),
- IsFullStrength(false),
- IsUnderStrength(true),
- IsReforming(false),
- IsLagging(false),
- IsAltered(true),
- JustAltered(false),
- IsMoving(false),
- IsNextMission(true),
- IsLeaveMap(false),
- Suspended(false),
- Trigger(NULL),
- Zone(TARGET_NONE),
- ClosestMember(TARGET_NONE),
- MissionTarget(TARGET_NONE),
- Target(TARGET_NONE),
- Total(0),
- Risk(0),
- Formation(FORMATION_NONE),
- SuspendTimer(0),
- CurrentMission(-1),
- TimeOut(0),
- Member(0)
- {
- assert(Class);
- assert(Class->IsActive);
- assert(Class->ClassCount > 0);
- if (owner == NULL) {
- House = HouseClass::As_Pointer(Class->House);
- }
- memset(Quantity, 0, sizeof(Quantity));
- if (Class->Origin != -1) {
- Zone = ::As_Target(Scen.Waypoint[Class->Origin]);
- }
- Class->Number++;
- /*
- ** If there is a trigger tightly associated with this team, then
- ** create an instance of that trigger and attach it to the team.
- */
- if (Class->Trigger.Is_Valid()) {
- Trigger = new TriggerClass(Class->Trigger);
- }
- }
- /***************************************************************************
- * TeamClass::Assign_Mission_Target -- Sets mission target and clears old *
- * *
- * INPUT: *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 05/16/1995 PWG : Created. *
- *=========================================================================*/
- void TeamClass::Assign_Mission_Target(TARGET new_target)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- /*
- ** First go through and find anyone who is currently targeting
- ** the old mission target and clear their Tarcom.
- */
- FootClass * unit = Member;
- if (MissionTarget != TARGET_NONE) {
- while (unit != NULL) {
- bool tar = (unit->TarCom == MissionTarget);
- bool nav = (unit->NavCom == MissionTarget);
- if (tar || nav) {
- /*
- ** If the unit was doing something related to the team mission
- ** then we kick him into guard mode so that he is easy to change
- ** missions for.
- */
- unit->Assign_Mission(MISSION_GUARD);
- /*
- ** If the unit's tarcom is set to the old mission target, then
- ** clear it, so that it will be reset by whatever happens next.
- */
- if (nav) {
- unit->Assign_Destination(TARGET_NONE);
- }
- /*
- ** If the unit's navcom is set to the old mission target, then
- ** clear it, so that it will be reset by whatever happens next.
- */
- if (tar) {
- unit->Assign_Target(TARGET_NONE);
- }
- }
- unit = unit->Member;
- }
- }
- /*
- ** If there is not currently an override on the current mission target
- ** then assign both MissionTarget and Target to the new target. If
- ** there is an override, allow the team to keep fighting the override but
- ** make sure they pick up on the new mission when they are ready.
- */
- if (Target == MissionTarget || !Target_Legal(Target)) {
- MissionTarget = Target = new_target;
- } else {
- MissionTarget = new_target;
- }
- }
- /***********************************************************************************************
- * TeamClass::AI -- Process team logic. *
- * *
- * General purpose team logic is handled by this routine. It should be called once per *
- * active team per game tick. This routine handles recruitment and assigning orders to *
- * member units. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- * 01/06/1995 JLB : Choreographed gesture. *
- *=============================================================================================*/
- void TeamClass::AI(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- int desired = 0;
- int old_under = IsUnderStrength;
- int old_full = IsFullStrength;
- /*
- ** If the team has been suspended then we need to check if it's time for
- ** us to reactivate the team. If not, no team logic will be processed
- ** for this team.
- */
- if (Suspended) {
- if (SuspendTimer != 0) {
- return;
- }
- Suspended = false;
- }
- /*
- ** If this team senses that its composition has been altered, then it should
- ** recalculate the under strength and full strength flags.
- */
- if (IsAltered) {
- /*
- ** Figure out the total number of objects that this team type requires.
- */
- for (int index = 0; index < Class->ClassCount; index++) {
- desired += Class->Members[index].Quantity;
- }
- assert(desired != 0);
- if (Total) {
- IsFullStrength = (Total == desired);
- if (IsFullStrength) {
- IsHasBeen = true;
- }
- /*
- ** Reinforceable teams will revert (or snap out of) the under strength
- ** mode when the members transition the magic 1/3 strength threshold.
- */
- if (Class->IsReinforcable) {
- if (desired > 2) {
- IsUnderStrength = (Total <= desired / 3);
- } else {
- IsUnderStrength = (Total < desired);
- }
- } else {
- /*
- ** Teams that are not flagged as reinforceable are never considered under
- ** strength if the team has already started its main mission. This
- ** ensures that once the team has started, it won't dally to pick up
- ** new members.
- */
- IsUnderStrength = !IsHasBeen;
- }
- IsAltered = JustAltered = false;
- } else {
- IsUnderStrength = true;
- IsFullStrength = false;
- Zone = TARGET_NONE;
- /*
- ** A team that exists on the player's side is automatically destroyed
- ** when there are no team members left. This team was created as a
- ** result of reinforcement logic and no longer needs to exist when there
- ** are no more team members.
- */
- if (IsHasBeen || Session.Type != GAME_NORMAL) {
- /*
- ** If this team had no members (i.e., the team object wasn't terminated by some
- ** outside means), then pass through the logic triggers to see if one that
- ** depends on this team leaving the map should be sprung.
- */
- if (IsLeaveMap) {
- for (int index = 0; index < LogicTriggers.Count(); index++) {
- TriggerClass * trig = LogicTriggers[index];
- if (trig->Spring(TEVENT_LEAVES_MAP)) {
- index--;
- if (LogicTriggers.Count() == 0) break;
- }
- }
- }
- delete this;
- return;
- }
- }
- /*
- ** If the team has gone from under strength to no longer under
- ** strength than the team needs to reform.
- */
- if (old_under != IsUnderStrength) {
- IsReforming = true;
- }
- }
- /*
- ** If the team is under strength, then flag it to regroup.
- */
- if (IsMoving && IsUnderStrength) {
- IsMoving = false;
- CurrentMission = -1;
- if (Total) {
- Calc_Center(Zone, ClosestMember);
- /*
- ** When a team is badly damaged and needs to regroup it should
- ** pick a friendly building to go and regroup at. Its first preference
- ** should be somewhere near repair factory. If it cannot find a repair
- ** factory then it should pick another structure that is friendly to
- ** its side.
- */
- CELL dest = As_Cell(Zone);
- int max = 0x7FFFFFFF;
- for (int index = 0; index < Buildings.Count(); index++) {
- BuildingClass * b = Buildings.Ptr(index);
- if (b != NULL && !b->IsInLimbo && b->House == House && b->Class->PrimaryWeapon == NULL) {
- CELL cell = Coord_Cell(b->Center_Coord());
- int dist = ::Distance(b->Center_Coord(), As_Coord(Zone)) * (Map.Cell_Threat(cell, House->Class->House) + 1);
- if (*b == STRUCT_REPAIR) {
- dist /= 2;
- }
- if (dist < max) {
- cell = Fetch_A_Leader()->Safety_Point(As_Cell(Zone), cell, 2, 4);
- // cell = Member->Safety_Point(As_Cell(Zone), cell, 2, 4);
- if (cell != -1) {
- max = dist;
- dest = cell;
- }
- }
- }
- }
- // Should calculate a regroup location.
- Target = ::As_Target(dest);
- Coordinate_Move();
- return;
- } else {
- Zone = TARGET_NONE;
- }
- }
- /*
- ** Flag this team into action when it gets to full strength. Human owned teams are only
- ** used for reinforcement purposes -- always consider them at full strength.
- */
- if (!IsMoving && (IsFullStrength || IsForcedActive)) {
- IsMoving = true;
- IsHasBeen = true;
- IsUnderStrength = false;
- /*
- ** Infantry can do a gesture when they start their mission. Pick
- ** a gesture at random.
- */
- FootClass * techno = Member;
- DoType doaction = Percent_Chance(50) ? DO_GESTURE1 : DO_GESTURE2;
- while (techno) {
- if (_Is_It_Breathing(techno) && techno->What_Am_I() == RTTI_INFANTRY) {
- ((InfantryClass *)techno)->Do_Action(doaction);
- }
- if (IsReforming || IsForcedActive) {
- techno->IsInitiated = true;
- }
- techno = techno->Member;
- }
- CurrentMission = -1;
- IsNextMission = true;
- // IsForcedActive = false;
- }
- /*
- ** If the team is moving or if there is no center position for
- ** the team, then the center position must be recalculated.
- */
- if (IsReforming || IsMoving || Zone == TARGET_NONE || ClosestMember == TARGET_NONE) {
- Calc_Center(Zone, ClosestMember);
- }
- /*
- ** Try to recruit members if there is room to do so for this team.
- ** Only try to recruit members for a non player controlled team.
- */
- if ((!IsMoving || (!IsFullStrength && Class->IsReinforcable)) && ((!House->IsHuman || !IsHasBeen) && Session.Type == GAME_NORMAL)) {
- // if ((!IsMoving || (!IsFullStrength && Class->IsReinforcable)) && ((/*!House->IsHuman ||*/ !IsHasBeen) && Session.Type == GAME_NORMAL)) {
- for (int index = 0; index < Class->ClassCount; index++) {
- if (Quantity[index] < Class->Members[index].Quantity) {
- Recruit(index);
- }
- }
- }
- /*
- ** If there are no members of the team and the team has reached
- ** full strength at one time, then delete the team.
- */
- if (Member == NULL && IsHasBeen) {
- /*
- ** If this team had no members (i.e., the team object wasn't terminated by some
- ** outside means), then pass through the logic triggers to see if one that
- ** depends on this team leaving the map should be sprung.
- */
- if (IsLeaveMap) {
- for (int index = 0; index < LogicTriggers.Count(); index++) {
- TriggerClass * trig = LogicTriggers[index];
- if (trig->Spring(TEVENT_LEAVES_MAP)) {
- index--;
- if (LogicTriggers.Count() == 0) break;
- }
- }
- }
- delete this;
- return;
- }
- /*
- ** If the mission should be advanced to the next entry, then do so at
- ** this time. Various events may cause the mission to advance, but it
- ** all boils down to the following change-mission code.
- */
- if (IsMoving && !IsReforming && IsNextMission) {
- IsNextMission = false;
- CurrentMission++;
- if (CurrentMission < Class->MissionCount) {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- TimeOut = mission->Data.Value * (TICKS_PER_MINUTE/10);
- Target = TARGET_NONE;
- switch (mission->Mission) {
- case TMISSION_MOVECELL:
- Assign_Mission_Target(::As_Target((CELL)(mission->Data.Value)));
- break;
- case TMISSION_MOVE:
- if ((unsigned)mission->Data.Value < WAYPT_COUNT && Member != NULL) {
- FootClass * leader = Fetch_A_Leader();
- CELL movecell = Scen.Waypoint[mission->Data.Value];
- if (!Is_Leaving_Map()) {
- if (leader->Can_Enter_Cell(movecell) != MOVE_OK) {
- movecell = Map.Nearby_Location(movecell, leader->Techno_Type_Class()->Speed);
- }
- }
- Assign_Mission_Target(::As_Target(movecell));
- Target = ::As_Target(movecell);
- }
- break;
- case TMISSION_ATT_WAYPT:
- case TMISSION_PATROL:
- case TMISSION_SPY:
- if ((unsigned)mission->Data.Value < WAYPT_COUNT) {
- Assign_Mission_Target(::As_Target(Scen.Waypoint[mission->Data.Value]));
- }
- break;
- case TMISSION_ATTACKTARCOM:
- Assign_Mission_Target(mission->Data.Value);
- break;
- case TMISSION_UNLOAD:
- default:
- Assign_Mission_Target(TARGET_NONE);
- break;
- }
- } else {
- delete this;
- return;
- }
- }
- /*
- ** Perform mission of the team. This depends on the mission list.
- */
- if (Member != NULL && IsMoving && !IsReforming && !IsUnderStrength) {
- /*
- ** If the current Target has been dealt with but the mission target
- ** has not, then the current target needs to be reset to the mission
- ** target.
- */
- if (!Target_Legal(Target)) {
- Target = MissionTarget;
- }
- /*
- ** If the current mission is one that times out, then check for
- ** this case. If it has timed out then advance to the next
- ** mission in the list or disband the team.
- */
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- // FootClass * member = Member;
- switch (mission->Mission) {
- case TMISSION_PATROL:
- TMission_Patrol();
- break;
- case TMISSION_FORMATION:
- TMission_Formation();
- break;
- case TMISSION_ATTACKTARCOM:
- case TMISSION_ATTACK:
- TMission_Attack();
- break;
- case TMISSION_LOAD:
- TMission_Load();
- break;
- case TMISSION_DEPLOY:
- TMission_Deploy();
- break;
- case TMISSION_UNLOAD:
- TMission_Unload();
- break;
- case TMISSION_MOVE:
- case TMISSION_MOVECELL:
- Coordinate_Move();
- break;
- /*
- ** All members of this team become invulnerable as if by magic.
- */
- case TMISSION_INVULNERABLE:
- TMission_Invulnerable();
- break;
- case TMISSION_GUARD:
- Coordinate_Regroup();
- break;
- case TMISSION_DO:
- Coordinate_Do();
- break;
- case TMISSION_SET_GLOBAL:
- TMission_Set_Global();
- break;
- case TMISSION_ATT_WAYPT:
- if (!Target_Legal(MissionTarget)) {
- Assign_Mission_Target(TARGET_NONE);
- IsNextMission = true;
- } else {
- Coordinate_Attack();
- }
- break;
- case TMISSION_SPY:
- TMission_Spy();
- break;
- case TMISSION_HOUND_DOG:
- TMission_Follow();
- break;
- case TMISSION_LOOP:
- TMission_Loop();
- break;
- }
- /*
- ** Check for mission time out condition. If the mission does in fact time out, then
- ** flag it so that the team mission list will advance.
- */
- switch (mission->Mission) {
- // case TMISSION_UNLOAD:
- case TMISSION_GUARD:
- if (TimeOut == 0) {
- IsNextMission = true;
- }
- break;
- }
- } else {
- if (IsMoving) {
- IsReforming = !Coordinate_Regroup();
- } else {
- Coordinate_Move();
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::Add -- Adds specified object to team. *
- * *
- * Use this routine to add the specified object to the team. The object is checked to make *
- * sure that it can be assigned to the team. If it can't, then the object will be left *
- * alone and false will be returned. *
- * *
- * INPUT: obj -- Pointer to the object that is to be assigned to this team. *
- * *
- * OUTPUT: bool; Was the unit added to the team? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- * 01/02/1995 JLB : Initiation flag setup. *
- * 08/06/1995 JLB : Allows member stealing from lesser priority teams. *
- *=============================================================================================*/
- bool TeamClass::Add(FootClass * obj)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- if (!obj) return(false);
- int typeindex;
- if (!Can_Add(obj, typeindex)) return(false);
- /*
- ** All is ok to add the object to the team, but if the object is already part of
- ** another team, then it must be removed from that team first.
- */
- if (obj->Team.Is_Valid()) {
- obj->Team->Remove(obj);
- }
- /*
- ** Actually add the object to the team.
- */
- Quantity[typeindex]++;
- obj->IsInitiated = (Member == NULL);
- obj->Member = Member;
- Member = obj;
- obj->Team = this;
- /*
- ** If a common trigger is designated for this team type, then attach the
- ** trigger to this team member.
- */
- if (Trigger.Is_Valid()) {
- obj->Attach_Trigger(Trigger);
- }
- Total++;
- Risk += obj->Risk();
- if (Zone == TARGET_NONE) {
- Calc_Center(Zone, ClosestMember);
- }
- /*
- ** Return with success, since the object was added to the team.
- */
- IsAltered = JustAltered = true;
- return(true);
- }
- /***********************************************************************************************
- * TeamClass::Can_Add -- Determines if the specified object can be added to team. *
- * *
- * This routine will examine the team and determine if the specified object can be *
- * properly added to this team. This is a security check to filter out those objects that *
- * should not be added because of conflicting priorities or other restrictions. *
- * *
- * INPUT: obj -- Pointer to the candidate object that is being checked for legal *
- * adding to this team. *
- * *
- * typeindex-- The class index number (according to the team type's class array) that *
- * the candidate object is classified as. The routine processes much *
- * faster if you can provide this information, but if you don't, the *
- * routine will figure it out. *
- * *
- * OUTPUT: bool; Can the specified object be added to this team? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 02/27/1996 JLB : Created. *
- *=============================================================================================*/
- bool TeamClass::Can_Add(FootClass * obj, int & typeindex) const
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- /*
- ** Trying to add the team member to itself is an error condition.
- */
- if (obj->Team == this) {
- return(false);
- }
- /*
- ** The object must be active, a member of this house. A special dispensation is given to
- ** units that are in radio contact. It is presumed that they are very busy and should
- ** not be disturbed.
- */
- if (!_Is_It_Breathing(obj) || obj->In_Radio_Contact() || obj->House != House) {
- return(false);
- }
- /*
- ** If the object is doing some mission that precludes it from joining
- ** a team then don't add it.
- */
- if (obj->Mission != MISSION_NONE && !MissionClass::Is_Recruitable_Mission(obj->Mission)) {
- return(false);
- }
- /*
- ** If this object is part of another team, then check to make sure that it
- ** is permitted to leave the other team in order to join this one. If not,
- ** then no further processing is allowed -- bail.
- */
- if (obj->Team.Is_Valid() && (obj->Team->Class->RecruitPriority >= Class->RecruitPriority)) {
- return(false);
- }
- /*
- ** Aircraft that have no ammo for their weapons cannot be recruited into a team.
- */
- if (obj->What_Am_I() == RTTI_AIRCRAFT && obj->Techno_Type_Class()->PrimaryWeapon != NULL && !obj->Ammo) {
- return(false);
- }
- /*
- ** Search for the exact member index that the candidate object matches.
- ** If no match could be found, then adding the object to the team cannot
- ** occur.
- */
- for (typeindex = 0; typeindex < Class->ClassCount; typeindex++) {
- if (Class->Members[typeindex].Class == &obj->Class_Of()) {
- break;
- }
- }
- if (typeindex == Class->ClassCount) {
- return(false);
- }
- /*
- ** If the team is already full of this type, then adding the object is not allowed.
- ** Return with a failure flag in this case.
- */
- if (Quantity[typeindex] >= Class->Members[typeindex].Quantity) {
- return(false);
- }
- return(true);
- }
- /***********************************************************************************************
- * TeamClass::Remove -- Removes the specified object from the team. *
- * *
- * Use this routine to remove an object from a team. Objects removed from the team are *
- * then available to be recruited by other teams, or even by the same team at a later time. *
- * *
- * INPUT: obj -- Pointer to the object that is to be removed from this team. *
- * *
- * typeindex-- Optional index of where this object type is specified in the type *
- * type class. This parameter can be omitted. It only serves to make *
- * the removal process faster. *
- * *
- * OUTPUT: bool; Was the object removed from this team? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- * 01/02/1995 JLB : Initiation tracking and team captain selection. *
- *=============================================================================================*/
- bool TeamClass::Remove(FootClass * obj, int typeindex)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- /*
- ** Make sure that the object is in fact a member of this team. If not, then it can't
- ** be removed. Return success because the end result is the same.
- */
- if (this != obj->Team) {
- return(true);
- }
- /*
- ** Detach the common trigger for this team type. Only current and active members of the
- ** team have that trigger attached. The exception is for player team members that
- ** get removed from a reinforcement team.
- */
- if (obj->Trigger == Trigger && !obj->House->IsPlayerControl) {
- obj->Attach_Trigger(NULL);
- }
- /*
- ** If the proper team index was not provided, then find it in the type type class. The
- ** team type class will not be set if the appropriate type could not be found
- ** for this object. This indicates that the object was illegally added. Continue to
- ** process however, since removing this object from the team is a good idea.
- */
- if (typeindex == -1) {
- for (typeindex = 0; typeindex < Class->ClassCount; typeindex++) {
- if (Class->Members[typeindex].Class == &obj->Class_Of()) {
- break;
- }
- }
- }
- /*
- ** Decrement the counter for the team class. There is now one less of this object type.
- */
- if (typeindex < Class->ClassCount) {
- Quantity[typeindex]--;
- }
- /*
- ** Actually remove the object from the team. Scan through the team members
- ** looking for the one that matches the one specified. If it is found, it
- ** is unlinked from the member chain. During this scan, a check is made to
- ** ensure that at least one remaining member is still initiated. If not, then
- ** a new team captain must be chosen.
- */
- bool initiated = false;
- FootClass * prev = 0;
- FootClass * curr = Member;
- bool found = false;
- while (curr != NULL && (!found || !initiated)) {
- if (curr == obj) {
- if (prev != NULL) {
- prev->Member = curr->Member;
- } else {
- Member = curr->Member;
- }
- FootClass * temp = curr->Member;
- curr->Member = 0;
- curr->Team = 0;
- curr->SuspendedMission = MISSION_NONE;
- curr->SuspendedNavCom = TARGET_NONE;
- curr->SuspendedTarCom = TARGET_NONE;
- curr = temp;
- Total--;
- found = true;
- Risk -= obj->Risk();
- continue;
- }
- /*
- ** If this (remaining) member is initiated, then keep a record of this.
- */
- initiated |= curr->IsInitiated;
- prev = curr;
- curr = curr->Member;
- }
- /*
- ** A unit that breaks off of a team will enter idle mode.
- */
- obj->Enter_Idle_Mode();
- /*
- ** If, after removing the team member, there are no initiated members left
- ** in the team, then just make the first remaining member of the team the
- ** team captain. Mark the center location of the team as invalid so that
- ** it will be centered around the captain.
- */
- if (!initiated && Member != NULL) {
- Member->IsInitiated = true;
- Zone = TARGET_NONE;
- }
- /*
- ** Must record that the team composition has changed. At the next opportunity,
- ** the team members will be counted and appropriate AI adjustments made.
- */
- IsAltered = JustAltered = true;
- return(true);
- }
- /***********************************************************************************************
- * TeamClass::Recruit -- Attempts to recruit members to the team for the given index ID. *
- * *
- * This routine will take the given index ID and scan for available objects of that type *
- * to recruit to the team. Recruiting will continue until that object type has either *
- * been exhausted or if the team's requirement for that type has been filled. *
- * *
- * INPUT: typeindex -- The index for the object type to recruit. The index is used to *
- * look into the type type's array of object types that make up this *
- * team. *
- * *
- * OUTPUT: Returns with the number of objects added to this team. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- * 04/10/1995 JLB : Scans for units too. *
- *=============================================================================================*/
- int TeamClass::Recruit(int typeindex)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- COORDINATE center = As_Coord(Zone);
- if (Class->Origin != -1) {
- center = Cell_Coord(Scen.Waypoint[Class->Origin]);
- }
- int added = 0; // Total number added to team.
- /*
- ** Quick check to see if recruiting is really allowed for this index or not.
- */
- if (Class->Members[typeindex].Quantity > Quantity[typeindex]) {
- switch (Class->Members[typeindex].Class->What_Am_I()) {
- /*
- ** For infantry objects, sweep through the infantry in the game looking for
- ** ones owned by the house that owns the team. When found, try to add.
- */
- case RTTI_INFANTRYTYPE:
- case RTTI_INFANTRY:
- {
- InfantryClass * best = 0;
- int bestdist = -1;
- for (int index = 0; index < Infantry.Count(); index++) {
- InfantryClass * infantry = Infantry.Ptr(index);
- int d = infantry->Distance(center);
- if ((d < bestdist || bestdist == -1) && Can_Add(infantry, typeindex)) {
- best = infantry;
- bestdist = d;
- }
- }
- if (best) {
- best->Assign_Target(TARGET_NONE);
- Add(best);
- added++;
- }
- }
- break;
- case RTTI_AIRCRAFTTYPE:
- case RTTI_AIRCRAFT:
- {
- AircraftClass * best = 0;
- int bestdist = -1;
- for (int index = 0; index < Aircraft.Count(); index++) {
- AircraftClass * aircraft = Aircraft.Ptr(index);
- int d = aircraft->Distance(center);
- if ((d < bestdist || bestdist == -1) && Can_Add(aircraft, typeindex)) {
- best = aircraft;
- bestdist = d;
- }
- }
- if (best) {
- best->Assign_Target(TARGET_NONE);
- Add(best);
- added++;
- }
- }
- break;
- case RTTI_UNITTYPE:
- case RTTI_UNIT:
- {
- UnitClass * best = 0;
- int bestdist = -1;
- for (int index = 0; index < Units.Count(); index++) {
- UnitClass * unit = Units.Ptr(index);
- int d = unit->Distance(center);
- if (unit->House == House && unit->Class == Class->Members[typeindex].Class) {
- if ((d < bestdist || bestdist == -1) && Can_Add(unit, typeindex)) {
- best = unit;
- bestdist = d;
- }
- }
- if (best) {
- best->Assign_Target(TARGET_NONE);
- Add(best);
- added++;
- /*
- ** If a transport is added to the team, the occupants
- ** are added by default.
- */
- FootClass * f = best->Attached_Object();
- while (f) {
- Add(f);
- f = (FootClass *)(ObjectClass *)f->Next;
- }
- }
- }
- }
- break;
- case RTTI_VESSELTYPE:
- case RTTI_VESSEL:
- {
- VesselClass * best = 0;
- int bestdist = -1;
- for (int index = 0; index < Vessels.Count(); index++) {
- VesselClass * vessel = Vessels.Ptr(index);
- int d = vessel->Distance(center);
- if (vessel->House == House && vessel->Class == Class->Members[typeindex].Class) {
- if ((d < bestdist || bestdist == -1) && Can_Add(vessel, typeindex)) {
- best = vessel;
- bestdist = d;
- }
- }
- if (best) {
- best->Assign_Target(TARGET_NONE);
- Add(best);
- added++;
- /*
- ** If a transport is added to the team, the occupants
- ** are added by default.
- */
- FootClass * f = best->Attached_Object();
- while (f) {
- Add(f);
- f = (FootClass *)(ObjectClass *)f->Next;
- }
- }
- }
- }
- break;
- }
- }
- return(added);
- }
- /***********************************************************************************************
- * TeamClass::Detach -- Removes specified target from team tracking. *
- * *
- * When a target object is about to be removed from the game (e.g., it was killed), then *
- * any team that is looking at that target must abort from that target. *
- * *
- * INPUT: target -- The target object that is going to be removed from the game. *
- * *
- * all -- Is the target going away for good as opposed to just cloaking/hiding? *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Detach(TARGET target, bool )
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- /*
- ** If the target to detach matches the target of this team, then remove
- ** the target from this team's Tar/Nav com and let the chips fall
- ** where they may.
- */
- if (Target == target) {
- Target = TARGET_NONE;
- }
- if (MissionTarget == target) {
- MissionTarget = TARGET_NONE;
- }
- if (Trigger.Is_Valid() && Trigger->As_Target() == target) {
- Trigger = 0;
- }
- }
- /***********************************************************************************************
- * TeamClass::Calc_Center -- Determines average location of team members. *
- * *
- * Use this routine to calculate the "center" location of the team. This is the average *
- * position of all members of the team. Using this center value it is possible to tell *
- * if a team member is too far away and where to head to in order to group up. *
- * *
- * INPUT: center -- Average center target location of the team. Only initiated members *
- * will be considered. *
- * *
- * close_member--Location (as target) of the unit that is closest to the team's *
- * target. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Calc_Center(TARGET & center, TARGET & close_member) const
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- /*
- ** Presume there is no center. This will be confirmed in the following scanning
- ** operation.
- */
- close_member = TARGET_NONE;
- center = TARGET_NONE;
- FootClass const * team_member = Member; // Working team member pointer.
- /*
- ** If there are no members of the team, then there can be no center point of the team.
- */
- if (team_member == NULL) return;
- /*
- ** If the team is supposed to follow a nearby friendly unit, then the
- ** team's "center" will actually be that unit. Otherwise, calculated the
- ** average center location for the team.
- */
- if (Class->MissionList[CurrentMission].Mission == TMISSION_HOUND_DOG) {
- /*
- ** First pick a member of the team. The closest friendly object to that member
- ** will be picked.
- */
- if (!team_member) return;
- FootClass const * closest = NULL; // Current closest friendly object.
- int distance = -1; // Record of last closest distance calc.
- /*
- ** Scan through all vehicles.
- */
- for (int unit_index = 0; unit_index < Units.Count(); unit_index++) {
- FootClass const * trial_unit = Units.Ptr(unit_index);
- if (_Is_It_Breathing(trial_unit) && trial_unit->House->Is_Ally(House) && trial_unit->Team != this) {
- int trial_distance = team_member->Distance(trial_unit);
- if (distance == -1 || trial_distance < distance) {
- distance = trial_distance;
- closest = trial_unit;
- }
- }
- }
- /*
- ** Scan through all infantry.
- */
- for (int infantry_index = 0; infantry_index < Infantry.Count(); infantry_index++) {
- FootClass const * trial_infantry = Infantry.Ptr(infantry_index);
- if (_Is_It_Breathing(trial_infantry) && trial_infantry->House->Is_Ally(House) && trial_infantry->Team != this) {
- int trial_distance = team_member->Distance(trial_infantry);
- if (distance == -1 || trial_distance < distance) {
- distance = trial_distance;
- closest = trial_infantry;
- }
- }
- }
- /*
- ** Scan through all vessels.
- */
- for (int vessel_index = 0; vessel_index < Vessels.Count(); vessel_index++) {
- FootClass const * trial_vessel = Vessels.Ptr(vessel_index);
- if (_Is_It_Breathing(trial_vessel) && trial_vessel->House->Is_Ally(House) && trial_vessel->Team != this) {
- int trial_distance = team_member->Distance(trial_vessel);
- if (distance == -1 || trial_distance < distance) {
- distance = trial_distance;
- closest = trial_vessel;
- }
- }
- }
- /*
- ** Set the center location as actually the friendly object that is closest. If there
- ** is no friendly object, then don't set any center location at all.
- */
- if (closest) {
- center = closest->As_Target();
- close_member = Member->As_Target();
- }
- } else {
- long x = 0; // Accumulated X coordinate.
- long y = 0; // Accumulated Y coordinate.
- int dist = 0; // Closest recorded distance to team target.
- int quantity = 0; // Number of team members counted.
- FootClass const * closest = 0; // Closest member to target.
- /*
- ** Scan through all team members and accumulate the X and Y component of their
- ** location. Only team members that are active will be considered. Also keep
- ** track of the team member that is closest to the team's target.
- */
- while (team_member != NULL) {
- if (_Is_It_Playing(team_member)) {
- /*
- ** Accumulate X and Y components of qualified team members.
- */
- x += Coord_X(team_member->Coord);
- y += Coord_Y(team_member->Coord);
- quantity++;
- /*
- ** Keep a record of the team member that is nearest to the team's
- ** target.
- */
- int try_dist = team_member->Distance(Target);
- if (!dist || try_dist < dist) {
- dist = try_dist;
- closest = team_member;
- }
- }
- team_member = team_member->Member;
- }
- /*
- ** If there were any qualifying members, then the team's center point can be
- ** determined.
- */
- if (quantity) {
- x /= quantity;
- y /= quantity;
- COORDINATE coord = XY_Coord((int)x, (int)y);
- center = ::As_Target(coord);
- /*
- ** If the center location is impassable, then just pick the location of
- ** one of the team members.
- */
- if (!closest->Can_Enter_Cell(As_Cell(center))) {
- // if (Class->Origin != -1) {
- // center = ::As_Target(Scen.Waypoint[Class->Origin]);
- // } else {
- center = ::As_Target(Coord_Cell(closest->Center_Coord()));
- // }
- }
- }
- /*
- ** Record the position of the closest member to the team's target and
- ** that will be used as the regroup point.
- */
- if (closest != NULL) {
- close_member = ::As_Target(Coord_Cell(closest->Center_Coord()));
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::Took_Damage -- Informs the team when the team member takes damage. *
- * *
- * This routine is used when a team member takes damage. Usually the team will react in *
- * some fashion to the attack. This reaction can range from running away to assigning this *
- * new target as the team's target. *
- * *
- * INPUT: obj -- The team member that was damaged. *
- * *
- * result -- The severity of the damage taken. *
- * *
- * source -- The perpetrator of the damage. *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 12/29/1994 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Took_Damage(FootClass * , ResultType result, TechnoClass * source)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- if ((result != RESULT_NONE) && (!Class->IsSuicide)) {
- if (!IsMoving) {
- // TCTCTC
- // Should run to a better hiding place or disband into a group of hunting units.
- } else {
- /*
- ** Respond to the attack, but not if we're an aircraft or a LST.
- */
- if (source && !Is_A_Member(source) && Member && Member->What_Am_I() != RTTI_AIRCRAFT && (Member->What_Am_I() != RTTI_VESSEL || *(VesselClass *)((FootClass *)Member) != VESSEL_TRANSPORT)) {
- if (Target != source->As_Target()) {
- /*
- ** Don't change target if the team's target is one that can fire as well. There is
- ** no point in endlessly shuffling between targets that have firepower.
- */
- if (Target_Legal(Target)) {
- TechnoClass * techno = As_Techno(Target);
- if (techno && ((TechnoTypeClass const &)techno->Class_Of()).PrimaryWeapon != NULL) {
- if (techno->In_Range(As_Coord(Zone), 0)) {
- return;
- }
- }
- }
- /*
- ** Don't change target to aggressor if the aggressor cannot normally be attacked.
- */
- if (source->What_Am_I() == RTTI_AIRCRAFT || (source->What_Am_I() == RTTI_VESSEL && (Member->What_Am_I() == RTTI_UNIT || Member->What_Am_I() == RTTI_INFANTRY))) {
- return;
- }
- Target = source->As_Target();
- }
- }
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::Coordinate_Attack -- Handles coordinating a team attack. *
- * *
- * This function is called when the team knows what it should attack. This routine will *
- * give the necessary orders to the members of the team. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/06/1995 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Coordinate_Attack(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- if (!Target_Legal(Target)) {
- Target = MissionTarget;
- }
- /*
- ** Check if they're attacking a cell. If the contents of the cell are
- ** a bridge or a building/unit/techno, then it's a valid target. Otherwise,
- ** the target is invalid. This only applies to non-aircraft teams. An aircraft team
- ** can "attack" an empty cell and this is perfectly ok (paratrooper drop and parabombs
- ** are prime examples).
- */
- if (Is_Target_Cell(Target) && Member != NULL && Fetch_A_Leader()->What_Am_I() != RTTI_AIRCRAFT) {
- CellClass *cellptr = &Map[As_Cell(Target)];
- TemplateType tt = cellptr->TType;
- if (cellptr->Cell_Object()) {
- Target = cellptr->Cell_Object()->As_Target();
- } else {
- if (tt != TEMPLATE_BRIDGE1 && tt != TEMPLATE_BRIDGE2 &&
- tt != TEMPLATE_BRIDGE1H && tt != TEMPLATE_BRIDGE2H &&
- tt != TEMPLATE_BRIDGE_1A && tt != TEMPLATE_BRIDGE_1B &&
- tt != TEMPLATE_BRIDGE_2A && tt != TEMPLATE_BRIDGE_2B &&
- tt != TEMPLATE_BRIDGE_3A && tt != TEMPLATE_BRIDGE_3B ) {
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- FootClass *unit = Member;
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- if(unit->What_Am_I() != RTTI_UNIT ||
- *(UnitClass *)unit != UNIT_CHRONOTANK ||
- mission->Mission != TMISSION_SPY)
- #endif
- Target = 0; // invalidize the target so it'll go to next mission.
- }
- }
- }
- if (!Target_Legal(Target)) {
- IsNextMission = true;
- } else {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- FootClass * unit = Member;
- while (unit != NULL) {
- Coordinate_Conscript(unit);
- if (_Is_It_Playing(unit)) {
- if (mission->Mission == TMISSION_SPY && unit->What_Am_I() == RTTI_INFANTRY && *(InfantryClass *)unit == INFANTRY_SPY) {
- unit->Assign_Mission(MISSION_CAPTURE);
- unit->Assign_Target(Target);
- } else {
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- if (mission->Mission == TMISSION_SPY && unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_CHRONOTANK) {
- UnitClass *tank = (UnitClass *)unit;
- tank->Teleport_To(::As_Cell(Target));
- tank->MoebiusCountDown = ChronoTankDuration * TICKS_PER_MINUTE;
- Scen.Do_BW_Fade();
- Sound_Effect(VOC_CHRONOTANK1, unit->Coord);
- tank->Assign_Target(TARGET_NONE);
- tank->Assign_Mission(MISSION_GUARD);
- } else {
- #endif
- if (unit->Mission != MISSION_ATTACK && unit->Mission != MISSION_ENTER && unit->Mission != MISSION_CAPTURE) {
- unit->Transmit_Message(RADIO_OVER_OUT);
- unit->Assign_Mission(MISSION_ATTACK);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Destination(TARGET_NONE);
- }
- }
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- }
- #endif
- if (unit->TarCom != Target) {
- unit->Assign_Target(Target);
- }
- }
- unit = unit->Member;
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::Coordinate_Regroup -- Handles team idling (regrouping). *
- * *
- * This routine is called when the team must delay at its current location. Team members *
- * are grouped together by this function. It is called when the team needs to sit and *
- * wait. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Has the team completely regrouped? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/06/1995 JLB : Created. *
- *=============================================================================================*/
- bool TeamClass::Coordinate_Regroup(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- bool retval = true;
- /*
- ** Regroup default logic.
- */
- while (unit != NULL) {
- Coordinate_Conscript(unit);
- if (_Is_It_Playing(unit)) {
- if (unit->Distance(Zone) > Rule.StrayDistance && (unit->Mission != MISSION_GUARD_AREA || !Target_Legal(unit->TarCom))) {
- if (!Target_Legal(unit->NavCom)) {
- // TCTCTC
- // if (!Target_Legal(unit->NavCom) || ::Distance(unit->NavCom, Zone) > Rule.StrayDistance) {
- unit->Assign_Mission(MISSION_MOVE);
- unit->Assign_Destination(Zone);
- retval = false;
- if (!unit->IsFormationMove) {
- unit->Assign_Mission(MISSION_MOVE);
- CELL dest = unit->Adjust_Dest(As_Cell(Zone));
- unit->Assign_Destination(::As_Target(dest));
- } else {
- retval = true; // formations are always considered regrouped.
- }
- }
- } else {
- /*
- ** The team is regrouping, so just sit here and wait.
- */
- if (unit->Mission != MISSION_GUARD_AREA) {
- unit->Assign_Mission(MISSION_GUARD);
- unit->Assign_Destination(TARGET_NONE);
- }
- }
- }
- unit = unit->Member;
- }
- return(retval);
- }
- /***********************************************************************************************
- * TeamClass::Coordinate_Do -- Handles the team performing specified mission. *
- * *
- * This will assign the specified mission to the team. If there are team members that are *
- * too far away from the center of the team, then they will be told to move to the team's *
- * location. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: This only works if the special mission the team members are to perform does not *
- * require extra parameters. The ATTACK and MOVE missions are particularly bad. *
- * *
- * HISTORY: *
- * 05/11/1996 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Coordinate_Do(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- MissionType do_mission = Class->MissionList[CurrentMission].Data.Mission;
- /*
- ** For each unit either head it back to the team center or give it the main
- ** team mission order as appropriate.
- */
- while (unit != NULL) {
- Coordinate_Conscript(unit);
- if (_Is_It_Playing(unit)) {
- if (!Target_Legal(unit->TarCom) && !Target_Legal(unit->NavCom) && unit->Distance(Zone) > Rule.StrayDistance * 2) {
- /*
- ** Only if the unit isn't already heading to regroup with the team, will it
- ** be given orders to do so.
- */
- unit->Assign_Mission(MISSION_MOVE);
- unit->Assign_Destination(Zone);
- unit->Assign_Mission(MISSION_MOVE);
- CELL dest = unit->Adjust_Dest(As_Cell(Zone));
- unit->Assign_Destination(::As_Target(dest));
- } else {
- /*
- ** The team is regrouping, so just sit here and wait.
- */
- if (!Target_Legal(unit->TarCom) && !Target_Legal(unit->NavCom) && unit->Mission != do_mission) {
- unit->ArchiveTarget = TARGET_NONE;
- unit->Assign_Mission(do_mission);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Destination(TARGET_NONE);
- }
- }
- }
- unit = unit->Member;
- }
- }
- /***********************************************************************************************
- * TeamClass::Coordinate_Move -- Handles team movement coordination. *
- * *
- * This routine is called when the team must move to a new location. Movement and grouping *
- * commands associated with this task are initiated here. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/06/1995 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Coordinate_Move(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- bool finished = true;
- bool found = false;
- if (!Target_Legal(Target)) {
- Target = MissionTarget;
- }
- if (Target_Legal(Target)) {
- if (!Lagging_Units()) {
- while (unit != NULL) {
- /*
- ** Tell the unit, if necessary, that it should regroup
- ** with the main team location. If the unit is regrouping, then
- ** the team should continue NOT qualify as fully reaching the desired
- ** location.
- */
- if (Coordinate_Conscript(unit)) {
- finished = false;
- }
- if (unit->Mission == MISSION_UNLOAD || unit->MissionQueue == MISSION_UNLOAD) {
- finished = false;
- }
- if (_Is_It_Playing(unit) && unit->Mission != MISSION_UNLOAD && unit->MissionQueue != MISSION_UNLOAD) {
- int stray = Rule.StrayDistance;
- if (unit->What_Am_I() == RTTI_AIRCRAFT) {
- stray *= 3;
- }
- if (unit->What_Am_I() == RTTI_INFANTRY && ((InfantryClass const *)unit)->Class->IsDog) {
- if (Target_Legal(unit->TarCom)) stray = unit->Techno_Type_Class()->ThreatRange;
- if (Target_Legal(unit->TarCom) && unit->Distance(unit->TarCom) > stray) {
- unit->Assign_Target(TARGET_NONE);
- }
- }
- found = true;
- int dist = unit->Distance(Target);
- if (unit->IsFormationMove) {
- if (::As_Target(Coord_Cell(unit->Coord)) != unit->NavCom) {
- dist = Rule.StrayDistance + 1; // formation moves must be exact.
- }
- }
- if (dist > stray ||
- (unit->What_Am_I() == RTTI_AIRCRAFT &&
- // (unit->In_Which_Layer() == LAYER_TOP &&
- ((AircraftClass *)unit)->Height > 0 &&
- Coord_Cell(unit->Center_Coord()) != As_Cell(Target) &&
- !((AircraftClass *)unit)->Class->IsFixedWing &&
- Class->MissionList[CurrentMission+1].Mission != TMISSION_MOVE)) {
- bool wasform = false;
- if (unit->Mission != MISSION_MOVE) {
- unit->Assign_Mission(MISSION_MOVE);
- }
- if (unit->NavCom != Target) {
- /*
- ** Check if this destination should be adjusted for
- ** a formation move
- */
- if (Is_Target_Cell(Target) && unit->IsFormationMove) {
- CELL newcell = unit->Adjust_Dest(As_Cell(Target));
- if (Coord_Cell(unit->Coord) != newcell) {
- unit->Assign_Destination(::As_Target(newcell));
- } else {
- unit->Assign_Mission(MISSION_GUARD);
- unit->Assign_Destination(TARGET_NONE);
- wasform = true;
- }
- } else {
- unit->Assign_Destination(Target);
- }
- }
- if (!wasform) {
- finished = false;
- }
- } else {
- if (unit->Mission == MISSION_MOVE && (!Target_Legal(unit->NavCom) || Distance(unit->NavCom) < CELL_LEPTON_W)) {
- unit->Assign_Destination(TARGET_NONE);
- unit->Enter_Idle_Mode();
- }
- }
- /*
- ** If any member still has a valid NavCom then consider this
- ** movement mission to still be in progress. This will ensure
- ** that the members come to a complete stop before the next
- ** mission commences. Without this, the team will prematurely
- ** start on the next mission even when all members aren't yet
- ** in their proper spot.
- */
- if (Target_Legal(unit->NavCom)) {
- finished = false;
- }
- }
- unit = unit->Member;
- }
- } else {
- finished = false;
- }
- }
- /*
- ** If there are no initiated members to this team, then it certainly
- ** could not have managed to move to the target destination.
- */
- if (!found) {
- finished = false;
- }
- /*
- ** If all the team members are close enough to the desired destination, then
- ** move to the next mission.
- */
- if (finished && IsMoving) {
- IsNextMission = true;
- }
- }
- /***********************************************************************************************
- * TeamClass::Lagging_Units -- Finds and orders any lagging units to catch up. *
- * *
- * This routine will examine the team and find any lagging units. The units are then *
- * ordered to catch up to the team member that is closest to the team's destination. This *
- * routine will not do anything unless lagging members are suspected. This fact is *
- * indicated by setting the IsLagging flag. The flag is set by some outside agent. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: Be sure to set IsLagging for the team if a lagging member is suspected. *
- * *
- * HISTORY: *
- * 08/01/1995 PWG : Created. *
- * 04/11/1996 JLB : Modified. *
- *=============================================================================================*/
- bool TeamClass::Lagging_Units(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- bool lag = false;
- //BG: HACK - if it's in a formation move, then disable the check for
- // VG added NULL check laggers, 'cause they're all moving simultaneously.
- if (unit != NULL && unit->IsFormationMove) IsLagging = false;
- /*
- ** If the IsLagging bit is not set, then obviously there are no lagging
- ** units.
- */
- if (!IsLagging) return(false);
- /*
- ** Scan through all of the units, searching for units who are having
- ** trouble keeping up with the pack.
- */
- while (unit != NULL) {
- if (_Is_It_Playing(unit)) {
- int stray = Rule.StrayDistance;
- if (unit->What_Am_I() == RTTI_AIRCRAFT) {
- stray *= 3;
- }
- /*
- ** If we find a unit who has fallen too far away from the center of
- ** the pack, then we need to order that unit to catch up with the
- ** first unit.
- */
- if (unit->Distance(ClosestMember) > stray) {
- // TCTCTC
- if (!Target_Legal(unit->NavCom)) {
- // if (!Target_Legal(unit->NavCom) || ::Distance(unit->NavCom, ClosestMember) > Rule.StrayDistance) {
- unit->Assign_Mission(MISSION_MOVE);
- unit->Assign_Destination(ClosestMember);
- }
- lag = true;
- } else {
- /*
- ** We need to order all of the other units to hold their
- ** position until all lagging units catch up.
- */
- if (unit->Mission != MISSION_GUARD) {
- unit->Assign_Mission(MISSION_GUARD);
- unit->Assign_Destination(TARGET_NONE);
- }
- }
- }
- unit = unit->Member;
- }
- /*
- ** Once we have handled the loop we know whether there are any lagging
- ** units or not.
- */
- IsLagging = lag;
- return(lag);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Unload -- Tells the team to unload passengers now. *
- * *
- * This routine tells all transport vehicles to unload passengers now. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/14/1995 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Unload(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- bool finished = true;
- while (unit != NULL) {
- Coordinate_Conscript(unit);
- if (_Is_It_Playing(unit)) {
- /*
- ** Only assign the mission if the unit is carrying a passenger, OR
- ** if the unit is a minelayer, with mines in it, and the cell it's
- ** on doesn't have a building (read: mine) in it already.
- */
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- /* Also, allow unload if it's a MAD Tank. */
- if (unit->Is_Something_Attached() || (unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_MINELAYER && unit->Ammo) || (unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_MAD )) {
- #else
- if (unit->Is_Something_Attached() || (unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_MINELAYER && unit->Ammo) ) {
- #endif
- if (unit->Is_Something_Attached()) {
- /*
- ** Passenger-carrying vehicles will always return false until
- ** they've unloaded all passengers.
- */
- finished = false;
- }
- /*
- ** The check for a building is located here because the mine layer may have
- ** already unloaded the mine but is still in the process of retracting
- ** the mine layer. During this time, it should not be considered to have
- ** finished its unload mission.
- */
- if (Map[unit->Center_Coord()].Cell_Building() == NULL && unit->Mission != MISSION_UNLOAD) {
- unit->Assign_Destination(TARGET_NONE);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Mission(MISSION_UNLOAD);
- finished = false;
- }
- } else {
- /*
- ** A loaner transport should vacate the map when all transported objects
- ** have been offloaded.
- */
- if (unit->IsALoaner) {
- Remove(unit);
- unit->Assign_Mission(MISSION_RETREAT);
- unit->Commence();
- }
- }
- }
- unit = unit->Member;
- }
- if (finished) {
- IsNextMission = true;
- }
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Load -- Tells the team to load onto the transport now. *
- * *
- * This routine tells all non-transport units in the team to climb onto the transport in the*
- * team. Note the transport must be a member of this team. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 06/28/1996 BWG : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Load(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- FootClass * trans = 0;
- /*
- ** First locate the transport in the team, if there is one. There should
- ** only be one transport in the team.
- */
- while(unit != NULL && trans == NULL) {
- if (unit->Techno_Type_Class()->Max_Passengers() > 0) {
- trans = unit;
- break;
- }
- unit = unit->Member;
- }
- /*
- ** In the case of no transport available, then consider the mission complete
- ** since it can never complete otherwise.
- */
- if (trans == NULL) {
- IsNextMission = true;
- return(1);
- }
- /*
- ** If the transport is already in radio contact, then this means that
- ** it is in the process of loading. During this time, don't bother to assign
- ** the enter mission to the other team members.
- */
- if (trans->In_Radio_Contact()) {
- return(1);
- }
- /*
- ** Find a member to assign the entry logic for.
- */
- bool finished = true;
- unit = Member; // re-point at the first member of the team again.
- while (unit != NULL && Total > 1) {
- Coordinate_Conscript(unit);
- /*
- ** Only assign the mission if the unit is not the transport.
- */
- if (_Is_It_Playing(unit) && unit != trans) {
- if (unit->Mission != MISSION_ENTER) {
- unit->Assign_Mission(MISSION_ENTER);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Destination(trans->As_Target());
- finished = false;
- break;
- }
- finished = false;
- }
- unit = unit->Member;
- }
- if (finished) {
- IsNextMission = true;
- }
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::Coordinate_Conscript -- Gives orders to new recruit. *
- * *
- * This routine will give the movement orders to the conscript so that it will group *
- * with the other members of the team. *
- * *
- * INPUT: unit -- Pointer to the conscript unit. *
- * *
- * OUTPUT: bool; Is the unit still scurrying to reach the team's current location? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/06/1995 JLB : Created. *
- *=============================================================================================*/
- bool TeamClass::Coordinate_Conscript(FootClass * unit)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- if (_Is_It_Breathing(unit) && !unit->IsInitiated) {
- if (unit->Distance(Zone) > Rule.StrayDistance) {
- if (!Target_Legal(unit->NavCom)) {
- unit->Assign_Mission(MISSION_MOVE);
- unit->Assign_Target(TARGET_NONE);
- unit->IsFormationMove = false;
- unit->Assign_Destination(Zone);
- }
- return(true);
- } else {
- /*
- ** This unit has gotten close enough to the team center so that it is
- ** now considered initiated. An initiated unit is considered when calculating
- ** the center of the team.
- */
- unit->IsInitiated = true;
- }
- }
- return(false);
- }
- /***************************************************************************
- * TeamClass::Is_A_Member -- Tests if a unit is a member of a team *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 05/16/1995 PWG : Created. *
- *=========================================================================*/
- bool TeamClass::Is_A_Member(void const * who) const
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- while (unit != NULL) {
- if (unit == who) {
- return(true);
- }
- unit = unit->Member;
- }
- return(false);
- }
- /***************************************************************************
- * TeamClass::Suspend_Teams -- Suspends activity for low priority teams *
- * *
- * INPUT: int priority - determines what is considered low priority. *
- * *
- * OUTPUT: *
- * *
- * WARNINGS: *
- * *
- * HISTORY: *
- * 06/19/1995 PWG : Created. *
- *=========================================================================*/
- void TeamClass::Suspend_Teams(int priority, HouseClass const * house)
- {
- for (int index = 0; index < Teams.Count(); index++) {
- TeamClass * team = Teams.Ptr(index);
- /*
- ** If a team is below the "survival priority level", then it gets
- ** destroyed. The team members are then free to be reassigned.
- */
- if (team != NULL && team->House == house && team->Class->RecruitPriority < priority) {
- FootClass * unit = team->Member;
- while (team->Member) {
- team->Remove(team->Member);
- }
- team->IsAltered = team->JustAltered = true;
- team->SuspendTimer = Rule.SuspendDelay * TICKS_PER_MINUTE;
- team->Suspended = true;
- }
- }
- }
- /***********************************************************************************************
- * TeamClass::Is_Leaving_Map -- Checks if team is in process of leaving the map *
- * *
- * This routine is used to see if the team is leaving the map. A team that is leaving the *
- * map gives implicit permission for its members to leave the map. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Is this team trying to leave the map? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 04/30/1996 JLB : Created. *
- *=============================================================================================*/
- bool TeamClass::Is_Leaving_Map(void) const
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- if (IsMoving && CurrentMission >= 0) {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- if (mission->Mission == TMISSION_MOVE && !Map.In_Radar(Scen.Waypoint[mission->Data.Value])) {
- return(true);
- }
- }
- return(false);
- }
- /***********************************************************************************************
- * TeamClass::Has_Entered_Map -- Determines if the entire team has entered the map. *
- * *
- * This will examine all team members and only if all of them have entered the map, will *
- * it return true. This routine is used to recognize the case of a team that has been *
- * generated off map and one that has already entered game play. This knowledge can lead *
- * to more intelligent behavior regarding team and member disposition. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: bool; Have all members of this team entered the map? *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 07/26/1996 JLB : Created. *
- *=============================================================================================*/
- bool TeamClass::Has_Entered_Map(void) const
- {
- bool ok = true;
- FootClass * foot = Member;
- while (foot != NULL) {
- if (!foot->IsLocked) {
- ok = false;
- break;
- }
- foot = (FootClass *)(ObjectClass *)(foot->Next);
- }
- return(ok);
- }
- /***********************************************************************************************
- * TeamClass::Scan_Limit -- Force all members of the team to have limited scan range. *
- * *
- * This routine is used when one of the team members cannot get within range of the team's *
- * target. In such a case, the team must be assigned a new target and all members of that *
- * team must recognize that a restricted target scan is required. This is done by clearing *
- * out the team's target so that it will be forced to search for a new one. Also, since the *
- * members are flagged for short scanning, whichever team member is picked to scan for a *
- * target will scan for one that is within range. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: none *
- * *
- * WARNINGS: The team will reassign its target as a result of this routine. *
- * *
- * HISTORY: *
- * 07/26/1996 JLB : Created. *
- *=============================================================================================*/
- void TeamClass::Scan_Limit(void)
- {
- Assign_Mission_Target(TARGET_NONE);
- FootClass * foot = Member;
- while (foot != NULL) {
- foot->Assign_Target(TARGET_NONE);
- foot->IsScanLimited = true;
- foot = foot->Member;
- }
- }
- /***********************************************************************************************
- * TeamClass::TMission_Formation -- Process team formation change command. *
- * *
- * This routine will change the team's formation to that specified in the team command *
- * parameter. It is presumed that the team will have further movement orders so that the *
- * formation can serve some purpose. Merely changing the formation doesn't alter the *
- * member's location. The team must be given a movement order before team member *
- * repositioning will occur. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the time to delay before further team actions should occur. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Formation(void)
- {
- FootClass * member = Member;
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- Formation = mission->Data.Formation;
- int group = ID + 10;
- int xdir = 0;
- int ydir = 0;
- bool evenodd = 1;
- HousesType house = (member != NULL) ? member->Owner() : HOUSE_NONE;
- /*
- ** Assign appropriate formation offsets for each of the members
- ** of this team.
- */
- switch (Formation) {
- case FORMATION_NONE:
- while (member != NULL) {
- member->Group = 0xFF;
- member->XFormOffset = 0x80000000;
- member->YFormOffset = 0x80000000;
- member->IsFormationMove = false;
- member = member->Member;
- }
- break;
- case FORMATION_TIGHT:
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = 0;
- member->YFormOffset = 0;
- member->IsFormationMove = true;
- member = member->Member;
- }
- break;
- case FORMATION_LOOSE:
- break;
- case FORMATION_WEDGE_N:
- ydir = -(Total / 2);
- xdir = 0;
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = xdir;
- member->YFormOffset = ydir;
- member->IsFormationMove = true;
- xdir = -xdir;
- evenodd ^= 1;
- if (!evenodd) {
- xdir -= 2;
- ydir += 2;
- }
- member = member->Member;
- }
- break;
- case FORMATION_WEDGE_E:
- xdir = (Total / 2);
- ydir = 0;
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = xdir;
- member->YFormOffset = ydir;
- member->IsFormationMove = true;
- ydir = -ydir;
- evenodd ^= 1;
- if (!evenodd) {
- xdir -= 2;
- ydir -= 2;
- }
- member = member->Member;
- }
- break;
- case FORMATION_WEDGE_S:
- ydir = (Total / 2);
- xdir = 0;
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = xdir;
- member->YFormOffset = ydir;
- member->IsFormationMove = true;
- xdir = -xdir;
- evenodd ^= 1;
- if (!evenodd) {
- xdir -= 2;
- ydir -= 2;
- }
- member = member->Member;
- }
- break;
- case FORMATION_WEDGE_W:
- xdir = -(Total / 2);
- ydir = 0;
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = xdir;
- member->YFormOffset = ydir;
- member->IsFormationMove = true;
- ydir = -ydir;
- evenodd ^= 1;
- if (!evenodd) {
- xdir += 2;
- ydir -= 2;
- }
- member = member->Member;
- }
- break;
- case FORMATION_LINE_NS:
- ydir = -(Total/2);
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = 0;
- member->YFormOffset = ydir;
- member->IsFormationMove = true;
- member = member->Member;
- ydir += 2;
- }
- break;
- case FORMATION_LINE_EW:
- xdir = -(Total/2);
- while (member != NULL) {
- member->Group = group;
- member->XFormOffset = xdir;
- member->YFormOffset = 0;
- member->IsFormationMove = true;
- member = member->Member;
- xdir += 2;
- }
- break;
- }
- /*
- ** Now calculate the group's movement type and speed
- */
- if (Formation != FORMATION_NONE && house != HOUSE_NONE) {
- TeamFormDataStruct& team_form_data = TeamFormData[house];
- team_form_data.TeamSpeed[group] = SPEED_WHEEL;
- team_form_data.TeamMaxSpeed[group] = MPH_LIGHT_SPEED;
- member = Member;
- while (member != NULL) {
- RTTIType mytype = member->What_Am_I();
- SpeedType memspeed;
- MPHType memmax;
- bool speedcheck = false;
- if (mytype == RTTI_INFANTRY) {
- memspeed = SPEED_FOOT;
- memmax = ((InfantryClass *)member)->Class->MaxSpeed;
- speedcheck = true;
- }
- if (mytype == RTTI_UNIT) {
- memspeed = ((UnitClass *)member)->Class->Speed;
- memmax = ((UnitClass *)member)->Class->MaxSpeed;
- speedcheck = true;
- }
- if (mytype == RTTI_VESSEL) {
- memspeed = ((VesselClass *)member)->Class->Speed;
- memmax = ((VesselClass *)member)->Class->MaxSpeed;
- speedcheck = true;
- }
- if (speedcheck) {
- if (memmax < team_form_data.TeamMaxSpeed[group]) {
- team_form_data.TeamMaxSpeed[group] = memmax;
- team_form_data.TeamSpeed[group] = memspeed;
- }
- }
- member = member->Member;
- }
- /*
- ** Now that it's all calculated, assign the movement type and
- ** speed to every member of the team.
- */
- member = Member;
- while (member != NULL) {
- member->FormationSpeed = team_form_data.TeamSpeed[group];
- member->FormationMaxSpeed = team_form_data.TeamMaxSpeed[group];
- if (member->What_Am_I() == RTTI_INFANTRY) {
- member->FormationSpeed = SPEED_FOOT;
- member->FormationMaxSpeed = MPH_SLOW_ISH;
- }
- member = member->Member;
- }
- }
- // Advance past the formation-setting command.
- IsNextMission = true;
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Attack -- Perform the team attack mission command. *
- * *
- * This will tell the team to attack the quarry specified in the team command. If the team *
- * already has a target, this it is presumed that this target take precidence and it won't *
- * be changed. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next team logic operation should occur. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Attack(void)
- {
- if (!Target_Legal(MissionTarget) && Member != NULL) {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- /*
- ** Pick a team leader that has a weapon. Only in the case of no
- ** team members having any weapons, will a member without a weapon
- ** be chosen.
- */
- FootClass const * candidate = Fetch_A_Leader();
- /*
- ** Have the team leader pick what the next team target will be.
- */
- switch (mission->Data.Quarry) {
- case QUARRY_ANYTHING:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_NORMAL));
- break;
- case QUARRY_BUILDINGS:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_BUILDINGS));
- break;
- case QUARRY_HARVESTERS:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_TIBERIUM));
- break;
- case QUARRY_INFANTRY:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_INFANTRY));
- break;
- case QUARRY_VEHICLES:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_VEHICLES));
- break;
- case QUARRY_FACTORIES:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_FACTORIES));
- break;
- case QUARRY_DEFENSE:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_BASE_DEFENSE));
- break;
- case QUARRY_THREAT:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_NORMAL));
- break;
- case QUARRY_POWER:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_POWER));
- break;
- case QUARRY_FAKES:
- Assign_Mission_Target(candidate->Greatest_Threat(THREAT_FAKES));
- break;
- default:
- break;
- }
- if (!Target_Legal(MissionTarget)) IsNextMission = true;
- }
- Coordinate_Attack();
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Spy -- Perform the team spy mission. *
- * *
- * This will give the team a spy mission to the location specified. It is presumed that *
- * the location of the team mission actually resides under the building to be spied. If *
- * no building exists at the location, then the spy operation is presumed to be a mere *
- * move operation. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next team logic operation should occur. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Spy(void)
- {
- if (Is_Target_Cell(MissionTarget))
- {
- CELL cell = ::As_Cell(MissionTarget);
- CellClass * cellptr = &Map[cell];
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- ObjectClass * bldg = cellptr->Cell_Building();
- #else
- ObjectClass * bldg = cellptr->Cell_Object();
- #endif
- if (bldg != NULL)
- {
- Assign_Mission_Target(bldg->As_Target());
- Coordinate_Attack();
- }
- #ifdef FIXIT_CSII // checked - ajw 9/28/98
- else
- {
- FootClass *member = Member;
- if(member->What_Am_I() == RTTI_UNIT && *(UnitClass *)member == UNIT_CHRONOTANK)
- {
- bool finished = true;
- while (member)
- {
- if ( !((UnitClass *)member)->MoebiusCountDown) finished = false;
- member = member->Member;
- }
-
- if (!finished)
- {
- Coordinate_Attack();
- }
- else
- {
- Assign_Mission_Target(TARGET_NONE);
- IsNextMission = true;
- }
- }
- }
- #endif
- }
- else
- {
- if (!Target_Legal(MissionTarget))
- {
- Assign_Mission_Target(TARGET_NONE);
- IsNextMission = true;
- }
- else
- {
- Coordinate_Attack();
- }
- }
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Follow -- Perform the "follow friendlies" team command. *
- * *
- * This will cause the team members to search out and follow the nearest friendly object. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next team logic operation should be performed. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Follow(void)
- {
- Calc_Center(Zone, ClosestMember);
- Target = Zone;
- Coordinate_Move();
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Loop -- Causes the team mission processor to jump to new location. *
- * *
- * This is equivalent to a jump or goto command. It will alter the team command processing *
- * such that it will continue processing at the command number specified. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next team logic operation should be performed. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Loop(void)
- {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- CurrentMission = mission->Data.Value-1;
- IsNextMission = true;
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Invulnerable -- Makes the entire team invulnerable for a period of time *
- * *
- * This is a team mission that simulates the Iron Curtain device. It will make all team *
- * members invlunerable for a temporary period of time. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the time delay before the next team logic operation should occur. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Invulnerable(void)
- {
- FootClass * foot = Member;
- while (foot != NULL) {
- foot->IronCurtainCountDown = Rule.IronCurtainDuration * TICKS_PER_MINUTE;
- foot->Mark(MARK_CHANGE);
- foot = foot->Member;
- }
- IsNextMission = true;
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMission_Set_Global -- Performs a set global flag operation. *
- * *
- * This routine is used by the team to set a global variable but otherwise perform no *
- * visible effect on the team. By using this routine, sophisticated trigger dependencies *
- * can be implemented. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next team logic operation should occur. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/06/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Set_Global(void)
- {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- Scen.Set_Global_To(mission->Data.Value, true);
- IsNextMission = true;
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::TMision_Patrol -- Handles patrolling from one location to another. *
- * *
- * A patrolling team will move to the designated waypoint, but along the way it will *
- * periodically scan for nearby enemies. If an enemy is found, the patrol mission turns *
- * into an attack mission until the target is destroyed -- after which it resumes its *
- * patrol duties. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with the delay before the next call to this routine is needed. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/12/1996 JLB : Created. *
- *=============================================================================================*/
- int TeamClass::TMission_Patrol(void)
- {
- /*
- ** Reassign the movement destination if the target has been prematurely
- ** cleared (probably because the object has been destroyed).
- */
- if (!Target_Legal(Target)) {
- TeamMissionClass const * mission = &Class->MissionList[CurrentMission];
- if ((unsigned)mission->Data.Value < WAYPT_COUNT) {
- Assign_Mission_Target(::As_Target(Scen.Waypoint[mission->Data.Value]));
- }
- }
- /*
- ** Every so often, scan for a nearby enemy.
- */
- if (Frame % (Rule.PatrolTime * TICKS_PER_MINUTE) == 0) {
- FootClass * leader = Fetch_A_Leader();
- if (leader != NULL) {
- TARGET target = leader->Greatest_Threat(THREAT_NORMAL|THREAT_RANGE);
- if (Target_Legal(target)) {
- Assign_Mission_Target(target);
- } else {
- Assign_Mission_Target(TARGET_NONE);
- }
- }
- }
- /*
- ** If the mission target looks like it should be attacked, then do so, otherwise
- ** treat it as a movement destination.
- */
- if (Is_Target_Object(Target)) {
- Coordinate_Attack();
- } else {
- Coordinate_Move();
- }
- return(1);
- }
- int TeamClass::TMission_Deploy(void)
- {
- assert(IsActive);
- assert(Teams.ID(this) == ID);
- FootClass * unit = Member;
- bool finished = true;
- while (unit != NULL) {
- Coordinate_Conscript(unit);
- if (_Is_It_Playing(unit)) {
- if (unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_MCV) {
- if (unit->Mission != MISSION_UNLOAD) {
- unit->Assign_Destination(TARGET_NONE);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Mission(MISSION_UNLOAD);
- finished = false;
- }
- }
- if (unit->What_Am_I() == RTTI_UNIT && *(UnitClass *)unit == UNIT_MINELAYER && unit->Ammo != 0) {
- /*
- ** The check for a building is located here because the mine layer may have
- ** already unloaded the mine but is still in the process of retracting
- ** the mine layer. During this time, it should not be considered to have
- ** finished its unload mission.
- */
- if (!Map[unit->Center_Coord()].Cell_Building() && unit->Mission != MISSION_UNLOAD) {
- unit->Assign_Destination(TARGET_NONE);
- unit->Assign_Target(TARGET_NONE);
- unit->Assign_Mission(MISSION_UNLOAD);
- finished = false;
- }
- }
- }
- unit = unit->Member;
- }
- if (finished) {
- IsNextMission = true;
- }
- return(1);
- }
- /***********************************************************************************************
- * TeamClass::Fetch_A_Leader -- Looks for a suitable leader member of the team. *
- * *
- * This will scan through the team members looking for one that is suitable as a leader *
- * type. A team can sometimes contain limboed or unarmed members. These members are not *
- * suitable for leadership roles. *
- * *
- * INPUT: none *
- * *
- * OUTPUT: Returns with a suitable leader type unit. *
- * *
- * WARNINGS: none *
- * *
- * HISTORY: *
- * 08/27/1996 JLB : Created. *
- *=============================================================================================*/
- FootClass * TeamClass::Fetch_A_Leader(void) const
- {
- FootClass * leader = Member;
- /*
- ** Scan through the team members trying to find one that is an active member and
- ** is equipped with a weapon.
- */
- while (leader != NULL) {
- if (_Is_It_Playing(leader) && leader->Is_Weapon_Equipped()) break;
- leader = leader->Member;
- }
- /*
- ** If no suitable leader was found, then just return with the first conveniently
- ** accessable team member. This presumes that some member is better than no member
- ** at all.
- */
- if (leader == NULL) {
- leader = Member;
- }
- return(leader);
- }
|