| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program 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.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- ////////////////////////////////////////////////////////////////////////////////
- // //
- // (c) 2001-2003 Electronic Arts Inc. //
- // //
- ////////////////////////////////////////////////////////////////////////////////
- // FILE: ActionManager.cpp ////////////////////////////////////////////////////////////////////////
- // Author: Colin Day
- // Desc: TheActionManager is a convenient place for us to wrap up all sorts of logical
- // queries about what objects can do in the world and to other objects. The purpose
- // of having a central place for this logic assists us in making these logical kind
- // of queries in the user interface and allows us to use the same code to validate
- // commands as they come in over the network interface in order to do the
- // real action.
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
- #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
- #include "Common/ActionManager.h"
- #include "Common/GlobalData.h"
- #include "Common/Player.h"
- #include "Common/PlayerList.h"
- #include "Common/SpecialPower.h"
- #include "Common/Team.h"
- #include "Common/ThingTemplate.h"
- #include "GameClient/Drawable.h"
- #include "GameClient/InGameUI.h"
- #include "GameLogic/Object.h"
- #include "GameLogic/PartitionManager.h"
- #include "GameLogic/Module/BodyModule.h"
- #include "GameLogic/Module/ContainModule.h"
- #include "GameLogic/Module/CollideModule.h"
- #include "GameLogic/Module/DozerAIUpdate.h"
- #include "GameLogic/Module/RailroadGuideAIUpdate.h"
- #include "GameLogic/Module/RailedTransportDockUpdate.h"
- #include "GameLogic/Module/SpawnBehavior.h"
- #include "GameLogic/Module/SupplyTruckAIUpdate.h"
- #include "GameLogic/Module/SupplyCenterDockUpdate.h"
- #include "GameLogic/Module/SupplyWarehouseDockUpdate.h"
- #include "GameLogic/Module/SpecialPowerModule.h"
- #include "GameLogic/Module/SpecialAbilityUpdate.h"
- #include "GameLogic/Weapon.h"
- #include "GameLogic/ExperienceTracker.h"//LORENZEN
- #ifdef _INTERNAL
- // for occasional debugging...
- //#pragma optimize("", off)
- //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
- #endif
- // GLOBAL /////////////////////////////////////////////////////////////////////////////////////////
- ActionManager *TheActionManager = NULL;
- // LOCAL //////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- static Bool appearsToContainFriendlies(const Object* obj, const Object* otherObject)
- {
- // check if the object is a container containing stealth units tricking
- // the player into thinking it isn't actually an enemy.
- const ContainModuleInterface *otherContain = otherObject->getContain();
- if( otherContain )
- {
- const Player *otherPlayer = otherContain->getApparentControllingPlayer(obj->getControllingPlayer());
- // if( otherPlayer && otherPlayer->getRelationship( obj->getTeam() ) != ENEMIES )
- // the above test is wrong; we want to know how WE consider THEM, not how THEY consider US
- if (otherPlayer && obj->getTeam()->getRelationship(otherPlayer->getDefaultTeam()) != ENEMIES)
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- static Bool isObjectShroudedForAction ( const Object *source, const Object *target, CommandSourceType commandSource )
- {
- /// @todo - reenable this when we can avoid breaking scripted actions.
- // In order to support ai and scripted actions in singler player, we have to disable this for now.
- // We can re-enable it when we can tell that this is a player generated action. jba.
- // return false;
- // GS Keeping this comment to show we now have commandSource, so everything should be fine again.
- // The target is only shrouded for action if...
-
- // the asking player is human
- // the asking impetus is not from a script
- // and the target object is Fogged or worse
- if( source && target && source->getControllingPlayer() )
- {
- if( source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN
- && commandSource != CMD_FROM_SCRIPT
- && target->getShroudedStatus( source->getControllingPlayer()->getPlayerIndex() ) >= OBJECTSHROUD_FOGGED
- )
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- ///////////////////////////////////////////////////////////////////////////////////////////////////
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ActionManager::ActionManager( void )
- {
- } // end ActionManager
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- ActionManager::~ActionManager( void )
- {
- } // end ~ActionManager
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canGetRepairedAt( const Object *obj, const Object *repairDest, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || repairDest == NULL )
- return FALSE;
- Relationship r = obj->getRelationship(repairDest);
- // only available by our allies
- if( r != ALLIES )
- return FALSE;
- // dead objects cannot be repaired
- if( obj->isEffectivelyDead() )
- return FALSE;
- // nothing can be done with things that are under construction
- if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE ||
- BitTest( repairDest->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- return FALSE;
- // Can't get repaired at something being sold
- if( repairDest->testStatus(OBJECT_STATUS_SOLD) )
- return FALSE;
-
- // only vehicles can go get repaired at something
- if( obj->isKindOf( KINDOF_VEHICLE ) == FALSE )
- return FALSE;
- // vehicles can only be repaired at something that is designated as a repair pad
- if (obj->isKindOf( KINDOF_AIRCRAFT ))
- {
- // aircraft require an airfield.
- if( !obj->isAboveTerrain() ||
- repairDest->isKindOf( KINDOF_AIRFIELD ) == FALSE )
- return FALSE;
- }
- else
- {
- if( repairDest->isKindOf( KINDOF_REPAIR_PAD ) == FALSE )
- return FALSE;
- }
- // if I am at full health, I can't get repair there
- BodyModuleInterface *body = obj->getBodyModule();
- if( body->getHealth() == body->getMaxHealth() )
- return FALSE;
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, repairDest, commandSource))
- return FALSE;
- // all is well, we can be repaired here
- return TRUE;
- } // end canGetRepairedAt
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- // note that "dest" is typically a building...
- Bool ActionManager::canTransferSuppliesAt( const Object *obj, const Object *transferDest )
- {
- // sanity
- if( obj == NULL || transferDest == NULL )
- return FALSE;
- if( transferDest->isEffectivelyDead() )
- {
- return FALSE;
- }
- // nothing can be done with things that are under construction
- if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE ||
- BitTest( transferDest->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- return FALSE;
- // Can't transfer at something being sold
- if( transferDest->testStatus(OBJECT_STATUS_SOLD) )
- return FALSE;
-
- // I must be something with a Supply Transfering AI interface
- const AIUpdateInterface *ai= obj->getAI();
- if( ai == NULL )
- return FALSE;
- const SupplyTruckAIInterface* supplyTruck = ai->getSupplyTruckAIInterface();
- if( supplyTruck == NULL )
- return FALSE;
- // If it is a warehouse, it must have boxes left and not be an enemy
- static const NameKeyType key_warehouseUpdate = NAMEKEY("SupplyWarehouseDockUpdate");
- SupplyWarehouseDockUpdate *warehouseModule = (SupplyWarehouseDockUpdate*)transferDest->findUpdateModule( key_warehouseUpdate );
- if( warehouseModule )
- if( warehouseModule->getBoxesStored() == 0 || transferDest->getRelationship( obj ) == ENEMIES )
- return FALSE;
- // if it is a supply center, I must have boxes, and must be controlled by the same player
- // (not merely an ally... otherwise you may find yourself funding your allies. ick.)
- static const NameKeyType key_centerUpdate = NAMEKEY("SupplyCenterDockUpdate");
- SupplyCenterDockUpdate *centerModule = (SupplyCenterDockUpdate*)transferDest->findUpdateModule( key_centerUpdate );
- if( centerModule )
- if( supplyTruck->getNumberBoxes() == 0 || transferDest->getControllingPlayer() != obj->getControllingPlayer() )
- return FALSE;
- // if he is not a warehouse or a center, then shut the hell up
- if( (warehouseModule == NULL) && (centerModule == NULL) )
- return FALSE;
- // We do not check ClearToApproach, as it is a temporary failure that is handled
- // in the state logic. This function is for Legality, not conditionals.
- // however, we DO check for the unit to be available (cf Chinook) (srj)
- if (!supplyTruck->isAvailableForSupplying())
- return FALSE;
- // if the target is in the shroud, we can't do anything
- // if (isObjectShroudedForAction(obj, transferDest))
- // return FALSE;
- //Commented out to show it is an intentional difference to most commands.
- // Fogged is okay for player, and anything is okay for AI.
- Player *objPlayer = obj->getControllingPlayer();
- if( objPlayer )
- {
- if( objPlayer->getPlayerType() == PLAYER_HUMAN &&
- transferDest->getShroudedStatus( objPlayer->getPlayerIndex() ) == OBJECTSHROUD_SHROUDED )
- {
- return FALSE;
- }
- }
- // all is well, we can transfer here
- return TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- /** Can object 'obj' dock with object 'dockDest' for any reason */
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDockAt( const Object *obj, const Object *dockDest, CommandSourceType commandSource )
- {
- // look for a dock interface
- DockUpdateInterface *di = NULL;
- for (BehaviorModule **u = dockDest->getBehaviorModules(); *u; ++u)
- {
- if ((di = (*u)->getDockUpdateInterface()) != NULL)
- break;
- }
- if( di == NULL )
- return FALSE; // no dock update interface, can't possibly dock
- /*
- // can't dock if the dock is closed
- if( di->isDockOpen() == FALSE )
- return FALSE;
- */
- // transferring supplies is a valid docking action
- if( canTransferSuppliesAt( obj, dockDest ) == TRUE )
- return TRUE;
- // units and infantry can dock with a railed transport
- static const NameKeyType key = NAMEKEY( "RailedTransportDockUpdate" );
- RailedTransportDockUpdate *fdu = (RailedTransportDockUpdate *)dockDest->findUpdateModule( key );
- if( fdu )
- {
- if( obj->isKindOf( KINDOF_VEHICLE ) || obj->isKindOf( KINDOF_INFANTRY ) )
- return TRUE;
- } // end if
- // cannot dock
- return FALSE;
- } // end canDockAt
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canGetHealedAt( const Object *obj, const Object *healDest, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || healDest == NULL )
- return FALSE;
- Relationship r = obj->getRelationship(healDest);
- // only available by our allies
- if( r != ALLIES )
- return FALSE;
- // dead objects cannot be healed
- if( healDest->isEffectivelyDead() )
- return FALSE;
- // nothing can be done with things that are under construction
- if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE ||
- BitTest( healDest->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- return FALSE;
- // Can't get healed at something being sold
- if( healDest->testStatus(OBJECT_STATUS_SOLD) )
- return FALSE;
-
- // only infantry can go get "healed" somewhere (vehicles get "repaired")
- if( obj->isKindOf( KINDOF_INFANTRY ) == FALSE )
- return FALSE;
- // infantry can only be healed at something that is designated as a heal pad
- if( healDest->isKindOf( KINDOF_HEAL_PAD ) == FALSE )
- return FALSE;
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, healDest, commandSource))
- return FALSE;
-
- BodyModuleInterface *body = obj->getBodyModule();
- if( body && body->getHealth() == body->getMaxHealth() )
- {
- //No point in healing if you have full health!
- return FALSE;
- }
- // all is well, we can be healed here
- return TRUE;
- } // end canGetHealedAt
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canRepairObject( const Object *obj, const Object *objectToRepair, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToRepair == NULL )
- return FALSE;
- Relationship r = obj->getRelationship(objectToRepair);
- // you can only repair allies, we ignore this restriction for bridges
- // srj sez: nope, allow neutral too, so civ bldgs can be repaired
- // GS repairing bridges cut 12/12/02 , so this check is just no to enemies
- if( r == ENEMIES )
- return FALSE;
- //
- // can't repair dead things ... the exception is bridges and bridge towers, which can
- // be destroyed and die, but can be repaired to bring the bring "back to life"
- //
- // GS and again, repairing bridges is cut, so this is just a dead check
- if( objectToRepair->isEffectivelyDead() )
- {
- return FALSE;
- }
- //GS So here's the ensuring that they can't be repaired
- if( objectToRepair->isKindOf(KINDOF_BRIDGE) || objectToRepair->isKindOf(KINDOF_BRIDGE_TOWER) )
- return FALSE;
- // nothing can be done with things that are under construction
- if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE ||
- BitTest( objectToRepair->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- return FALSE;
- // we cannot manually repair things that are regeneration holes
- if( objectToRepair->isKindOf( KINDOF_REBUILD_HOLE ) == TRUE )
- return FALSE;
- // only Dozers can go repair things
- if( obj->isKindOf( KINDOF_DOZER ) == FALSE )
- return FALSE;
- // dozers can only repair buildings
- if( objectToRepair->isKindOf( KINDOF_STRUCTURE ) == FALSE )
- return FALSE;
- // get the body module from the object to repair
- BodyModuleInterface *body = objectToRepair->getBodyModule();
- // buildings that are at full health cannot be repaired
- if( body->getHealth() == body->getMaxHealth() )
- return FALSE;
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToRepair, commandSource))
- return FALSE;
- if( obj->getContainedBy() )
- {
- // We can't heal things while in a transport (especially our own transport, you cheater)
- return FALSE;
- }
- return TRUE;
- } // end canRepair
- // ------------------------------------------------------------------------------------------------
- /** Can 'obj' resume the construction of 'objectBeingConstructed' */
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canResumeConstructionOf( const Object *obj,
- const Object *objectBeingConstructed,
- CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectBeingConstructed == NULL )
- return FALSE;
- // only dozers or workers can resume construction of things
- if( obj->isKindOf( KINDOF_DOZER ) == FALSE )
- return FALSE;
- Relationship r = obj->getRelationship(objectBeingConstructed);
- // only available to our allies
- if( r != ALLIES )
- return FALSE;
- // if the objectBeingConstructed is not actually under construction we can't resume that!
- if( BitTest( objectBeingConstructed->getStatusBits(),
- OBJECT_STATUS_UNDER_CONSTRUCTION ) == FALSE )
- return FALSE;
- // dead things can do nothing
- if( obj->isEffectivelyDead() )
- {
- return FALSE;
- }
- //
- // if the object being constructed is actively being built by another dozer we cannot
- // add more effectiveness to the construction so we'll say no (this might change for workers
- // in the future)
- //
- Object *builder = TheGameLogic->findObjectByID( objectBeingConstructed->getBuilderID() );
- if( builder )
- {
- AIUpdateInterface *ai = builder->getAI();
- DEBUG_ASSERTCRASH( ai, ("Builder object does not have an AI interface!\n") );
- if( ai )
- {
- DozerAIInterface *dozerAI = ai->getDozerAIInterface();
- DEBUG_ASSERTCRASH( dozerAI, ("Builder object doest not have a DozerAI interface!\n") );
- if( dozerAI )
- {
- if( dozerAI->getCurrentTask() == DOZER_TASK_BUILD &&
- dozerAI->getTaskTarget( DOZER_TASK_BUILD ) == objectBeingConstructed->getID() )
- return FALSE;
- } // end if
- } // en dif
- } //end if
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectBeingConstructed, commandSource))
- return FALSE;
- //
- // all is well, the objectBeingConstructeds' builder object has gone away or is no longer
- // building the object anymore
- //
- return TRUE;
- } // end canResumeConstructionOf
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canEnterObject( const Object *obj, const Object *objectToEnter, CommandSourceType commandSource, CanEnterType mode )
- {
- // sanity
- if( obj == NULL || objectToEnter == NULL )
- return FALSE;
-
- if( obj == objectToEnter )
- {
- //You can't contain yourself (crash fix for pow truck reselection)
- return FALSE;
- }
- // can't enter dead things
- if( objectToEnter->isEffectivelyDead() )
- return FALSE;
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToEnter, commandSource))
- return FALSE;
- // nothing can be done with things that are under construction
- if( BitTest( obj->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE ||
- BitTest( objectToEnter->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- {
- return FALSE;
- }
-
- // Can't enter something being sold
- if( objectToEnter->testStatus(OBJECT_STATUS_SOLD) )
- return FALSE;
- if ( obj->isKindOf( KINDOF_IGNORED_IN_GUI ) //As in, Angry Mob Members, Cargo Planes
- || obj->isKindOf( KINDOF_MOB_NEXUS )
- || objectToEnter->isKindOf( KINDOF_IGNORED_IN_GUI ) ) // As in Cargo Planes
- {
-
- return FALSE;
- }
- if( obj->isKindOf( KINDOF_STRUCTURE ) || obj->isKindOf( KINDOF_IMMOBILE ) )
- {
- //Structures or immobiles can't garrison
- return FALSE;
- }
- // Special case for unmanned vehicles. Any infantry unit can take over any unmanned vehicle!
- if( obj->isKindOf( KINDOF_INFANTRY ) && objectToEnter->isDisabledByType( DISABLED_UNMANNED ) )
- {
- return TRUE;
- }
- // Special case for aircraft.
- if( obj->isKindOf( KINDOF_AIRCRAFT ) && objectToEnter->isKindOf( KINDOF_AIRFIELD ) )
- {
- if (!obj->isAboveTerrain())
- return FALSE;
-
- if( obj->getControllingPlayer() == objectToEnter->getControllingPlayer() )
- {
- //Kris -- added code to prevent aircraft from landing in any airstrips other than their own!
- /// @todo srj -- this is horrible, but expedient.
- for (BehaviorModule** i = objectToEnter->getBehaviorModules(); *i; ++i)
- {
- ParkingPlaceBehaviorInterface* pp = (*i)->getParkingPlaceBehaviorInterface();
- if (pp == NULL)
- continue;
- if (pp->hasReservedSpace(obj->getID()))
- return TRUE;
-
- if (pp->shouldReserveDoorWhenQueued(obj->getTemplate()) && pp->hasAvailableSpaceFor(obj->getTemplate()))
- return TRUE;
- }
- }
- return FALSE;
- }
- // first, see if we'd like to collide with 'other'
- for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
- {
- CollideModuleInterface* collide = (*m)->getCollide();
- if (!collide)
- continue;
- if( collide->wouldLikeToCollideWith( objectToEnter ) )
- {
- //I thought this was a little confusing that it would return TRUE here before
- //getting to any of the other checks. The key is that it usually doesn't return
- //TRUE because most things aren't trying to collide with objects. This is different
- //for terrorist converting carbombs, and pilots entering vehicles. In these cases,
- //the vehicles don't have transport capacities, therefore returning true here
- //foregoes that checking later on.
- return TRUE;
- }
- }
-
- #ifdef ALLOW_SURRENDER
- if( objectToEnter->isKindOf( KINDOF_PRISON ) )
- {
- //We can't manually enter a prison!
- return FALSE;
- }
- #endif
- #ifdef ALLOW_SURRENDER
- if( objectToEnter->isKindOf( KINDOF_POW_TRUCK ) )
- {
- //We can't manually enter POWTruck, either!
- return FALSE;
- }
- #endif
- // make sure our objectToEnter has a contain module.
- ContainModuleInterface *contain = objectToEnter->getContain();
- if( !contain )
- {
- return FALSE;
- }
- if( contain->isHealContain() )
- {
- BodyModuleInterface *body = obj->getBodyModule();
- if( body->getHealth() == body->getMaxHealth() )
- {
- //This container is only used for the purposes of healing and we cannot
- //enter it with full health. This is not a normal container.
- return FALSE;
- }
- }
- if (mode == COMBATDROP_INTO)
- {
- // we don't care about valid container-ness, but we DO care about faction structures...
- // we aren't allowed to combat drop into them
- if (objectToEnter->isFactionStructure())
- return FALSE;
- }
- else
- {
- Bool checkCapacity = (mode == CHECK_CAPACITY);
- Int containCount = contain->getContainCount();
- Int stealthContainCount = contain->getStealthUnitsContained();
- Int nonStealthContainCount = containCount - stealthContainCount;
- // not ours... must do special checks.
- if (objectToEnter->getControllingPlayer() != obj->getControllingPlayer())
- {
- // not empty... can't do it.
- if (nonStealthContainCount > 0)
- return FALSE;
- // faction structure... can't do it.
- if (objectToEnter->isFactionStructure())
- return FALSE;
-
- // it's stealth-garrisoned... ignore check-cap and fall thru to
- // normal isValid test.
- if (stealthContainCount > 0 && nonStealthContainCount == 0)
- checkCapacity = FALSE;
- }
- // if our transport slot count is zero, we can't be transported. so punt.
- /// @todo srj -- seems like we should check always (not just for checkCap), but scared to change now -- check later
- if( checkCapacity && obj->getTransportSlotCount() == 0 )
- {
- return FALSE;
- }
- // finally: make sure that objectToEnter is a valid container for obj
- if( contain->isValidContainerFor( obj, checkCapacity ) == FALSE )
- {
- return FALSE;
- }
- }
- return TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- CanAttackResult ActionManager::getCanAttackObject( const Object *obj, const Object *objectToAttack, CommandSourceType commandSource, AbleToAttackType attackType )
- {
- // sanity
- if( !obj || !objectToAttack || obj->isEffectivelyDead() || objectToAttack->isEffectivelyDead() || objectToAttack == obj )
- {
- return ATTACKRESULT_NOT_POSSIBLE;
- }
- if( !obj->isAbleToAttack() )
- {
- return ATTACKRESULT_NOT_POSSIBLE;
- }
- //has any weapons that are capable of inflicting damage. Special damage types are rejected
- //such as hack weapons... others can be added.
- CanAttackResult result = obj->getAbleToAttackSpecificObject( attackType, objectToAttack, commandSource );
- if( result != ATTACKRESULT_NOT_POSSIBLE )
- {
- if( result == ATTACKRESULT_INVALID_SHOT && obj->isKindOf( KINDOF_DOZER ) )
- {
- //For the case of dozers, we don't ever want to see an attack cursor
- //unless it's valid on a mine.
- const Weapon *weapon = obj->getCurrentWeapon();
- if( weapon && weapon->getDamageType() == DAMAGE_DISARM )
- {
- return ATTACKRESULT_NOT_POSSIBLE;
- }
- }
- return result;
- }
- //Special case code for stinger sites: Stinger sites have no weapons, instead -- their spawns are the weapons, in this case the
- //stinger soldiers.
- if( obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) )
- {
- //Look at the spawn behavior and evaluate them!
- SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface();
- if( spawnInterface )
- {
- //We found the spawn interface, now get the closest slave to the target.
- Object *slave = spawnInterface->getClosestSlave( objectToAttack->getPosition() );
-
- if( slave )
- {
- result = slave->getAbleToAttackSpecificObject( attackType, objectToAttack, commandSource );
- if( result != ATTACKRESULT_NOT_POSSIBLE )
- {
- return result;
- }
- }
- }
- }
- return ATTACKRESULT_NOT_POSSIBLE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canConvertObjectToCarBomb( const Object *obj, const Object *objectToConvert, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToConvert == NULL )
- {
- return FALSE;
- }
- if( objectToConvert->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToConvert, commandSource))
- return FALSE;
- // first, see if we'd like to collide with 'other'
- for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
- {
- CollideModuleInterface* collide = (*m)->getCollide();
- if (!collide)
- continue;
- if( collide->wouldLikeToCollideWith( objectToConvert ) && collide->isCarBombCrateCollide() )
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canHijackVehicle( const Object *obj, const Object *objectToHijack, CommandSourceType commandSource ) //LORENZEN
- {
- int foo = 10;
- ++foo;
- // sanity
- if( obj == NULL || objectToHijack == NULL )
- {
- return FALSE;
- }
- //Make sure it's alive.
- if( objectToHijack->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToHijack, commandSource))
- {
- return FALSE;
- }
- Relationship r = obj->getRelationship(objectToHijack);
- //Only hijack enemy objects
- if( r != ENEMIES )
- {
- return FALSE;
- }
- //Make sure target is a vehicle.
- if( ! objectToHijack->isKindOf( KINDOF_VEHICLE ) )
- {
- return FALSE;
- }
- //Silly hijacker, you can't hijack that plane from the ground!
- //if( objectToHijack->isAirborneTarget() )
- //{
- // return FALSE;
- //}
-
- //Kris -- Hijackers can no longer hijack any aircraft.
- if( objectToHijack->isKindOf( KINDOF_AIRCRAFT ) )
- {
- return FALSE;
- }
- // Dustin asked for this to be removed, 12/13... ML
- //Elite and heroic units are immune to this kind of attack
- // VeterancyLevel veterancyLevel = objectToHijack->getVeterancyLevel();
- // if( veterancyLevel >= LEVEL_ELITE )
- // {
- // return FALSE;
- // }
- // last, see if we'd like to collide with 'objectToHijack'
- for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
- {
- CollideModuleInterface* collide = (*m)->getCollide();
- if (!collide)
- continue;
- if( collide->wouldLikeToCollideWith( objectToHijack ) && collide->isHijackedVehicleCrateCollide() )
- {
- return TRUE;
- }
- }
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canMakeObjectDefector( const Object *obj, const Object *objectToMakeDefector, CommandSourceType commandSource ) //LORENZEN
- {
- // sanity
- if( obj == NULL || objectToMakeDefector == NULL )
- {
- return FALSE;
- }
- Relationship r = obj->getRelationship(objectToMakeDefector);
- //Only make defectors of enemy objects
- if( r != ENEMIES )
- {
- return FALSE;
- }
- //Make sure it's alive.
- if( objectToMakeDefector->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToMakeDefector, commandSource))
- {
- return FALSE;
- }
- return TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canCaptureBuilding( const Object *obj, const Object *objectToCapture, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToCapture == NULL )
- return FALSE;
- //Make sure our object has the capability of performing this special ability.
- Bool isOwnerBlackLotus = obj->hasSpecialPower( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
- if( !obj->hasSpecialPower( SPECIAL_INFANTRY_CAPTURE_BUILDING ) && !isOwnerBlackLotus)
- {
- return false;
- }
- if( objectToCapture->isKindOf( KINDOF_IMMUNE_TO_CAPTURE ) )
- {
- return false;
- }
- // This is the althernate way to one-at-a-time BlackLotus' specials; we'll keep it commented her until Dustin decides, or until 12/10/02
- // if ( isOwnerBlackLotus )
- // {
- // SpecialPowerModuleInterface *disableSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
- // if ( disableSPI && disableSPI->isBusy() )
- // return FALSE;
- // SpecialPowerModuleInterface *cashSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
- // if ( cashSPI && cashSPI->isBusy() )
- // return FALSE;
- // }
- SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_INFANTRY_CAPTURE_BUILDING );
- if (!spInterface)
- spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
- if (!spInterface)
- return false;
- if( spInterface->getPercentReady() < 1.0f )
- {
- // Special not ready or non-existent.
- return false;
- }
- // can't capture dead things.
- if (objectToCapture->isEffectivelyDead())
- {
- return FALSE;
- }
- // Make sure we are targeting a building!
- if( !objectToCapture->isKindOf( KINDOF_STRUCTURE ) )
- {
- return FALSE;
- }
- // can't capture things that are under construction, or sold.
- if (objectToCapture->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION) ||
- objectToCapture->testStatus(OBJECT_STATUS_SOLD))
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToCapture, commandSource))
- return FALSE;
- Relationship r = obj->getRelationship(objectToCapture);
- // ensure that it's capturable, and not allied
- // exception: we can always capture enemy bldgs, regardless of kindof
- if (!(r == ENEMIES || (objectToCapture->isKindOf(KINDOF_CAPTURABLE) && r != ALLIES)))
- return false;
- //If the enemy unit is stealthed and not detected, then we can't capture it!
- UnsignedInt status = objectToCapture->getStatusBits();
- if ((status & OBJECT_STATUS_STEALTHED) && !(status & OBJECT_STATUS_DETECTED))
- {
- return FALSE;
- }
- // if it's garrisoned already, we cannot capture it.
- // (unless it's just stealth-garrisoned.)
- ContainModuleInterface *contain = objectToCapture->getContain();
- if (contain != NULL && contain->isGarrisonable())
- {
- Int containCount = contain->getContainCount();
- Int stealthContainCount = contain->getStealthUnitsContained();
- Int nonStealthContainCount = containCount - stealthContainCount;
- if (nonStealthContainCount > 0)
- return FALSE;
- }
- // Also check if the object is a container containing stealth units, tricking
- // the player into thinking it isn't actually an enemy.
- if (appearsToContainFriendlies(obj, objectToCapture))
- return FALSE;
- return TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDisableVehicleViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource, Bool checkSourceRequirements)
- {
- // sanity
- if( obj == NULL || objectToHack == NULL )
- return FALSE;
- if (checkSourceRequirements)
- {
- //Make sure our object has the capability of performing this special ability.
- if( !obj->hasSpecialPower( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK ) )
- {
- return false;
- }
- }
- // This is the althernate way to one-at-a-time BlackLotus' specials; we'll keep it commented her until Dustin decides, or until 12/10/02
- // SpecialPowerModuleInterface *captureSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
- // if ( captureSPI && captureSPI->isBusy() )
- // return FALSE;
- // SpecialPowerModuleInterface *cashSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
- // if ( cashSPI && cashSPI->isBusy() )
- // return FALSE;
-
- SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
- if (checkSourceRequirements)
- {
- if( !spInterface || spInterface->getPercentReady() < 1.0f )
- {
- //Special not ready or non-existent.
- return FALSE;
- }
- }
- if( objectToHack->isEffectivelyDead() )
- {
- return FALSE;
- }
- if( objectToHack->isKindOf( KINDOF_AIRCRAFT ) || objectToHack->isAirborneTarget() )
- {
- return false;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToHack, commandSource))
- return FALSE;
- Relationship r = obj->getRelationship(objectToHack);
- // Make sure object is an enemy
- if( r == ENEMIES )
- {
- //Make sure we are targeting a building!
- if( !objectToHack->isKindOf( KINDOF_VEHICLE ) )
- {
- return FALSE;
- }
- //If the enemy unit is stealthed and not detected, then we can't attack it!
- UnsignedInt status = objectToHack->getStatusBits();
- if( status & OBJECT_STATUS_STEALTHED && !(status & OBJECT_STATUS_DETECTED) )
- {
- return FALSE;
- }
- //Also check if the object is a container containing stealth units tricking
- //the player into thinking it isn't actually an enemy.
- if (appearsToContainFriendlies(obj, objectToHack))
- return FALSE;
- return TRUE;
- }
- return FALSE;
- }
- #ifdef ALLOW_SURRENDER
- // ------------------------------------------------------------------------------------------------
- /** Can 'obj' pick up the prisoner 'prisoner' */
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canPickUpPrisoner( const Object *obj, const Object *prisoner, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || prisoner == NULL )
- return FALSE;
- // only pow trucks can pick up anything
- if( obj->isKindOf( KINDOF_POW_TRUCK ) == FALSE )
- return FALSE;
- // only infantry can be picked up
- if( prisoner->isKindOf( KINDOF_INFANTRY ) == FALSE )
- return FALSE;
- // prisoner cannot be contained inside anything
- if( prisoner->getContainedBy() )
- return FALSE;
- // prisoner must be in a surrendered state
- const AIUpdateInterface *ai = prisoner->getAI();
- if( ai == NULL || ai->isSurrendered() == FALSE )
- return FALSE;
- // prisoner must have been put in a surrendered state by our own player
- // (or be surrendered to "everyone")
- Int idx = ai->getSurrenderedPlayerIndex();
- Player* surrenderedToPlayer = (idx >= 0) ? ThePlayerList->getNthPlayer(idx) : NULL;
- if (surrenderedToPlayer != NULL && surrenderedToPlayer != obj->getControllingPlayer())
- return FALSE;
- // we must be enemies
- if( obj->getRelationship( prisoner ) != ENEMIES )
- return FALSE;
- return TRUE;
- } // end canPickUpPrisoner
- #endif
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canStealCashViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToHack == NULL )
- return FALSE;
- //Make sure our object has the capability of performing this special ability.
- if( !obj->hasSpecialPower( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK ) )
- {
- return false;
- }
- // This is the althernate way to one-at-a-time BlackLotus' specials; we'll keep it commented her until Dustin decides, or until 12/10/02
- // SpecialPowerModuleInterface *captureSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
- // if ( captureSPI && captureSPI->isBusy() )
- // return FALSE;
- // SpecialPowerModuleInterface *disableSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
- // if ( disableSPI && disableSPI->isBusy() )
- // return FALSE;
- SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
- if( !spInterface || spInterface->getPercentReady() < 1.0f )
- {
- //Special not ready or non-existent.
- return false;
- }
- if( objectToHack->isEffectivelyDead() )
- {
- return FALSE;
- }
- if( BitTest( objectToHack->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) == TRUE )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToHack, commandSource))
- return FALSE;
- Relationship r = obj->getRelationship(objectToHack);
- // Make sure object is an enemy
- if( r == ENEMIES )
- {
- //Make sure we are targeting something that contains cash!
- if( !objectToHack->isKindOf( KINDOF_CASH_GENERATOR ) )
- {
- return FALSE;
- }
-
- //Make sure object isn't under construction!
- UnsignedInt status = objectToHack->getStatusBits();
- if( status & OBJECT_STATUS_UNDER_CONSTRUCTION )
- {
- return FALSE;
- }
-
- //Make sure the building is considered hackable (temp: using capturable)
- if( !objectToHack->isKindOf( KINDOF_CAPTURABLE ) || objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) )
- {
- return FALSE;
- }
- //If the enemy unit is stealthed and not detected, then we can't attack it!
- if( status & OBJECT_STATUS_STEALTHED && !(status & OBJECT_STATUS_DETECTED) )
- {
- return FALSE;
- }
- //Also check if the object is a container containing stealth units tricking
- //the player into thinking it isn't actually an enemy.
- if (appearsToContainFriendlies(obj, objectToHack))
- return FALSE;
- return TRUE;
- }
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDisableBuildingViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToHack == NULL )
- return FALSE;
- //Make sure our object has the capability of performing this special ability.
- if( !obj->hasSpecialPower( SPECIAL_HACKER_DISABLE_BUILDING ) )
- {
- return FALSE;
- }
-
- SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_HACKER_DISABLE_BUILDING );
- if( !spInterface || spInterface->getPercentReady() < 1.0f )
- {
- //Special not ready or non-existent.
- return FALSE;
- }
- if( objectToHack->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToHack, commandSource))
- return FALSE;
- Relationship r = obj->getRelationship(objectToHack);
- // Make sure object is an enemy
- if( r != ENEMIES )
- return FALSE;
- //Make sure we are targeting a building!
- if( !objectToHack->isKindOf( KINDOF_STRUCTURE ) )
- {
- return FALSE;
- }
- //Make sure the building is considered hackable (temp: using capturable)
- // An exception is any TechFactionBuilding that is not explicitly immune to capture
- if( ( !objectToHack->isKindOf( KINDOF_CAPTURABLE ) || objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) ) &&
- ! (objectToHack->isKindOf(KINDOF_FS_TECHNOLOGY) && ! objectToHack->isKindOf(KINDOF_IMMUNE_TO_CAPTURE)) )
- {
- return FALSE;
- }
-
- if ( objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) || objectToHack->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION ))
- return FALSE;
- //If the enemy unit is stealthed and not detected, then we can't attack it!
- UnsignedInt status = objectToHack->getStatusBits();
- if( (status & OBJECT_STATUS_STEALTHED) && !(status & OBJECT_STATUS_DETECTED) )
- {
- return FALSE;
- }
- //Also check if the object is a container containing stealth units tricking
- //the player into thinking it isn't actually an enemy.
- if (appearsToContainFriendlies(obj, objectToHack))
- return FALSE;
- return TRUE;
- }
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canBribeUnit( const Object *obj, const Object *objectToBribe, CommandSourceType commandSource )
- {
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canCutBuildingPower( const Object *obj, const Object *building, CommandSourceType commandSource )
- {
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canSnipeVehicle( const Object *obj, const Object *objectToSnipe, CommandSourceType commandSource )
- {
- //Sanity check
- if( obj == NULL || objectToSnipe == NULL )
- {
- return FALSE;
- }
- //Make sure it's alive.
- if( objectToSnipe->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToSnipe, commandSource))
- return FALSE;
- Relationship r = obj->getRelationship(objectToSnipe);
- if( r == ENEMIES )
- {
- //Make sure target is a vehicle.
- if( !objectToSnipe->isKindOf( KINDOF_VEHICLE ) )
- {
- return FALSE;
- }
- //Make sure object is not flying
- if( objectToSnipe->isAirborneTarget() )
- {
- return false;
- }
- //Make sure the vehicle is manned!
- if( objectToSnipe->isDisabledByType( DISABLED_UNMANNED ) )
- {
- return FALSE;
- }
- return TRUE;
- }
-
- return FALSE;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3D *loc, CommandSourceType commandSource, const SpecialPowerTemplate *spTemplate, const Object *objectInWay, UnsignedInt commandOptions, Bool checkSourceRequirements )
- {
- if (checkSourceRequirements)
- {
- //First check, if our object can do this special power.
- if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
- {
- return false;
- }
- }
- SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
- if( mod )
- {
- if (checkSourceRequirements)
- {
- if( mod->getPercentReady() < 1.0f )
- {
- //Not fully ready
- return false;
- }
- }
- // First check terrain type, if it is cared about. Don't return a true, since there are more checks.
- switch( spTemplate->getSpecialPowerType() )
- {
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CRATE_DROP:
- {
- if( TheTerrainLogic->isUnderwater( loc->x, loc->y ) )
- return FALSE;
- }
- }
- // Last check is shroudedness, if it is cared about
- switch( spTemplate->getSpecialPowerType() )
- {
- case SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CARPET_BOMB:
- case SPECIAL_CLUSTER_MINES:
- case SPECIAL_EMP_PULSE:
- case SPECIAL_CRATE_DROP:
- case SPECIAL_NAPALM_STRIKE:
- case SPECIAL_BLACK_MARKET_NUKE:
- case SPECIAL_ANTHRAX_BOMB:
- case SPECIAL_TERROR_CELL:
- case SPECIAL_AMBUSH:
- case SPECIAL_NEUTRON_MISSILE:
- case SPECIAL_SCUD_STORM:
- #ifdef ALLOW_DEMORALIZE
- case SPECIAL_DEMORALIZE:
- #endif
- case SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CLEANUP_AREA:
- //Don't allow "damaging" special powers in shrouded areas, but Fogged are okay.
- return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED;
- case SPECIAL_SPY_SATELLITE:
- case SPECIAL_RADAR_VAN_SCAN:
- case SPECIAL_SPY_DRONE:
- case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
- //These specials can be used anywhere!
- return true;
- //These special powers require object targets!
- case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
- case SPECIAL_HACKER_DISABLE_BUILDING:
- case SPECIAL_TANKHUNTER_TNT_ATTACK:
- case SPECIAL_CASH_HACK:
- case SPECIAL_DEFECTOR:
- case SPECIAL_BLACKLOTUS_CAPTURE_BUILDING:
- case SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK:
- case SPECIAL_BLACKLOTUS_STEAL_CASH_HACK:
- case SPECIAL_INFANTRY_CAPTURE_BUILDING:
- case SPECIAL_DETONATE_DIRTY_NUKE:
- case SPECIAL_DISGUISE_AS_VEHICLE:
- case SPECIAL_REMOTE_CHARGES:
- case SPECIAL_TIMED_CHARGES:
- case SPECIAL_CASH_BOUNTY:
- case SPECIAL_CHANGE_BATTLE_PLANS:
- return false;
- }
- }
- return false;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDoSpecialPowerAtObject( const Object *obj, const Object *target, CommandSourceType commandSource, const SpecialPowerTemplate *spTemplate, UnsignedInt commandOptions, Bool checkSourceRequirements )
- {
- if (checkSourceRequirements)
- {
- //First check, if our object can do this special power.
- if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
- {
- return false;
- }
- }
- if( target->isEffectivelyDead() )
- {
- return FALSE;
- }
- Relationship r = obj->getRelationship(target);
-
- SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
- if( mod )
- {
- if (checkSourceRequirements)
- {
- if( mod->getPercentReady() < 1.0f )
- {
- //Not fully ready
- return false;
- }
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, target, commandSource))
- return FALSE;
- switch( spTemplate->getSpecialPowerType() )
- {
- case SPECIAL_CASH_BOUNTY:
- return false;
- case SPECIAL_TANKHUNTER_TNT_ATTACK:
- if( target->isKindOf( KINDOF_STRUCTURE ) || (target->isKindOf( KINDOF_VEHICLE ) && !target->isKindOf(KINDOF_AIRCRAFT)) )
- {
- return true;
- }
- break;
- case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
- //Can only use laser guided missiles on vehicles!
- if( target->isKindOf( KINDOF_VEHICLE ) && r == ENEMIES )
- {
- return true;
- }
- break;
- case SPECIAL_HACKER_DISABLE_BUILDING:
- //Can only disable buildings...
- if( target->isKindOf( KINDOF_STRUCTURE ) && r == ENEMIES )
- {
- //Make sure the building is considered hackable (temp: using capturable)
- if( !target->isKindOf( KINDOF_CAPTURABLE ) || target->isKindOf( KINDOF_REBUILD_HOLE ) )
- {
- return FALSE;
- }
- return true;
- }
- break;
-
- case SPECIAL_INFANTRY_CAPTURE_BUILDING:
- case SPECIAL_BLACKLOTUS_CAPTURE_BUILDING:
- return canCaptureBuilding( obj, target, commandSource );
- case SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK:
- return canDisableVehicleViaHacking( obj, target, commandSource, false );
-
- case SPECIAL_BLACKLOTUS_STEAL_CASH_HACK:
- return canStealCashViaHacking( obj, target, commandSource );
- case SPECIAL_CASH_HACK:
- //Can only disable enemy supply centers.
- if( target->isKindOf( KINDOF_STRUCTURE ) && r == ENEMIES )
- {
- //Make sure the building is considered hackable (temp: using capturable)
- if( !target->isKindOf( KINDOF_CAPTURABLE ) || target->isKindOf( KINDOF_REBUILD_HOLE ) )
- {
- return FALSE;
- }
-
- //Can't cash hack a building that's under construction.
- if( BitTest( target->getStatusBits(), OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- {
- return FALSE;
- }
-
- if (target->isKindOf( KINDOF_CASH_GENERATOR ) )
- {
- return true;
- }
- }
- break;
- case SPECIAL_DISGUISE_AS_VEHICLE:
- if( target->isKindOf( KINDOF_VEHICLE ) && !target->isKindOf( KINDOF_AIRCRAFT ) && !target->isKindOf( KINDOF_BOAT ) )
- {
- //Don't allow it to disguise as another bomb truck -- that's just plain dumb.
- //if( target->getTemplate() != obj->getTemplate() )
- {
- //Don't allow it to disguise as a train -- they don't have KINDOF_TRAIN yet, but
- //if added, please change this code so it'll be faster!
- static const NameKeyType key = NAMEKEY( "RailroadBehavior" );
- RailroadBehavior *rBehavior = (RailroadBehavior*)target->findUpdateModule( key );
- if( !rBehavior )
- {
- return true;
- }
- }
- }
- break;
- case SPECIAL_DEFECTOR:
- //buildings do not defect
- if( ! target->isKindOf( KINDOF_STRUCTURE ) )
- {
- // only attacking type things will defect (no dozers, supply trucks, workers...)
- // srj sez: I don't know why this is commented out, but it should remain thus, because
- // it is not necessarily the case that dozers, workers, etc. cannot attack; they may
- // "attack" Mines to disarm them...
- // if ( target->isKindOf( KINDOF_CAN_ATTACK ) )
- {
- //neutral or same-team units are worthless defectors
- if( r == ENEMIES )
- {
- return canMakeObjectDefector( obj, target, commandSource );
- }
- }
- }
- break;
- //These special powers require locations, not objects!
- case SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CARPET_BOMB:
- case SPECIAL_CLUSTER_MINES:
- case SPECIAL_EMP_PULSE:
- case SPECIAL_CRATE_DROP:
- case SPECIAL_NAPALM_STRIKE:
- case SPECIAL_TERROR_CELL:
- case SPECIAL_AMBUSH:
- case SPECIAL_NEUTRON_MISSILE:
- case SPECIAL_DETONATE_DIRTY_NUKE:
- case SPECIAL_BLACK_MARKET_NUKE:
- case SPECIAL_ANTHRAX_BOMB:
- case SPECIAL_SPY_SATELLITE:
- case SPECIAL_SPY_DRONE:
- case SPECIAL_RADAR_VAN_SCAN:
- case SPECIAL_SCUD_STORM:
- case SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CHANGE_BATTLE_PLANS:
- case SPECIAL_CLEANUP_AREA:
- case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
- return false;
- case SPECIAL_REMOTE_CHARGES:
- case SPECIAL_TIMED_CHARGES:
- {
- if( target->isEffectivelyDead() ||
- target->isKindOf( KINDOF_BRIDGE ) ||
- target->isKindOf( KINDOF_BRIDGE_TOWER ) )
- return FALSE;
- if( target->isKindOf( KINDOF_STRUCTURE ) || target->isKindOf( KINDOF_VEHICLE ) )
- {
- SpecialAbilityUpdate *spUpdate = obj->findSpecialAbilityUpdate( spTemplate->getSpecialPowerType() );
- if( spUpdate )
- {
- //Make sure we have enough equipment to place an additional charge.
- if( spUpdate->getSpecialObjectCount() < spUpdate->getSpecialObjectMax() )
- {
- //Also restrict the unit from placing more than one charge on the same building.
- //We accomplish this by having the stickybomb update store the target as the producer ID.
- if( spUpdate->findSpecialObjectWithProducerID( target ) )
- {
- return false;
- }
- //HERE'S THE TOUGH CASE...
- //We also don't want to allow a unit that can place timed charges on a building to be able to place
- //remote charges (or vice-versa). So we're going to look for the other special ability update and
- //reject if the other one has it planted...
- if( spTemplate->getSpecialPowerType() == SPECIAL_REMOTE_CHARGES )
- {
- spUpdate = obj->findSpecialAbilityUpdate( SPECIAL_TIMED_CHARGES );
- }
- else if( spTemplate->getSpecialPowerType() == SPECIAL_TIMED_CHARGES )
- {
- spUpdate = obj->findSpecialAbilityUpdate( SPECIAL_REMOTE_CHARGES );
- }
- //If we have a valid pointer at this point, we found the other special. Make sure it
- //isn't planted on the same target.
- if( spUpdate && spUpdate->findSpecialObjectWithProducerID( target ) )
- {
- return false;
- }
-
- return true;
- }
- }
- }
- break;
- }
- }
- }
- return false;
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- Bool ActionManager::canDoSpecialPower( const Object *obj, const SpecialPowerTemplate *spTemplate, CommandSourceType commandSource, UnsignedInt commandOptions, Bool checkSourceRequirements )
- {
- if (checkSourceRequirements)
- {
- //First check, if our object can do this special power.
- if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
- {
- return false;
- }
- }
- SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
- if( mod )
- {
- if (checkSourceRequirements)
- {
- if( mod->getPercentReady() < 1.0f )
- {
- //Not fully ready
- return false;
- }
- }
- switch( spTemplate->getSpecialPowerType() )
- {
- case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
- case SPECIAL_TANKHUNTER_TNT_ATTACK:
- case SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_NAPALM_STRIKE:
- case SPECIAL_TERROR_CELL:
- case SPECIAL_NEUTRON_MISSILE:
- case SPECIAL_BLACK_MARKET_NUKE:
- case SPECIAL_ANTHRAX_BOMB:
- case SPECIAL_SPY_SATELLITE:
- case SPECIAL_SPY_DRONE:
- case SPECIAL_RADAR_VAN_SCAN:
- case SPECIAL_TIMED_CHARGES:
- case SPECIAL_SCUD_STORM:
- case SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_DISGUISE_AS_VEHICLE:
- case SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CASH_BOUNTY:
- case SPECIAL_CLEANUP_AREA:
- //These all require object or location targets.
- return false;
- case SPECIAL_REMOTE_CHARGES:
- case SPECIAL_CIA_INTELLIGENCE:
- case SPECIAL_DETONATE_DIRTY_NUKE:
- case SPECIAL_CHANGE_BATTLE_PLANS:
- case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
- //Detonate's any existing charges
- return true;
- }
- }
- return false;
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canFireWeaponAtLocation( const Object *obj, const Coord3D *loc, CommandSourceType commandSource, const WeaponSlotType slot, const Object *objectInWay )
- {
- //Sanity check
- if( obj == NULL || loc == NULL )
- {
- return false;
- }
- //Make sure we have the right weapon.
- Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
- if( !weapon )
- {
- return false;
- }
- return true;
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canFireWeaponAtObject( const Object *obj, const Object *target, CommandSourceType commandSource, const WeaponSlotType slot )
- {
- //Sanity check
- if( obj == NULL || target == NULL )
- {
- return false;
- }
- //Make sure we have the right weapon.
- Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
- if( !weapon )
- {
- return false;
- }
- //if( weapon->getDamageType() == DAMAGE_KILLPILOT )
- //{
- // return canSnipeVehicle( obj, target, commandSource );
- //}
- CanAttackResult result = obj->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET, target, commandSource );
-
- if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
- {
- return weapon->estimateWeaponDamage( obj, target ) != 0.0f;
- }
- return FALSE;
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canFireWeapon( const Object *obj, const WeaponSlotType slot, CommandSourceType commandSource )
- {
- //Sanity check
- if( obj == NULL )
- {
- return false;
- }
- //Make sure we have the right weapon.
- Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
- if( !weapon )
- {
- return false;
- }
- return true;
-
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canGarrison( const Object *obj, const Object *target, CommandSourceType commandSource )
- {
- if (!(obj && target))
- return false;
- // The object was not an infantry, or is disallowed from being allowed to garrison stuff.
- if (obj->isKindOf(KINDOF_INFANTRY) == false || obj->isKindOf(KINDOF_NO_GARRISON))
- return false;
- if (target->isKindOf(KINDOF_STRUCTURE) == false)
- return false;
- ContainModuleInterface *objCMI = obj->getContain();
- if (!objCMI)
- return false;
- ContainModuleInterface *cmi = target->getContain();
- if (cmi == NULL)
- return false;
- if (cmi->isGarrisonable() == false)
- return false;
- if (obj->getControllingPlayer() == target->getControllingPlayer())
- {
- return cmi->isValidContainerFor(obj, true);
- }
- if (obj->getControllingPlayer()->getRelationship(target->getTeam()) == NEUTRAL)
- {
- // needs to be empty if its not already ours.
- return (cmi->getContainCount() == 0 && cmi->isValidContainerFor(obj, true));
- }
- return false;
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canPlayerGarrison( const Player *player, const Object *target, CommandSourceType commandSource )
- {
- if (!(player && target))
- return false;
-
- if (target->isEffectivelyDead()) {
- return false;
- }
- if (target->isKindOf(KINDOF_STRUCTURE) == false)
- return false;
- ContainModuleInterface *cmi = target->getContain();
- if (cmi == NULL)
- return false;
- if (cmi->isGarrisonable() == false)
- return false;
- if (player == target->getControllingPlayer())
- {
- return true;
- }
- if (player->getRelationship(target->getTeam()) == NEUTRAL)
- {
- // needs to be empty if its not already ours.
- return cmi->getContainCount() == 0;
- }
- return false;
- }
- //------------------------------------------------------------------------------------------------
- Bool ActionManager::canOverrideSpecialPowerDestination( const Object *obj, const Coord3D *loc, SpecialPowerType spType, CommandSourceType commandSource )
- {
- SpecialPowerUpdateInterface* spuInterface = obj->findSpecialPowerWithOverridableDestinationActive( spType );
- if( spuInterface )
- {
- //But so long as it's not in the black areas of the map.
- return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED;
- }
- return false;
- }
|