| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093 |
- /*
- ** Command & Conquer Generals Zero Hour(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;
-
- // If I can't move, I can't get repaired
- if( !obj->isMobile() )
- return FALSE;
- // nothing can be done with things that are under construction
- if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
- repairDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- 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_FS_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( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
- transferDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- 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( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
- healDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- 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( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
- objectToRepair->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- 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( !objectBeingConstructed->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- 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( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
- objectToEnter->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- {
- 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 (objectToEnter->isDisabledByType( DISABLED_SUBDUED ))
- return FALSE; // a microwave tank has soldered the doors shut
- 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 ) )
- {
- if( !obj->isKindOf( KINDOF_REJECT_UNMANNED ) )
- {
- //But only if it's allowed to.
- return TRUE;
- }
- }
- // Special case for aircraft.
- if( obj->isKindOf( KINDOF_AIRCRAFT ) && objectToEnter->isKindOf( KINDOF_FS_AIRFIELD ) )
- {
- if( obj->getStatusBits().test( OBJECT_STATUS_DECK_HEIGHT_OFFSET ) && obj->getCarrierDeckHeight() >= obj->getPosition()->z )
- {
- return FALSE;
- }
- 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 )
- {
- //Kris: August 5, 2003
- //Fix a case where the Demo_GLAInfantryWorker is able to attack using his passive bomb upgrade. We don't
- //want him to allow a visible attack cursor for the player. This code never checked for AutoChoosesSources
- //logic, but now we will but only when the commandSource is FROM_PLAYER.
- if( commandSource == CMD_FROM_PLAYER )
- {
- //Check if it's got any weapons that can be used.
- Bool anyValidWeapon = FALSE;
- for( Int i = 0; i < WEAPONSLOT_COUNT; i++ )
- {
- UnsignedInt cmdSourceMask = obj->getWeaponInWeaponSlotCommandSourceMask( (WeaponSlotType)i );
- if( cmdSourceMask )
- {
- anyValidWeapon = TRUE;
- break;
- }
- }
- if( !anyValidWeapon )
- {
- return 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;
- }
- }
- }
- else if( result == ATTACKRESULT_NOT_POSSIBLE )// oh dear me. The wierd case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase
- {
- ContainModuleInterface *contain = obj->getContain();
- if ( contain )
- {
- Object *rider = contain->getClosestRider( objectToAttack->getPosition() );
- if ( rider )
- {
- result = rider->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
- {
- // 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;
- }
- //Kris -- Hijackers can no longer hijack any aircraft.
- if( objectToHijack->isKindOf( KINDOF_AIRCRAFT ) )
- {
- return FALSE;
- }
- //Can't hijack a drone type.
- if( objectToHijack->isKindOf( KINDOF_DRONE ) )
- {
- 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::canSabotageBuilding( const Object *obj, const Object *objectToSabotage, CommandSourceType commandSource )
- {
- // sanity
- if( obj == NULL || objectToSabotage == NULL )
- {
- return FALSE;
- }
- //Make sure it's alive.
- if( objectToSabotage->isEffectivelyDead() )
- {
- return FALSE;
- }
- // if the target is in the shroud, we can't do anything
- if (isObjectShroudedForAction(obj, objectToSabotage, commandSource))
- {
- return FALSE;
- }
- Relationship r = obj->getRelationship(objectToSabotage);
- //Only sabotage enemy objects
- if( r != ENEMIES )
- {
- return FALSE;
- }
- // last, see if we'd like to collide with 'objectToSabotage'
- for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
- {
- CollideModuleInterface* collide = (*m)->getCollide();
- if (!collide)
- continue;
- if( collide->wouldLikeToCollideWith( objectToSabotage ) && collide->isSabotageBuildingCrateCollide() )
- {
- 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!
- if( objectToCapture->testStatus( OBJECT_STATUS_STEALTHED ) &&
- !objectToCapture->testStatus( OBJECT_STATUS_DETECTED ) &&
- !objectToCapture->testStatus( OBJECT_STATUS_DISGUISED ) )
- {
- 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!
- if( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
- {
- 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( objectToHack->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
- {
- 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!
- if( objectToHack->getStatusBits().test( 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( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
- {
- 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!
- if( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
- !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
- {
- 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;
- }
-
- //Can't be a drone type.
- if( objectToSnipe->isKindOf( KINDOF_DRONE ) )
- {
- 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;
- }
- //-------------------------------------------------------------------------------------------------
- inline Bool isPointOnMap( const Coord3D *testPos )
- {
- Region3D mapRegion;
- TheTerrainLogic->getExtent( &mapRegion );
- return mapRegion.isInRegionNoZ( testPos );
- }
- // ------------------------------------------------------------------------------------------------
- // ------------------------------------------------------------------------------------------------
- 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 INFA_SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CRATE_DROP:
- case SPECIAL_TANK_PARADROP:
- {
- 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 AIRF_SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_TANK_PARADROP:
- case INFA_SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CARPET_BOMB:
- case SPECIAL_CHINA_CARPET_BOMB:
- case SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_CHINA_CARPET_BOMB:
- case AIRF_SPECIAL_CARPET_BOMB:
- case SUPR_SPECIAL_CRUISE_MISSILE:
- case SPECIAL_CLUSTER_MINES:
- case NUKE_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 NUKE_SPECIAL_NEUTRON_MISSILE:
- case SUPW_SPECIAL_NEUTRON_MISSILE:
- case SPECIAL_SCUD_STORM:
- #ifdef ALLOW_DEMORALIZE
- case SPECIAL_DEMORALIZE:
- #endif
- case SPECIAL_A10_THUNDERBOLT_STRIKE:
- case AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_SPECTRE_GUNSHIP:
- case AIRF_SPECIAL_SPECTRE_GUNSHIP:
- case SPECIAL_REPAIR_VEHICLES:
- case EARLY_SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_GPS_SCRAMBLER:
- case SLTH_SPECIAL_GPS_SCRAMBLER:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_FRENZY:
- case EARLY_SPECIAL_FRENZY:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SUPW_SPECIAL_PARTICLE_UPLINK_CANNON:
- case LAZR_SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CLEANUP_AREA:
- case SPECIAL_SNEAK_ATTACK:
- case SPECIAL_BATTLESHIP_BOMBARDMENT:
- //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_HELIX_NAPALM_BOMB:
- //These specials can be used anywhere!
- return isPointOnMap( loc );
- case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
- 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_BOOBY_TRAP:
- 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_BATTLESHIP_BOMBARDMENT:
- if( obj->getRelationship( target ) != ALLIES )
- {
- return TRUE;
- }
- 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_BOOBY_TRAP:
- {
- // We can booby trap any building that is allied or neutral
- if( target->isKindOf(KINDOF_STRUCTURE) && (r == NEUTRAL || r == ALLIES) )
- {
- return TRUE;
- }
- return FALSE;
- }
- 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( target->getStatusBits().test( 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 )
- && !target->isKindOf( KINDOF_CLIFF_JUMPER ) )
- {
- //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 AIRF_SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_TANK_PARADROP:
- case INFA_SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CARPET_BOMB:
- case SPECIAL_CHINA_CARPET_BOMB:
- case SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_CHINA_CARPET_BOMB:
- case AIRF_SPECIAL_CARPET_BOMB:
- case SUPR_SPECIAL_CRUISE_MISSILE:
- case SPECIAL_CLUSTER_MINES:
- case NUKE_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 NUKE_SPECIAL_NEUTRON_MISSILE:
- case SUPW_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 AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_SPECTRE_GUNSHIP:
- case AIRF_SPECIAL_SPECTRE_GUNSHIP:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_FRENZY:
- case EARLY_SPECIAL_FRENZY:
- case SPECIAL_REPAIR_VEHICLES:
- case EARLY_SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_GPS_SCRAMBLER:
- case SLTH_SPECIAL_GPS_SCRAMBLER:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CHANGE_BATTLE_PLANS:
- case SPECIAL_CLEANUP_AREA:
- case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
- case SPECIAL_SNEAK_ATTACK:
- return false;
- case SPECIAL_REMOTE_CHARGES:
- case SPECIAL_TIMED_CHARGES:
- case SPECIAL_HELIX_NAPALM_BOMB:
- {
- 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_BOOBY_TRAP:
- case SPECIAL_DAISY_CUTTER:
- case AIRF_SPECIAL_DAISY_CUTTER:
- case SPECIAL_PARADROP_AMERICA:
- case SPECIAL_TANK_PARADROP:
- case INFA_SPECIAL_PARADROP_AMERICA:
- case SPECIAL_CARPET_BOMB:
- case SPECIAL_CHINA_CARPET_BOMB:
- case SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_LEAFLET_DROP:
- case EARLY_SPECIAL_CHINA_CARPET_BOMB:
- case AIRF_SPECIAL_CARPET_BOMB:
- case SUPR_SPECIAL_CRUISE_MISSILE:
- case SPECIAL_CLUSTER_MINES:
- case NUKE_SPECIAL_CLUSTER_MINES:
- case SPECIAL_NAPALM_STRIKE:
- case SPECIAL_TERROR_CELL:
- case SPECIAL_NEUTRON_MISSILE:
- case NUKE_SPECIAL_NEUTRON_MISSILE:
- case SUPW_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 AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
- case SPECIAL_SPECTRE_GUNSHIP:
- case AIRF_SPECIAL_SPECTRE_GUNSHIP:
- case SPECIAL_ARTILLERY_BARRAGE:
- case SPECIAL_FRENZY:
- case EARLY_SPECIAL_FRENZY:
- case SPECIAL_DISGUISE_AS_VEHICLE:
- case SPECIAL_REPAIR_VEHICLES:
- case EARLY_SPECIAL_REPAIR_VEHICLES:
- case SPECIAL_GPS_SCRAMBLER:
- case SLTH_SPECIAL_GPS_SCRAMBLER:
- case SPECIAL_PARTICLE_UPLINK_CANNON:
- case SPECIAL_CASH_BOUNTY:
- case SPECIAL_CLEANUP_AREA:
- case SPECIAL_HELIX_NAPALM_BOMB:
- case SPECIAL_SNEAK_ATTACK:
- case SPECIAL_EMP_PULSE:
- case SPECIAL_CASH_HACK:
- //These all require object or location targets.
- return false;
- case SPECIAL_REMOTE_CHARGES:
- case SPECIAL_CIA_INTELLIGENCE:
- case SPECIAL_COMMUNICATIONS_DOWNLOAD:
- 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;
- }
- Bool sniper = FALSE;
- if( weapon->getDamageType() == DAMAGE_KILLPILOT )
- {
- if( !canSnipeVehicle( obj, target, commandSource ) )
- {
- return FALSE;
- }
- sniper = TRUE;
- }
- CanAttackResult result;
- if( sniper )
- result = obj->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET, target, commandSource, slot );
- else
- 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;
- }
|