ActionManager.cpp 65 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. ////////////////////////////////////////////////////////////////////////////////
  19. // //
  20. // (c) 2001-2003 Electronic Arts Inc. //
  21. // //
  22. ////////////////////////////////////////////////////////////////////////////////
  23. // FILE: ActionManager.cpp ////////////////////////////////////////////////////////////////////////
  24. // Author: Colin Day
  25. // Desc: TheActionManager is a convenient place for us to wrap up all sorts of logical
  26. // queries about what objects can do in the world and to other objects. The purpose
  27. // of having a central place for this logic assists us in making these logical kind
  28. // of queries in the user interface and allows us to use the same code to validate
  29. // commands as they come in over the network interface in order to do the
  30. // real action.
  31. ///////////////////////////////////////////////////////////////////////////////////////////////////
  32. // INCLUDES ///////////////////////////////////////////////////////////////////////////////////////
  33. #include "PreRTS.h" // This must go first in EVERY cpp file int the GameEngine
  34. #include "Common/ActionManager.h"
  35. #include "Common/GlobalData.h"
  36. #include "Common/Player.h"
  37. #include "Common/PlayerList.h"
  38. #include "Common/SpecialPower.h"
  39. #include "Common/Team.h"
  40. #include "Common/ThingTemplate.h"
  41. #include "GameClient/Drawable.h"
  42. #include "GameClient/InGameUI.h"
  43. #include "GameLogic/Object.h"
  44. #include "GameLogic/PartitionManager.h"
  45. #include "GameLogic/Module/BodyModule.h"
  46. #include "GameLogic/Module/ContainModule.h"
  47. #include "GameLogic/Module/CollideModule.h"
  48. #include "GameLogic/Module/DozerAIUpdate.h"
  49. #include "GameLogic/Module/RailroadGuideAIUpdate.h"
  50. #include "GameLogic/Module/RailedTransportDockUpdate.h"
  51. #include "GameLogic/Module/SpawnBehavior.h"
  52. #include "GameLogic/Module/SupplyTruckAIUpdate.h"
  53. #include "GameLogic/Module/SupplyCenterDockUpdate.h"
  54. #include "GameLogic/Module/SupplyWarehouseDockUpdate.h"
  55. #include "GameLogic/Module/SpecialPowerModule.h"
  56. #include "GameLogic/Module/SpecialAbilityUpdate.h"
  57. #include "GameLogic/Weapon.h"
  58. #include "GameLogic/ExperienceTracker.h"//LORENZEN
  59. #ifdef _INTERNAL
  60. // for occasional debugging...
  61. //#pragma optimize("", off)
  62. //#pragma MESSAGE("************************************** WARNING, optimization disabled for debugging purposes")
  63. #endif
  64. // GLOBAL /////////////////////////////////////////////////////////////////////////////////////////
  65. ActionManager *TheActionManager = NULL;
  66. // LOCAL //////////////////////////////////////////////////////////////////////////////////////////
  67. // ------------------------------------------------------------------------------------------------
  68. // ------------------------------------------------------------------------------------------------
  69. static Bool appearsToContainFriendlies(const Object* obj, const Object* otherObject)
  70. {
  71. // check if the object is a container containing stealth units tricking
  72. // the player into thinking it isn't actually an enemy.
  73. const ContainModuleInterface *otherContain = otherObject->getContain();
  74. if( otherContain )
  75. {
  76. const Player *otherPlayer = otherContain->getApparentControllingPlayer(obj->getControllingPlayer());
  77. // if( otherPlayer && otherPlayer->getRelationship( obj->getTeam() ) != ENEMIES )
  78. // the above test is wrong; we want to know how WE consider THEM, not how THEY consider US
  79. if (otherPlayer && obj->getTeam()->getRelationship(otherPlayer->getDefaultTeam()) != ENEMIES)
  80. {
  81. return TRUE;
  82. }
  83. }
  84. return FALSE;
  85. }
  86. // ------------------------------------------------------------------------------------------------
  87. // ------------------------------------------------------------------------------------------------
  88. static Bool isObjectShroudedForAction ( const Object *source, const Object *target, CommandSourceType commandSource )
  89. {
  90. /// @todo - reenable this when we can avoid breaking scripted actions.
  91. // In order to support ai and scripted actions in singler player, we have to disable this for now.
  92. // We can re-enable it when we can tell that this is a player generated action. jba.
  93. // return false;
  94. // GS Keeping this comment to show we now have commandSource, so everything should be fine again.
  95. // The target is only shrouded for action if...
  96. // the asking player is human
  97. // the asking impetus is not from a script
  98. // and the target object is Fogged or worse
  99. if( source && target && source->getControllingPlayer() )
  100. {
  101. if( source->getControllingPlayer()->getPlayerType() == PLAYER_HUMAN
  102. && commandSource != CMD_FROM_SCRIPT
  103. && target->getShroudedStatus( source->getControllingPlayer()->getPlayerIndex() ) >= OBJECTSHROUD_FOGGED
  104. )
  105. {
  106. return TRUE;
  107. }
  108. }
  109. return FALSE;
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////////////////////////
  112. // ------------------------------------------------------------------------------------------------
  113. // ------------------------------------------------------------------------------------------------
  114. ActionManager::ActionManager( void )
  115. {
  116. } // end ActionManager
  117. // ------------------------------------------------------------------------------------------------
  118. // ------------------------------------------------------------------------------------------------
  119. ActionManager::~ActionManager( void )
  120. {
  121. } // end ~ActionManager
  122. // ------------------------------------------------------------------------------------------------
  123. // ------------------------------------------------------------------------------------------------
  124. Bool ActionManager::canGetRepairedAt( const Object *obj, const Object *repairDest, CommandSourceType commandSource )
  125. {
  126. // sanity
  127. if( obj == NULL || repairDest == NULL )
  128. return FALSE;
  129. Relationship r = obj->getRelationship(repairDest);
  130. // only available by our allies
  131. if( r != ALLIES )
  132. return FALSE;
  133. // dead objects cannot be repaired
  134. if( obj->isEffectivelyDead() )
  135. return FALSE;
  136. // If I can't move, I can't get repaired
  137. if( !obj->isMobile() )
  138. return FALSE;
  139. // nothing can be done with things that are under construction
  140. if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
  141. repairDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  142. return FALSE;
  143. // Can't get repaired at something being sold
  144. if( repairDest->testStatus(OBJECT_STATUS_SOLD) )
  145. return FALSE;
  146. // only vehicles can go get repaired at something
  147. if( obj->isKindOf( KINDOF_VEHICLE ) == FALSE )
  148. return FALSE;
  149. // vehicles can only be repaired at something that is designated as a repair pad
  150. if (obj->isKindOf( KINDOF_AIRCRAFT ))
  151. {
  152. // aircraft require an airfield.
  153. if( !obj->isAboveTerrain() ||
  154. repairDest->isKindOf( KINDOF_FS_AIRFIELD ) == FALSE )
  155. return FALSE;
  156. }
  157. else
  158. {
  159. if( repairDest->isKindOf( KINDOF_REPAIR_PAD ) == FALSE )
  160. return FALSE;
  161. }
  162. // if I am at full health, I can't get repair there
  163. BodyModuleInterface *body = obj->getBodyModule();
  164. if( body->getHealth() == body->getMaxHealth() )
  165. return FALSE;
  166. // if the target is in the shroud, we can't do anything
  167. if (isObjectShroudedForAction(obj, repairDest, commandSource))
  168. return FALSE;
  169. // all is well, we can be repaired here
  170. return TRUE;
  171. } // end canGetRepairedAt
  172. // ------------------------------------------------------------------------------------------------
  173. // ------------------------------------------------------------------------------------------------
  174. // note that "dest" is typically a building...
  175. Bool ActionManager::canTransferSuppliesAt( const Object *obj, const Object *transferDest )
  176. {
  177. // sanity
  178. if( obj == NULL || transferDest == NULL )
  179. return FALSE;
  180. if( transferDest->isEffectivelyDead() )
  181. {
  182. return FALSE;
  183. }
  184. // nothing can be done with things that are under construction
  185. if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
  186. transferDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  187. return FALSE;
  188. // Can't transfer at something being sold
  189. if( transferDest->testStatus(OBJECT_STATUS_SOLD) )
  190. return FALSE;
  191. // I must be something with a Supply Transfering AI interface
  192. const AIUpdateInterface *ai= obj->getAI();
  193. if( ai == NULL )
  194. return FALSE;
  195. const SupplyTruckAIInterface* supplyTruck = ai->getSupplyTruckAIInterface();
  196. if( supplyTruck == NULL )
  197. return FALSE;
  198. // If it is a warehouse, it must have boxes left and not be an enemy
  199. static const NameKeyType key_warehouseUpdate = NAMEKEY("SupplyWarehouseDockUpdate");
  200. SupplyWarehouseDockUpdate *warehouseModule = (SupplyWarehouseDockUpdate*)transferDest->findUpdateModule( key_warehouseUpdate );
  201. if( warehouseModule )
  202. if( warehouseModule->getBoxesStored() == 0 || transferDest->getRelationship( obj ) == ENEMIES )
  203. return FALSE;
  204. // if it is a supply center, I must have boxes, and must be controlled by the same player
  205. // (not merely an ally... otherwise you may find yourself funding your allies. ick.)
  206. static const NameKeyType key_centerUpdate = NAMEKEY("SupplyCenterDockUpdate");
  207. SupplyCenterDockUpdate *centerModule = (SupplyCenterDockUpdate*)transferDest->findUpdateModule( key_centerUpdate );
  208. if( centerModule )
  209. if( supplyTruck->getNumberBoxes() == 0 || transferDest->getControllingPlayer() != obj->getControllingPlayer() )
  210. return FALSE;
  211. // if he is not a warehouse or a center, then shut the hell up
  212. if( (warehouseModule == NULL) && (centerModule == NULL) )
  213. return FALSE;
  214. // We do not check ClearToApproach, as it is a temporary failure that is handled
  215. // in the state logic. This function is for Legality, not conditionals.
  216. // however, we DO check for the unit to be available (cf Chinook) (srj)
  217. if (!supplyTruck->isAvailableForSupplying())
  218. return FALSE;
  219. // if the target is in the shroud, we can't do anything
  220. // if (isObjectShroudedForAction(obj, transferDest))
  221. // return FALSE;
  222. //Commented out to show it is an intentional difference to most commands.
  223. // Fogged is okay for player, and anything is okay for AI.
  224. Player *objPlayer = obj->getControllingPlayer();
  225. if( objPlayer )
  226. {
  227. if( objPlayer->getPlayerType() == PLAYER_HUMAN &&
  228. transferDest->getShroudedStatus( objPlayer->getPlayerIndex() ) == OBJECTSHROUD_SHROUDED )
  229. {
  230. return FALSE;
  231. }
  232. }
  233. // all is well, we can transfer here
  234. return TRUE;
  235. }
  236. // ------------------------------------------------------------------------------------------------
  237. /** Can object 'obj' dock with object 'dockDest' for any reason */
  238. // ------------------------------------------------------------------------------------------------
  239. Bool ActionManager::canDockAt( const Object *obj, const Object *dockDest, CommandSourceType commandSource )
  240. {
  241. // look for a dock interface
  242. DockUpdateInterface *di = NULL;
  243. for (BehaviorModule **u = dockDest->getBehaviorModules(); *u; ++u)
  244. {
  245. if ((di = (*u)->getDockUpdateInterface()) != NULL)
  246. break;
  247. }
  248. if( di == NULL )
  249. return FALSE; // no dock update interface, can't possibly dock
  250. /*
  251. // can't dock if the dock is closed
  252. if( di->isDockOpen() == FALSE )
  253. return FALSE;
  254. */
  255. // transferring supplies is a valid docking action
  256. if( canTransferSuppliesAt( obj, dockDest ) == TRUE )
  257. return TRUE;
  258. // units and infantry can dock with a railed transport
  259. static const NameKeyType key = NAMEKEY( "RailedTransportDockUpdate" );
  260. RailedTransportDockUpdate *fdu = (RailedTransportDockUpdate *)dockDest->findUpdateModule( key );
  261. if( fdu )
  262. {
  263. if( obj->isKindOf( KINDOF_VEHICLE ) || obj->isKindOf( KINDOF_INFANTRY ) )
  264. return TRUE;
  265. } // end if
  266. // cannot dock
  267. return FALSE;
  268. } // end canDockAt
  269. // ------------------------------------------------------------------------------------------------
  270. // ------------------------------------------------------------------------------------------------
  271. Bool ActionManager::canGetHealedAt( const Object *obj, const Object *healDest, CommandSourceType commandSource )
  272. {
  273. // sanity
  274. if( obj == NULL || healDest == NULL )
  275. return FALSE;
  276. Relationship r = obj->getRelationship(healDest);
  277. // only available by our allies
  278. if( r != ALLIES )
  279. return FALSE;
  280. // dead objects cannot be healed
  281. if( healDest->isEffectivelyDead() )
  282. return FALSE;
  283. // nothing can be done with things that are under construction
  284. if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
  285. healDest->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  286. return FALSE;
  287. // Can't get healed at something being sold
  288. if( healDest->testStatus(OBJECT_STATUS_SOLD) )
  289. return FALSE;
  290. // only infantry can go get "healed" somewhere (vehicles get "repaired")
  291. if( obj->isKindOf( KINDOF_INFANTRY ) == FALSE )
  292. return FALSE;
  293. // infantry can only be healed at something that is designated as a heal pad
  294. if( healDest->isKindOf( KINDOF_HEAL_PAD ) == FALSE )
  295. return FALSE;
  296. // if the target is in the shroud, we can't do anything
  297. if (isObjectShroudedForAction(obj, healDest, commandSource))
  298. return FALSE;
  299. BodyModuleInterface *body = obj->getBodyModule();
  300. if( body && body->getHealth() == body->getMaxHealth() )
  301. {
  302. //No point in healing if you have full health!
  303. return FALSE;
  304. }
  305. // all is well, we can be healed here
  306. return TRUE;
  307. } // end canGetHealedAt
  308. // ------------------------------------------------------------------------------------------------
  309. // ------------------------------------------------------------------------------------------------
  310. Bool ActionManager::canRepairObject( const Object *obj, const Object *objectToRepair, CommandSourceType commandSource )
  311. {
  312. // sanity
  313. if( obj == NULL || objectToRepair == NULL )
  314. return FALSE;
  315. Relationship r = obj->getRelationship(objectToRepair);
  316. // you can only repair allies, we ignore this restriction for bridges
  317. // srj sez: nope, allow neutral too, so civ bldgs can be repaired
  318. // GS repairing bridges cut 12/12/02 , so this check is just no to enemies
  319. if( r == ENEMIES )
  320. return FALSE;
  321. //
  322. // can't repair dead things ... the exception is bridges and bridge towers, which can
  323. // be destroyed and die, but can be repaired to bring the bring "back to life"
  324. //
  325. // GS and again, repairing bridges is cut, so this is just a dead check
  326. if( objectToRepair->isEffectivelyDead() )
  327. {
  328. return FALSE;
  329. }
  330. //GS So here's the ensuring that they can't be repaired
  331. if( objectToRepair->isKindOf(KINDOF_BRIDGE) || objectToRepair->isKindOf(KINDOF_BRIDGE_TOWER) )
  332. return FALSE;
  333. // nothing can be done with things that are under construction
  334. if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
  335. objectToRepair->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  336. return FALSE;
  337. // we cannot manually repair things that are regeneration holes
  338. if( objectToRepair->isKindOf( KINDOF_REBUILD_HOLE ) == TRUE )
  339. return FALSE;
  340. // only Dozers can go repair things
  341. if( obj->isKindOf( KINDOF_DOZER ) == FALSE )
  342. return FALSE;
  343. // dozers can only repair buildings
  344. if( objectToRepair->isKindOf( KINDOF_STRUCTURE ) == FALSE )
  345. return FALSE;
  346. // get the body module from the object to repair
  347. BodyModuleInterface *body = objectToRepair->getBodyModule();
  348. // buildings that are at full health cannot be repaired
  349. if( body->getHealth() == body->getMaxHealth() )
  350. return FALSE;
  351. // if the target is in the shroud, we can't do anything
  352. if (isObjectShroudedForAction(obj, objectToRepair, commandSource))
  353. return FALSE;
  354. if( obj->getContainedBy() )
  355. {
  356. // We can't heal things while in a transport (especially our own transport, you cheater)
  357. return FALSE;
  358. }
  359. return TRUE;
  360. } // end canRepair
  361. // ------------------------------------------------------------------------------------------------
  362. /** Can 'obj' resume the construction of 'objectBeingConstructed' */
  363. // ------------------------------------------------------------------------------------------------
  364. Bool ActionManager::canResumeConstructionOf( const Object *obj,
  365. const Object *objectBeingConstructed,
  366. CommandSourceType commandSource )
  367. {
  368. // sanity
  369. if( obj == NULL || objectBeingConstructed == NULL )
  370. return FALSE;
  371. // only dozers or workers can resume construction of things
  372. if( obj->isKindOf( KINDOF_DOZER ) == FALSE )
  373. return FALSE;
  374. Relationship r = obj->getRelationship(objectBeingConstructed);
  375. // only available to our allies
  376. if( r != ALLIES )
  377. return FALSE;
  378. // if the objectBeingConstructed is not actually under construction we can't resume that!
  379. if( !objectBeingConstructed->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  380. return FALSE;
  381. // dead things can do nothing
  382. if( obj->isEffectivelyDead() )
  383. {
  384. return FALSE;
  385. }
  386. //
  387. // if the object being constructed is actively being built by another dozer we cannot
  388. // add more effectiveness to the construction so we'll say no (this might change for workers
  389. // in the future)
  390. //
  391. Object *builder = TheGameLogic->findObjectByID( objectBeingConstructed->getBuilderID() );
  392. if( builder )
  393. {
  394. AIUpdateInterface *ai = builder->getAI();
  395. DEBUG_ASSERTCRASH( ai, ("Builder object does not have an AI interface!\n") );
  396. if( ai )
  397. {
  398. DozerAIInterface *dozerAI = ai->getDozerAIInterface();
  399. DEBUG_ASSERTCRASH( dozerAI, ("Builder object doest not have a DozerAI interface!\n") );
  400. if( dozerAI )
  401. {
  402. if( dozerAI->getCurrentTask() == DOZER_TASK_BUILD &&
  403. dozerAI->getTaskTarget( DOZER_TASK_BUILD ) == objectBeingConstructed->getID() )
  404. return FALSE;
  405. } // end if
  406. } // en dif
  407. } //end if
  408. // if the target is in the shroud, we can't do anything
  409. if (isObjectShroudedForAction(obj, objectBeingConstructed, commandSource))
  410. return FALSE;
  411. //
  412. // all is well, the objectBeingConstructeds' builder object has gone away or is no longer
  413. // building the object anymore
  414. //
  415. return TRUE;
  416. } // end canResumeConstructionOf
  417. // ------------------------------------------------------------------------------------------------
  418. // ------------------------------------------------------------------------------------------------
  419. Bool ActionManager::canEnterObject( const Object *obj, const Object *objectToEnter, CommandSourceType commandSource, CanEnterType mode )
  420. {
  421. // sanity
  422. if( obj == NULL || objectToEnter == NULL )
  423. return FALSE;
  424. if( obj == objectToEnter )
  425. {
  426. //You can't contain yourself (crash fix for pow truck reselection)
  427. return FALSE;
  428. }
  429. // can't enter dead things
  430. if( objectToEnter->isEffectivelyDead() )
  431. return FALSE;
  432. // if the target is in the shroud, we can't do anything
  433. if (isObjectShroudedForAction(obj, objectToEnter, commandSource))
  434. return FALSE;
  435. // nothing can be done with things that are under construction
  436. if( obj->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) ||
  437. objectToEnter->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  438. {
  439. return FALSE;
  440. }
  441. // Can't enter something being sold
  442. if( objectToEnter->testStatus(OBJECT_STATUS_SOLD) )
  443. return FALSE;
  444. if ( obj->isKindOf( KINDOF_IGNORED_IN_GUI ) //As in, Angry Mob Members, Cargo Planes
  445. || obj->isKindOf( KINDOF_MOB_NEXUS )
  446. || objectToEnter->isKindOf( KINDOF_IGNORED_IN_GUI ) ) // As in Cargo Planes
  447. {
  448. return FALSE;
  449. }
  450. if (objectToEnter->isDisabledByType( DISABLED_SUBDUED ))
  451. return FALSE; // a microwave tank has soldered the doors shut
  452. if( obj->isKindOf( KINDOF_STRUCTURE ) || obj->isKindOf( KINDOF_IMMOBILE ) )
  453. {
  454. //Structures or immobiles can't garrison
  455. return FALSE;
  456. }
  457. // Special case for unmanned vehicles. Any infantry unit can take over any unmanned vehicle!
  458. if( obj->isKindOf( KINDOF_INFANTRY ) && objectToEnter->isDisabledByType( DISABLED_UNMANNED ) )
  459. {
  460. if( !obj->isKindOf( KINDOF_REJECT_UNMANNED ) )
  461. {
  462. //But only if it's allowed to.
  463. return TRUE;
  464. }
  465. }
  466. // Special case for aircraft.
  467. if( obj->isKindOf( KINDOF_AIRCRAFT ) && objectToEnter->isKindOf( KINDOF_FS_AIRFIELD ) )
  468. {
  469. if( obj->getStatusBits().test( OBJECT_STATUS_DECK_HEIGHT_OFFSET ) && obj->getCarrierDeckHeight() >= obj->getPosition()->z )
  470. {
  471. return FALSE;
  472. }
  473. if (!obj->isAboveTerrain())
  474. return FALSE;
  475. if( obj->getControllingPlayer() == objectToEnter->getControllingPlayer() )
  476. {
  477. //Kris -- added code to prevent aircraft from landing in any airstrips other than their own!
  478. /// @todo srj -- this is horrible, but expedient.
  479. for (BehaviorModule** i = objectToEnter->getBehaviorModules(); *i; ++i)
  480. {
  481. ParkingPlaceBehaviorInterface* pp = (*i)->getParkingPlaceBehaviorInterface();
  482. if (pp == NULL)
  483. continue;
  484. if (pp->hasReservedSpace(obj->getID()))
  485. return TRUE;
  486. if (pp->shouldReserveDoorWhenQueued(obj->getTemplate()) && pp->hasAvailableSpaceFor(obj->getTemplate()))
  487. return TRUE;
  488. }
  489. }
  490. return FALSE;
  491. }
  492. // first, see if we'd like to collide with 'other'
  493. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  494. {
  495. CollideModuleInterface* collide = (*m)->getCollide();
  496. if (!collide)
  497. continue;
  498. if( collide->wouldLikeToCollideWith( objectToEnter ) )
  499. {
  500. //I thought this was a little confusing that it would return TRUE here before
  501. //getting to any of the other checks. The key is that it usually doesn't return
  502. //TRUE because most things aren't trying to collide with objects. This is different
  503. //for terrorist converting carbombs, and pilots entering vehicles. In these cases,
  504. //the vehicles don't have transport capacities, therefore returning true here
  505. //foregoes that checking later on.
  506. return TRUE;
  507. }
  508. }
  509. #ifdef ALLOW_SURRENDER
  510. if( objectToEnter->isKindOf( KINDOF_PRISON ) )
  511. {
  512. //We can't manually enter a prison!
  513. return FALSE;
  514. }
  515. #endif
  516. #ifdef ALLOW_SURRENDER
  517. if( objectToEnter->isKindOf( KINDOF_POW_TRUCK ) )
  518. {
  519. //We can't manually enter POWTruck, either!
  520. return FALSE;
  521. }
  522. #endif
  523. // make sure our objectToEnter has a contain module.
  524. ContainModuleInterface *contain = objectToEnter->getContain();
  525. if( !contain )
  526. {
  527. return FALSE;
  528. }
  529. if( contain->isHealContain() )
  530. {
  531. BodyModuleInterface *body = obj->getBodyModule();
  532. if( body->getHealth() == body->getMaxHealth() )
  533. {
  534. //This container is only used for the purposes of healing and we cannot
  535. //enter it with full health. This is not a normal container.
  536. return FALSE;
  537. }
  538. }
  539. if (mode == COMBATDROP_INTO)
  540. {
  541. // we don't care about valid container-ness, but we DO care about faction structures...
  542. // we aren't allowed to combat drop into them
  543. if (objectToEnter->isFactionStructure())
  544. return FALSE;
  545. }
  546. else
  547. {
  548. Bool checkCapacity = (mode == CHECK_CAPACITY);
  549. Int containCount = contain->getContainCount();
  550. Int stealthContainCount = contain->getStealthUnitsContained();
  551. Int nonStealthContainCount = containCount - stealthContainCount;
  552. // not ours... must do special checks.
  553. if (objectToEnter->getControllingPlayer() != obj->getControllingPlayer())
  554. {
  555. // not empty... can't do it.
  556. if (nonStealthContainCount > 0)
  557. return FALSE;
  558. // faction structure... can't do it.
  559. if (objectToEnter->isFactionStructure())
  560. return FALSE;
  561. // it's stealth-garrisoned... ignore check-cap and fall thru to
  562. // normal isValid test.
  563. if (stealthContainCount > 0 && nonStealthContainCount == 0)
  564. checkCapacity = FALSE;
  565. }
  566. // if our transport slot count is zero, we can't be transported. so punt.
  567. /// @todo srj -- seems like we should check always (not just for checkCap), but scared to change now -- check later
  568. if( checkCapacity && obj->getTransportSlotCount() == 0 )
  569. {
  570. return FALSE;
  571. }
  572. // finally: make sure that objectToEnter is a valid container for obj
  573. if( contain->isValidContainerFor( obj, checkCapacity ) == FALSE )
  574. {
  575. return FALSE;
  576. }
  577. }
  578. return TRUE;
  579. }
  580. // ------------------------------------------------------------------------------------------------
  581. // ------------------------------------------------------------------------------------------------
  582. CanAttackResult ActionManager::getCanAttackObject( const Object *obj, const Object *objectToAttack, CommandSourceType commandSource, AbleToAttackType attackType )
  583. {
  584. // sanity
  585. if( !obj || !objectToAttack || obj->isEffectivelyDead() || objectToAttack->isEffectivelyDead() || objectToAttack == obj )
  586. {
  587. return ATTACKRESULT_NOT_POSSIBLE;
  588. }
  589. if( !obj->isAbleToAttack() )
  590. {
  591. return ATTACKRESULT_NOT_POSSIBLE;
  592. }
  593. //has any weapons that are capable of inflicting damage. Special damage types are rejected
  594. //such as hack weapons... others can be added.
  595. CanAttackResult result = obj->getAbleToAttackSpecificObject( attackType, objectToAttack, commandSource );
  596. if( result != ATTACKRESULT_NOT_POSSIBLE )
  597. {
  598. //Kris: August 5, 2003
  599. //Fix a case where the Demo_GLAInfantryWorker is able to attack using his passive bomb upgrade. We don't
  600. //want him to allow a visible attack cursor for the player. This code never checked for AutoChoosesSources
  601. //logic, but now we will but only when the commandSource is FROM_PLAYER.
  602. if( commandSource == CMD_FROM_PLAYER )
  603. {
  604. //Check if it's got any weapons that can be used.
  605. Bool anyValidWeapon = FALSE;
  606. for( Int i = 0; i < WEAPONSLOT_COUNT; i++ )
  607. {
  608. UnsignedInt cmdSourceMask = obj->getWeaponInWeaponSlotCommandSourceMask( (WeaponSlotType)i );
  609. if( cmdSourceMask )
  610. {
  611. anyValidWeapon = TRUE;
  612. break;
  613. }
  614. }
  615. if( !anyValidWeapon )
  616. {
  617. return ATTACKRESULT_NOT_POSSIBLE;
  618. }
  619. }
  620. if( result == ATTACKRESULT_INVALID_SHOT && obj->isKindOf( KINDOF_DOZER ) )
  621. {
  622. //For the case of dozers, we don't ever want to see an attack cursor
  623. //unless it's valid on a mine.
  624. const Weapon *weapon = obj->getCurrentWeapon();
  625. if( weapon && weapon->getDamageType() == DAMAGE_DISARM )
  626. {
  627. return ATTACKRESULT_NOT_POSSIBLE;
  628. }
  629. }
  630. return result;
  631. }
  632. //Special case code for stinger sites: Stinger sites have no weapons, instead -- their spawns are the weapons, in this case the
  633. //stinger soldiers.
  634. if( obj->isKindOf( KINDOF_SPAWNS_ARE_THE_WEAPONS ) )
  635. {
  636. //Look at the spawn behavior and evaluate them!
  637. SpawnBehaviorInterface *spawnInterface = obj->getSpawnBehaviorInterface();
  638. if( spawnInterface )
  639. {
  640. //We found the spawn interface, now get the closest slave to the target.
  641. Object *slave = spawnInterface->getClosestSlave( objectToAttack->getPosition() );
  642. if( slave )
  643. {
  644. result = slave->getAbleToAttackSpecificObject( attackType, objectToAttack, commandSource );
  645. if( result != ATTACKRESULT_NOT_POSSIBLE )
  646. {
  647. return result;
  648. }
  649. }
  650. }
  651. else if( result == ATTACKRESULT_NOT_POSSIBLE )// oh dear me. The wierd case of a garrisoncontainer being a KINDOF_SPAWNS_ARE_THE_WEAPONS... the AmericaBuildingFirebase
  652. {
  653. ContainModuleInterface *contain = obj->getContain();
  654. if ( contain )
  655. {
  656. Object *rider = contain->getClosestRider( objectToAttack->getPosition() );
  657. if ( rider )
  658. {
  659. result = rider->getAbleToAttackSpecificObject( attackType, objectToAttack, commandSource );
  660. if( result != ATTACKRESULT_NOT_POSSIBLE )
  661. return result;
  662. }
  663. }
  664. }
  665. }
  666. return ATTACKRESULT_NOT_POSSIBLE;
  667. }
  668. // ------------------------------------------------------------------------------------------------
  669. // ------------------------------------------------------------------------------------------------
  670. Bool ActionManager::canConvertObjectToCarBomb( const Object *obj, const Object *objectToConvert, CommandSourceType commandSource )
  671. {
  672. // sanity
  673. if( obj == NULL || objectToConvert == NULL )
  674. {
  675. return FALSE;
  676. }
  677. if( objectToConvert->isEffectivelyDead() )
  678. {
  679. return FALSE;
  680. }
  681. // if the target is in the shroud, we can't do anything
  682. if (isObjectShroudedForAction(obj, objectToConvert, commandSource))
  683. return FALSE;
  684. // first, see if we'd like to collide with 'other'
  685. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  686. {
  687. CollideModuleInterface* collide = (*m)->getCollide();
  688. if (!collide)
  689. continue;
  690. if( collide->wouldLikeToCollideWith( objectToConvert ) && collide->isCarBombCrateCollide() )
  691. {
  692. return TRUE;
  693. }
  694. }
  695. return FALSE;
  696. }
  697. // ------------------------------------------------------------------------------------------------
  698. // ------------------------------------------------------------------------------------------------
  699. Bool ActionManager::canHijackVehicle( const Object *obj, const Object *objectToHijack, CommandSourceType commandSource ) //LORENZEN
  700. {
  701. // sanity
  702. if( obj == NULL || objectToHijack == NULL )
  703. {
  704. return FALSE;
  705. }
  706. //Make sure it's alive.
  707. if( objectToHijack->isEffectivelyDead() )
  708. {
  709. return FALSE;
  710. }
  711. // if the target is in the shroud, we can't do anything
  712. if (isObjectShroudedForAction(obj, objectToHijack, commandSource))
  713. {
  714. return FALSE;
  715. }
  716. Relationship r = obj->getRelationship(objectToHijack);
  717. //Only hijack enemy objects
  718. if( r != ENEMIES )
  719. {
  720. return FALSE;
  721. }
  722. //Make sure target is a vehicle.
  723. if( ! objectToHijack->isKindOf( KINDOF_VEHICLE ) )
  724. {
  725. return FALSE;
  726. }
  727. //Kris -- Hijackers can no longer hijack any aircraft.
  728. if( objectToHijack->isKindOf( KINDOF_AIRCRAFT ) )
  729. {
  730. return FALSE;
  731. }
  732. //Can't hijack a drone type.
  733. if( objectToHijack->isKindOf( KINDOF_DRONE ) )
  734. {
  735. return FALSE;
  736. }
  737. // last, see if we'd like to collide with 'objectToHijack'
  738. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  739. {
  740. CollideModuleInterface* collide = (*m)->getCollide();
  741. if (!collide)
  742. continue;
  743. if( collide->wouldLikeToCollideWith( objectToHijack ) && collide->isHijackedVehicleCrateCollide() )
  744. {
  745. return TRUE;
  746. }
  747. }
  748. return FALSE;
  749. }
  750. // ------------------------------------------------------------------------------------------------
  751. Bool ActionManager::canSabotageBuilding( const Object *obj, const Object *objectToSabotage, CommandSourceType commandSource )
  752. {
  753. // sanity
  754. if( obj == NULL || objectToSabotage == NULL )
  755. {
  756. return FALSE;
  757. }
  758. //Make sure it's alive.
  759. if( objectToSabotage->isEffectivelyDead() )
  760. {
  761. return FALSE;
  762. }
  763. // if the target is in the shroud, we can't do anything
  764. if (isObjectShroudedForAction(obj, objectToSabotage, commandSource))
  765. {
  766. return FALSE;
  767. }
  768. Relationship r = obj->getRelationship(objectToSabotage);
  769. //Only sabotage enemy objects
  770. if( r != ENEMIES )
  771. {
  772. return FALSE;
  773. }
  774. // last, see if we'd like to collide with 'objectToSabotage'
  775. for (BehaviorModule** m = obj->getBehaviorModules(); *m; ++m)
  776. {
  777. CollideModuleInterface* collide = (*m)->getCollide();
  778. if (!collide)
  779. continue;
  780. if( collide->wouldLikeToCollideWith( objectToSabotage ) && collide->isSabotageBuildingCrateCollide() )
  781. {
  782. return TRUE;
  783. }
  784. }
  785. return FALSE;
  786. }
  787. // ------------------------------------------------------------------------------------------------
  788. // ------------------------------------------------------------------------------------------------
  789. Bool ActionManager::canMakeObjectDefector( const Object *obj, const Object *objectToMakeDefector, CommandSourceType commandSource ) //LORENZEN
  790. {
  791. // sanity
  792. if( obj == NULL || objectToMakeDefector == NULL )
  793. {
  794. return FALSE;
  795. }
  796. Relationship r = obj->getRelationship(objectToMakeDefector);
  797. //Only make defectors of enemy objects
  798. if( r != ENEMIES )
  799. {
  800. return FALSE;
  801. }
  802. //Make sure it's alive.
  803. if( objectToMakeDefector->isEffectivelyDead() )
  804. {
  805. return FALSE;
  806. }
  807. // if the target is in the shroud, we can't do anything
  808. if (isObjectShroudedForAction(obj, objectToMakeDefector, commandSource))
  809. {
  810. return FALSE;
  811. }
  812. return TRUE;
  813. }
  814. // ------------------------------------------------------------------------------------------------
  815. // ------------------------------------------------------------------------------------------------
  816. Bool ActionManager::canCaptureBuilding( const Object *obj, const Object *objectToCapture, CommandSourceType commandSource )
  817. {
  818. // sanity
  819. if( obj == NULL || objectToCapture == NULL )
  820. return FALSE;
  821. //Make sure our object has the capability of performing this special ability.
  822. Bool isOwnerBlackLotus = obj->hasSpecialPower( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
  823. if( !obj->hasSpecialPower( SPECIAL_INFANTRY_CAPTURE_BUILDING ) && !isOwnerBlackLotus)
  824. {
  825. return false;
  826. }
  827. if( objectToCapture->isKindOf( KINDOF_IMMUNE_TO_CAPTURE ) )
  828. {
  829. return false;
  830. }
  831. // 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
  832. // if ( isOwnerBlackLotus )
  833. // {
  834. // SpecialPowerModuleInterface *disableSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
  835. // if ( disableSPI && disableSPI->isBusy() )
  836. // return FALSE;
  837. // SpecialPowerModuleInterface *cashSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
  838. // if ( cashSPI && cashSPI->isBusy() )
  839. // return FALSE;
  840. // }
  841. SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_INFANTRY_CAPTURE_BUILDING );
  842. if (!spInterface)
  843. spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
  844. if (!spInterface)
  845. return false;
  846. if( spInterface->getPercentReady() < 1.0f )
  847. {
  848. // Special not ready or non-existent.
  849. return false;
  850. }
  851. // can't capture dead things.
  852. if (objectToCapture->isEffectivelyDead())
  853. {
  854. return FALSE;
  855. }
  856. // Make sure we are targeting a building!
  857. if( !objectToCapture->isKindOf( KINDOF_STRUCTURE ) )
  858. {
  859. return FALSE;
  860. }
  861. // can't capture things that are under construction, or sold.
  862. if (objectToCapture->testStatus(OBJECT_STATUS_UNDER_CONSTRUCTION) ||
  863. objectToCapture->testStatus(OBJECT_STATUS_SOLD))
  864. {
  865. return FALSE;
  866. }
  867. // if the target is in the shroud, we can't do anything
  868. if (isObjectShroudedForAction(obj, objectToCapture, commandSource))
  869. return FALSE;
  870. Relationship r = obj->getRelationship(objectToCapture);
  871. // ensure that it's capturable, and not allied
  872. // exception: we can always capture enemy bldgs, regardless of kindof
  873. if (!(r == ENEMIES || (objectToCapture->isKindOf(KINDOF_CAPTURABLE) && r != ALLIES)))
  874. return false;
  875. //If the enemy unit is stealthed and not detected, then we can't capture it!
  876. if( objectToCapture->testStatus( OBJECT_STATUS_STEALTHED ) &&
  877. !objectToCapture->testStatus( OBJECT_STATUS_DETECTED ) &&
  878. !objectToCapture->testStatus( OBJECT_STATUS_DISGUISED ) )
  879. {
  880. return FALSE;
  881. }
  882. // if it's garrisoned already, we cannot capture it.
  883. // (unless it's just stealth-garrisoned.)
  884. ContainModuleInterface *contain = objectToCapture->getContain();
  885. if (contain != NULL && contain->isGarrisonable())
  886. {
  887. Int containCount = contain->getContainCount();
  888. Int stealthContainCount = contain->getStealthUnitsContained();
  889. Int nonStealthContainCount = containCount - stealthContainCount;
  890. if (nonStealthContainCount > 0)
  891. return FALSE;
  892. }
  893. // Also check if the object is a container containing stealth units, tricking
  894. // the player into thinking it isn't actually an enemy.
  895. if (appearsToContainFriendlies(obj, objectToCapture))
  896. return FALSE;
  897. return TRUE;
  898. }
  899. // ------------------------------------------------------------------------------------------------
  900. // ------------------------------------------------------------------------------------------------
  901. Bool ActionManager::canDisableVehicleViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource, Bool checkSourceRequirements)
  902. {
  903. // sanity
  904. if( obj == NULL || objectToHack == NULL )
  905. return FALSE;
  906. if (checkSourceRequirements)
  907. {
  908. //Make sure our object has the capability of performing this special ability.
  909. if( !obj->hasSpecialPower( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK ) )
  910. {
  911. return false;
  912. }
  913. }
  914. // 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
  915. // SpecialPowerModuleInterface *captureSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
  916. // if ( captureSPI && captureSPI->isBusy() )
  917. // return FALSE;
  918. // SpecialPowerModuleInterface *cashSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
  919. // if ( cashSPI && cashSPI->isBusy() )
  920. // return FALSE;
  921. SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
  922. if (checkSourceRequirements)
  923. {
  924. if( !spInterface || spInterface->getPercentReady() < 1.0f )
  925. {
  926. //Special not ready or non-existent.
  927. return FALSE;
  928. }
  929. }
  930. if( objectToHack->isEffectivelyDead() )
  931. {
  932. return FALSE;
  933. }
  934. if( objectToHack->isKindOf( KINDOF_AIRCRAFT ) || objectToHack->isAirborneTarget() )
  935. {
  936. return false;
  937. }
  938. // if the target is in the shroud, we can't do anything
  939. if (isObjectShroudedForAction(obj, objectToHack, commandSource))
  940. return FALSE;
  941. Relationship r = obj->getRelationship(objectToHack);
  942. // Make sure object is an enemy
  943. if( r == ENEMIES )
  944. {
  945. //Make sure we are targeting a building!
  946. if( !objectToHack->isKindOf( KINDOF_VEHICLE ) )
  947. {
  948. return FALSE;
  949. }
  950. //If the enemy unit is stealthed and not detected, then we can't attack it!
  951. if( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
  952. !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
  953. !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
  954. {
  955. return FALSE;
  956. }
  957. //Also check if the object is a container containing stealth units tricking
  958. //the player into thinking it isn't actually an enemy.
  959. if (appearsToContainFriendlies(obj, objectToHack))
  960. return FALSE;
  961. return TRUE;
  962. }
  963. return FALSE;
  964. }
  965. #ifdef ALLOW_SURRENDER
  966. // ------------------------------------------------------------------------------------------------
  967. /** Can 'obj' pick up the prisoner 'prisoner' */
  968. // ------------------------------------------------------------------------------------------------
  969. Bool ActionManager::canPickUpPrisoner( const Object *obj, const Object *prisoner, CommandSourceType commandSource )
  970. {
  971. // sanity
  972. if( obj == NULL || prisoner == NULL )
  973. return FALSE;
  974. // only pow trucks can pick up anything
  975. if( obj->isKindOf( KINDOF_POW_TRUCK ) == FALSE )
  976. return FALSE;
  977. // only infantry can be picked up
  978. if( prisoner->isKindOf( KINDOF_INFANTRY ) == FALSE )
  979. return FALSE;
  980. // prisoner cannot be contained inside anything
  981. if( prisoner->getContainedBy() )
  982. return FALSE;
  983. // prisoner must be in a surrendered state
  984. const AIUpdateInterface *ai = prisoner->getAI();
  985. if( ai == NULL || ai->isSurrendered() == FALSE )
  986. return FALSE;
  987. // prisoner must have been put in a surrendered state by our own player
  988. // (or be surrendered to "everyone")
  989. Int idx = ai->getSurrenderedPlayerIndex();
  990. Player* surrenderedToPlayer = (idx >= 0) ? ThePlayerList->getNthPlayer(idx) : NULL;
  991. if (surrenderedToPlayer != NULL && surrenderedToPlayer != obj->getControllingPlayer())
  992. return FALSE;
  993. // we must be enemies
  994. if( obj->getRelationship( prisoner ) != ENEMIES )
  995. return FALSE;
  996. return TRUE;
  997. } // end canPickUpPrisoner
  998. #endif
  999. // ------------------------------------------------------------------------------------------------
  1000. // ------------------------------------------------------------------------------------------------
  1001. Bool ActionManager::canStealCashViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource )
  1002. {
  1003. // sanity
  1004. if( obj == NULL || objectToHack == NULL )
  1005. return FALSE;
  1006. //Make sure our object has the capability of performing this special ability.
  1007. if( !obj->hasSpecialPower( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK ) )
  1008. {
  1009. return false;
  1010. }
  1011. // 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
  1012. // SpecialPowerModuleInterface *captureSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_CAPTURE_BUILDING );
  1013. // if ( captureSPI && captureSPI->isBusy() )
  1014. // return FALSE;
  1015. // SpecialPowerModuleInterface *disableSPI = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK );
  1016. // if ( disableSPI && disableSPI->isBusy() )
  1017. // return FALSE;
  1018. SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_BLACKLOTUS_STEAL_CASH_HACK );
  1019. if( !spInterface || spInterface->getPercentReady() < 1.0f )
  1020. {
  1021. //Special not ready or non-existent.
  1022. return false;
  1023. }
  1024. if( objectToHack->isEffectivelyDead() )
  1025. {
  1026. return FALSE;
  1027. }
  1028. if( objectToHack->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  1029. {
  1030. return FALSE;
  1031. }
  1032. // if the target is in the shroud, we can't do anything
  1033. if (isObjectShroudedForAction(obj, objectToHack, commandSource))
  1034. return FALSE;
  1035. Relationship r = obj->getRelationship(objectToHack);
  1036. // Make sure object is an enemy
  1037. if( r == ENEMIES )
  1038. {
  1039. //Make sure we are targeting something that contains cash!
  1040. if( !objectToHack->isKindOf( KINDOF_CASH_GENERATOR ) )
  1041. {
  1042. return FALSE;
  1043. }
  1044. //Make sure object isn't under construction!
  1045. if( objectToHack->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  1046. {
  1047. return FALSE;
  1048. }
  1049. //Make sure the building is considered hackable (temp: using capturable)
  1050. if( !objectToHack->isKindOf( KINDOF_CAPTURABLE ) || objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) )
  1051. {
  1052. return FALSE;
  1053. }
  1054. //If the enemy unit is stealthed and not detected, then we can't attack it!
  1055. if( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
  1056. !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
  1057. !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
  1058. {
  1059. return FALSE;
  1060. }
  1061. //Also check if the object is a container containing stealth units tricking
  1062. //the player into thinking it isn't actually an enemy.
  1063. if (appearsToContainFriendlies(obj, objectToHack))
  1064. return FALSE;
  1065. return TRUE;
  1066. }
  1067. return FALSE;
  1068. }
  1069. // ------------------------------------------------------------------------------------------------
  1070. // ------------------------------------------------------------------------------------------------
  1071. Bool ActionManager::canDisableBuildingViaHacking( const Object *obj, const Object *objectToHack, CommandSourceType commandSource )
  1072. {
  1073. // sanity
  1074. if( obj == NULL || objectToHack == NULL )
  1075. return FALSE;
  1076. //Make sure our object has the capability of performing this special ability.
  1077. if( !obj->hasSpecialPower( SPECIAL_HACKER_DISABLE_BUILDING ) )
  1078. {
  1079. return FALSE;
  1080. }
  1081. SpecialPowerModuleInterface *spInterface = obj->findSpecialPowerModuleInterface( SPECIAL_HACKER_DISABLE_BUILDING );
  1082. if( !spInterface || spInterface->getPercentReady() < 1.0f )
  1083. {
  1084. //Special not ready or non-existent.
  1085. return FALSE;
  1086. }
  1087. if( objectToHack->isEffectivelyDead() )
  1088. {
  1089. return FALSE;
  1090. }
  1091. // if the target is in the shroud, we can't do anything
  1092. if (isObjectShroudedForAction(obj, objectToHack, commandSource))
  1093. return FALSE;
  1094. Relationship r = obj->getRelationship(objectToHack);
  1095. // Make sure object is an enemy
  1096. if( r != ENEMIES )
  1097. return FALSE;
  1098. //Make sure we are targeting a building!
  1099. if( !objectToHack->isKindOf( KINDOF_STRUCTURE ) )
  1100. {
  1101. return FALSE;
  1102. }
  1103. //Make sure the building is considered hackable (temp: using capturable)
  1104. // An exception is any TechFactionBuilding that is not explicitly immune to capture
  1105. if( ( !objectToHack->isKindOf( KINDOF_CAPTURABLE ) || objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) ) &&
  1106. ! (objectToHack->isKindOf(KINDOF_FS_TECHNOLOGY) && ! objectToHack->isKindOf(KINDOF_IMMUNE_TO_CAPTURE)) )
  1107. {
  1108. return FALSE;
  1109. }
  1110. if ( objectToHack->isKindOf( KINDOF_REBUILD_HOLE ) || objectToHack->testStatus( OBJECT_STATUS_UNDER_CONSTRUCTION ))
  1111. return FALSE;
  1112. //If the enemy unit is stealthed and not detected, then we can't attack it!
  1113. if( objectToHack->testStatus( OBJECT_STATUS_STEALTHED ) &&
  1114. !objectToHack->testStatus( OBJECT_STATUS_DETECTED ) &&
  1115. !objectToHack->testStatus( OBJECT_STATUS_DISGUISED ) )
  1116. {
  1117. return FALSE;
  1118. }
  1119. //Also check if the object is a container containing stealth units tricking
  1120. //the player into thinking it isn't actually an enemy.
  1121. if (appearsToContainFriendlies(obj, objectToHack))
  1122. return FALSE;
  1123. return TRUE;
  1124. }
  1125. // ------------------------------------------------------------------------------------------------
  1126. Bool ActionManager::canBribeUnit( const Object *obj, const Object *objectToBribe, CommandSourceType commandSource )
  1127. {
  1128. return FALSE;
  1129. }
  1130. // ------------------------------------------------------------------------------------------------
  1131. Bool ActionManager::canCutBuildingPower( const Object *obj, const Object *building, CommandSourceType commandSource )
  1132. {
  1133. return FALSE;
  1134. }
  1135. // ------------------------------------------------------------------------------------------------
  1136. // ------------------------------------------------------------------------------------------------
  1137. Bool ActionManager::canSnipeVehicle( const Object *obj, const Object *objectToSnipe, CommandSourceType commandSource )
  1138. {
  1139. //Sanity check
  1140. if( obj == NULL || objectToSnipe == NULL )
  1141. {
  1142. return FALSE;
  1143. }
  1144. //Make sure it's alive.
  1145. if( objectToSnipe->isEffectivelyDead() )
  1146. {
  1147. return FALSE;
  1148. }
  1149. // if the target is in the shroud, we can't do anything
  1150. if (isObjectShroudedForAction(obj, objectToSnipe, commandSource))
  1151. return FALSE;
  1152. Relationship r = obj->getRelationship(objectToSnipe);
  1153. if( r == ENEMIES )
  1154. {
  1155. //Make sure target is a vehicle.
  1156. if( !objectToSnipe->isKindOf( KINDOF_VEHICLE ) )
  1157. {
  1158. return FALSE;
  1159. }
  1160. //Can't be a drone type.
  1161. if( objectToSnipe->isKindOf( KINDOF_DRONE ) )
  1162. {
  1163. return FALSE;
  1164. }
  1165. //Make sure object is not flying
  1166. if( objectToSnipe->isAirborneTarget() )
  1167. {
  1168. return FALSE;
  1169. }
  1170. //Make sure the vehicle is manned!
  1171. if( objectToSnipe->isDisabledByType( DISABLED_UNMANNED ) )
  1172. {
  1173. return FALSE;
  1174. }
  1175. return TRUE;
  1176. }
  1177. return FALSE;
  1178. }
  1179. //-------------------------------------------------------------------------------------------------
  1180. inline Bool isPointOnMap( const Coord3D *testPos )
  1181. {
  1182. Region3D mapRegion;
  1183. TheTerrainLogic->getExtent( &mapRegion );
  1184. return mapRegion.isInRegionNoZ( testPos );
  1185. }
  1186. // ------------------------------------------------------------------------------------------------
  1187. // ------------------------------------------------------------------------------------------------
  1188. Bool ActionManager::canDoSpecialPowerAtLocation( const Object *obj, const Coord3D *loc, CommandSourceType commandSource, const SpecialPowerTemplate *spTemplate, const Object *objectInWay, UnsignedInt commandOptions, Bool checkSourceRequirements )
  1189. {
  1190. if (checkSourceRequirements)
  1191. {
  1192. //First check, if our object can do this special power.
  1193. if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
  1194. {
  1195. return false;
  1196. }
  1197. }
  1198. SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
  1199. if( mod )
  1200. {
  1201. if (checkSourceRequirements)
  1202. {
  1203. if( mod->getPercentReady() < 1.0f )
  1204. {
  1205. //Not fully ready
  1206. return false;
  1207. }
  1208. }
  1209. // First check terrain type, if it is cared about. Don't return a true, since there are more checks.
  1210. switch( spTemplate->getSpecialPowerType() )
  1211. {
  1212. case SPECIAL_PARADROP_AMERICA:
  1213. case INFA_SPECIAL_PARADROP_AMERICA:
  1214. case SPECIAL_CRATE_DROP:
  1215. case SPECIAL_TANK_PARADROP:
  1216. {
  1217. if( TheTerrainLogic->isUnderwater( loc->x, loc->y ) )
  1218. return FALSE;
  1219. }
  1220. }
  1221. // Last check is shroudedness, if it is cared about
  1222. switch( spTemplate->getSpecialPowerType() )
  1223. {
  1224. case SPECIAL_DAISY_CUTTER:
  1225. case AIRF_SPECIAL_DAISY_CUTTER:
  1226. case SPECIAL_PARADROP_AMERICA:
  1227. case SPECIAL_TANK_PARADROP:
  1228. case INFA_SPECIAL_PARADROP_AMERICA:
  1229. case SPECIAL_CARPET_BOMB:
  1230. case SPECIAL_CHINA_CARPET_BOMB:
  1231. case SPECIAL_LEAFLET_DROP:
  1232. case EARLY_SPECIAL_LEAFLET_DROP:
  1233. case EARLY_SPECIAL_CHINA_CARPET_BOMB:
  1234. case AIRF_SPECIAL_CARPET_BOMB:
  1235. case SUPR_SPECIAL_CRUISE_MISSILE:
  1236. case SPECIAL_CLUSTER_MINES:
  1237. case NUKE_SPECIAL_CLUSTER_MINES:
  1238. case SPECIAL_EMP_PULSE:
  1239. case SPECIAL_CRATE_DROP:
  1240. case SPECIAL_NAPALM_STRIKE:
  1241. case SPECIAL_BLACK_MARKET_NUKE:
  1242. case SPECIAL_ANTHRAX_BOMB:
  1243. case SPECIAL_TERROR_CELL:
  1244. case SPECIAL_AMBUSH:
  1245. case SPECIAL_NEUTRON_MISSILE:
  1246. case NUKE_SPECIAL_NEUTRON_MISSILE:
  1247. case SUPW_SPECIAL_NEUTRON_MISSILE:
  1248. case SPECIAL_SCUD_STORM:
  1249. #ifdef ALLOW_DEMORALIZE
  1250. case SPECIAL_DEMORALIZE:
  1251. #endif
  1252. case SPECIAL_A10_THUNDERBOLT_STRIKE:
  1253. case AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
  1254. case SPECIAL_SPECTRE_GUNSHIP:
  1255. case AIRF_SPECIAL_SPECTRE_GUNSHIP:
  1256. case SPECIAL_REPAIR_VEHICLES:
  1257. case EARLY_SPECIAL_REPAIR_VEHICLES:
  1258. case SPECIAL_GPS_SCRAMBLER:
  1259. case SLTH_SPECIAL_GPS_SCRAMBLER:
  1260. case SPECIAL_ARTILLERY_BARRAGE:
  1261. case SPECIAL_FRENZY:
  1262. case EARLY_SPECIAL_FRENZY:
  1263. case SPECIAL_PARTICLE_UPLINK_CANNON:
  1264. case SUPW_SPECIAL_PARTICLE_UPLINK_CANNON:
  1265. case LAZR_SPECIAL_PARTICLE_UPLINK_CANNON:
  1266. case SPECIAL_CLEANUP_AREA:
  1267. case SPECIAL_SNEAK_ATTACK:
  1268. case SPECIAL_BATTLESHIP_BOMBARDMENT:
  1269. //Don't allow "damaging" special powers in shrouded areas, but Fogged are okay.
  1270. return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED;
  1271. case SPECIAL_SPY_SATELLITE:
  1272. case SPECIAL_RADAR_VAN_SCAN:
  1273. case SPECIAL_SPY_DRONE:
  1274. case SPECIAL_HELIX_NAPALM_BOMB:
  1275. //These specials can be used anywhere!
  1276. return isPointOnMap( loc );
  1277. case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
  1278. return TRUE;
  1279. //These special powers require object targets!
  1280. case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
  1281. case SPECIAL_HACKER_DISABLE_BUILDING:
  1282. case SPECIAL_TANKHUNTER_TNT_ATTACK:
  1283. case SPECIAL_BOOBY_TRAP:
  1284. case SPECIAL_CASH_HACK:
  1285. case SPECIAL_DEFECTOR:
  1286. case SPECIAL_BLACKLOTUS_CAPTURE_BUILDING:
  1287. case SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK:
  1288. case SPECIAL_BLACKLOTUS_STEAL_CASH_HACK:
  1289. case SPECIAL_INFANTRY_CAPTURE_BUILDING:
  1290. case SPECIAL_DETONATE_DIRTY_NUKE:
  1291. case SPECIAL_DISGUISE_AS_VEHICLE:
  1292. case SPECIAL_REMOTE_CHARGES:
  1293. case SPECIAL_TIMED_CHARGES:
  1294. case SPECIAL_CASH_BOUNTY:
  1295. case SPECIAL_CHANGE_BATTLE_PLANS:
  1296. return false;
  1297. }
  1298. }
  1299. return false;
  1300. }
  1301. // ------------------------------------------------------------------------------------------------
  1302. // ------------------------------------------------------------------------------------------------
  1303. Bool ActionManager::canDoSpecialPowerAtObject( const Object *obj, const Object *target, CommandSourceType commandSource, const SpecialPowerTemplate *spTemplate, UnsignedInt commandOptions, Bool checkSourceRequirements )
  1304. {
  1305. if (checkSourceRequirements)
  1306. {
  1307. //First check, if our object can do this special power.
  1308. if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
  1309. {
  1310. return false;
  1311. }
  1312. }
  1313. if( target->isEffectivelyDead() )
  1314. {
  1315. return FALSE;
  1316. }
  1317. Relationship r = obj->getRelationship(target);
  1318. SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
  1319. if( mod )
  1320. {
  1321. if (checkSourceRequirements)
  1322. {
  1323. if( mod->getPercentReady() < 1.0f )
  1324. {
  1325. //Not fully ready
  1326. return false;
  1327. }
  1328. }
  1329. // if the target is in the shroud, we can't do anything
  1330. if (isObjectShroudedForAction(obj, target, commandSource))
  1331. return FALSE;
  1332. switch( spTemplate->getSpecialPowerType() )
  1333. {
  1334. case SPECIAL_CASH_BOUNTY:
  1335. return false;
  1336. case SPECIAL_BATTLESHIP_BOMBARDMENT:
  1337. if( obj->getRelationship( target ) != ALLIES )
  1338. {
  1339. return TRUE;
  1340. }
  1341. return FALSE;
  1342. case SPECIAL_TANKHUNTER_TNT_ATTACK:
  1343. if( target->isKindOf( KINDOF_STRUCTURE ) || (target->isKindOf( KINDOF_VEHICLE ) && !target->isKindOf(KINDOF_AIRCRAFT)) )
  1344. {
  1345. return true;
  1346. }
  1347. break;
  1348. case SPECIAL_BOOBY_TRAP:
  1349. {
  1350. // We can booby trap any building that is allied or neutral
  1351. if( target->isKindOf(KINDOF_STRUCTURE) && (r == NEUTRAL || r == ALLIES) )
  1352. {
  1353. return TRUE;
  1354. }
  1355. return FALSE;
  1356. }
  1357. case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
  1358. //Can only use laser guided missiles on vehicles!
  1359. if( target->isKindOf( KINDOF_VEHICLE ) && r == ENEMIES )
  1360. {
  1361. return true;
  1362. }
  1363. break;
  1364. case SPECIAL_HACKER_DISABLE_BUILDING:
  1365. //Can only disable buildings...
  1366. if( target->isKindOf( KINDOF_STRUCTURE ) && r == ENEMIES )
  1367. {
  1368. //Make sure the building is considered hackable (temp: using capturable)
  1369. if( !target->isKindOf( KINDOF_CAPTURABLE ) || target->isKindOf( KINDOF_REBUILD_HOLE ) )
  1370. {
  1371. return FALSE;
  1372. }
  1373. return true;
  1374. }
  1375. break;
  1376. case SPECIAL_INFANTRY_CAPTURE_BUILDING:
  1377. case SPECIAL_BLACKLOTUS_CAPTURE_BUILDING:
  1378. return canCaptureBuilding( obj, target, commandSource );
  1379. case SPECIAL_BLACKLOTUS_DISABLE_VEHICLE_HACK:
  1380. return canDisableVehicleViaHacking( obj, target, commandSource, false );
  1381. case SPECIAL_BLACKLOTUS_STEAL_CASH_HACK:
  1382. return canStealCashViaHacking( obj, target, commandSource );
  1383. case SPECIAL_CASH_HACK:
  1384. //Can only disable enemy supply centers.
  1385. if( target->isKindOf( KINDOF_STRUCTURE ) && r == ENEMIES )
  1386. {
  1387. //Make sure the building is considered hackable (temp: using capturable)
  1388. if( !target->isKindOf( KINDOF_CAPTURABLE ) || target->isKindOf( KINDOF_REBUILD_HOLE ) )
  1389. {
  1390. return FALSE;
  1391. }
  1392. //Can't cash hack a building that's under construction.
  1393. if( target->getStatusBits().test( OBJECT_STATUS_UNDER_CONSTRUCTION ) )
  1394. {
  1395. return FALSE;
  1396. }
  1397. if (target->isKindOf( KINDOF_CASH_GENERATOR ) )
  1398. {
  1399. return true;
  1400. }
  1401. }
  1402. break;
  1403. case SPECIAL_DISGUISE_AS_VEHICLE:
  1404. if( target->isKindOf( KINDOF_VEHICLE )
  1405. && !target->isKindOf( KINDOF_AIRCRAFT )
  1406. && !target->isKindOf( KINDOF_BOAT )
  1407. && !target->isKindOf( KINDOF_CLIFF_JUMPER ) )
  1408. {
  1409. //Don't allow it to disguise as another bomb truck -- that's just plain dumb.
  1410. //if( target->getTemplate() != obj->getTemplate() )
  1411. {
  1412. //Don't allow it to disguise as a train -- they don't have KINDOF_TRAIN yet, but
  1413. //if added, please change this code so it'll be faster!
  1414. static const NameKeyType key = NAMEKEY( "RailroadBehavior" );
  1415. RailroadBehavior *rBehavior = (RailroadBehavior*)target->findUpdateModule( key );
  1416. if( !rBehavior )
  1417. {
  1418. return true;
  1419. }
  1420. }
  1421. }
  1422. break;
  1423. case SPECIAL_DEFECTOR:
  1424. //buildings do not defect
  1425. if( ! target->isKindOf( KINDOF_STRUCTURE ) )
  1426. {
  1427. // only attacking type things will defect (no dozers, supply trucks, workers...)
  1428. // srj sez: I don't know why this is commented out, but it should remain thus, because
  1429. // it is not necessarily the case that dozers, workers, etc. cannot attack; they may
  1430. // "attack" Mines to disarm them...
  1431. // if ( target->isKindOf( KINDOF_CAN_ATTACK ) )
  1432. {
  1433. //neutral or same-team units are worthless defectors
  1434. if( r == ENEMIES )
  1435. {
  1436. return canMakeObjectDefector( obj, target, commandSource );
  1437. }
  1438. }
  1439. }
  1440. break;
  1441. //These special powers require locations, not objects!
  1442. case SPECIAL_DAISY_CUTTER:
  1443. case AIRF_SPECIAL_DAISY_CUTTER:
  1444. case SPECIAL_PARADROP_AMERICA:
  1445. case SPECIAL_TANK_PARADROP:
  1446. case INFA_SPECIAL_PARADROP_AMERICA:
  1447. case SPECIAL_CARPET_BOMB:
  1448. case SPECIAL_CHINA_CARPET_BOMB:
  1449. case SPECIAL_LEAFLET_DROP:
  1450. case EARLY_SPECIAL_LEAFLET_DROP:
  1451. case EARLY_SPECIAL_CHINA_CARPET_BOMB:
  1452. case AIRF_SPECIAL_CARPET_BOMB:
  1453. case SUPR_SPECIAL_CRUISE_MISSILE:
  1454. case SPECIAL_CLUSTER_MINES:
  1455. case NUKE_SPECIAL_CLUSTER_MINES:
  1456. case SPECIAL_EMP_PULSE:
  1457. case SPECIAL_CRATE_DROP:
  1458. case SPECIAL_NAPALM_STRIKE:
  1459. case SPECIAL_TERROR_CELL:
  1460. case SPECIAL_AMBUSH:
  1461. case SPECIAL_NEUTRON_MISSILE:
  1462. case NUKE_SPECIAL_NEUTRON_MISSILE:
  1463. case SUPW_SPECIAL_NEUTRON_MISSILE:
  1464. case SPECIAL_DETONATE_DIRTY_NUKE:
  1465. case SPECIAL_BLACK_MARKET_NUKE:
  1466. case SPECIAL_ANTHRAX_BOMB:
  1467. case SPECIAL_SPY_SATELLITE:
  1468. case SPECIAL_SPY_DRONE:
  1469. case SPECIAL_RADAR_VAN_SCAN:
  1470. case SPECIAL_SCUD_STORM:
  1471. case SPECIAL_A10_THUNDERBOLT_STRIKE:
  1472. case AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
  1473. case SPECIAL_SPECTRE_GUNSHIP:
  1474. case AIRF_SPECIAL_SPECTRE_GUNSHIP:
  1475. case SPECIAL_ARTILLERY_BARRAGE:
  1476. case SPECIAL_FRENZY:
  1477. case EARLY_SPECIAL_FRENZY:
  1478. case SPECIAL_REPAIR_VEHICLES:
  1479. case EARLY_SPECIAL_REPAIR_VEHICLES:
  1480. case SPECIAL_GPS_SCRAMBLER:
  1481. case SLTH_SPECIAL_GPS_SCRAMBLER:
  1482. case SPECIAL_PARTICLE_UPLINK_CANNON:
  1483. case SPECIAL_CHANGE_BATTLE_PLANS:
  1484. case SPECIAL_CLEANUP_AREA:
  1485. case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
  1486. case SPECIAL_SNEAK_ATTACK:
  1487. return false;
  1488. case SPECIAL_REMOTE_CHARGES:
  1489. case SPECIAL_TIMED_CHARGES:
  1490. case SPECIAL_HELIX_NAPALM_BOMB:
  1491. {
  1492. if( target->isEffectivelyDead() ||
  1493. target->isKindOf( KINDOF_BRIDGE ) ||
  1494. target->isKindOf( KINDOF_BRIDGE_TOWER ) )
  1495. return FALSE;
  1496. if( target->isKindOf( KINDOF_STRUCTURE ) || target->isKindOf( KINDOF_VEHICLE ) )
  1497. {
  1498. SpecialAbilityUpdate *spUpdate = obj->findSpecialAbilityUpdate( spTemplate->getSpecialPowerType() );
  1499. if( spUpdate )
  1500. {
  1501. //Make sure we have enough equipment to place an additional charge.
  1502. if( spUpdate->getSpecialObjectCount() < spUpdate->getSpecialObjectMax() )
  1503. {
  1504. //Also restrict the unit from placing more than one charge on the same building.
  1505. //We accomplish this by having the stickybomb update store the target as the producer ID.
  1506. if( spUpdate->findSpecialObjectWithProducerID( target ) )
  1507. {
  1508. return false;
  1509. }
  1510. //HERE'S THE TOUGH CASE...
  1511. //We also don't want to allow a unit that can place timed charges on a building to be able to place
  1512. //remote charges (or vice-versa). So we're going to look for the other special ability update and
  1513. //reject if the other one has it planted...
  1514. if( spTemplate->getSpecialPowerType() == SPECIAL_REMOTE_CHARGES )
  1515. {
  1516. spUpdate = obj->findSpecialAbilityUpdate( SPECIAL_TIMED_CHARGES );
  1517. }
  1518. else if( spTemplate->getSpecialPowerType() == SPECIAL_TIMED_CHARGES )
  1519. {
  1520. spUpdate = obj->findSpecialAbilityUpdate( SPECIAL_REMOTE_CHARGES );
  1521. }
  1522. //If we have a valid pointer at this point, we found the other special. Make sure it
  1523. //isn't planted on the same target.
  1524. if( spUpdate && spUpdate->findSpecialObjectWithProducerID( target ) )
  1525. {
  1526. return false;
  1527. }
  1528. return true;
  1529. }
  1530. }
  1531. }
  1532. break;
  1533. }
  1534. }
  1535. }
  1536. return false;
  1537. }
  1538. // ------------------------------------------------------------------------------------------------
  1539. // ------------------------------------------------------------------------------------------------
  1540. Bool ActionManager::canDoSpecialPower( const Object *obj, const SpecialPowerTemplate *spTemplate, CommandSourceType commandSource, UnsignedInt commandOptions, Bool checkSourceRequirements )
  1541. {
  1542. if (checkSourceRequirements)
  1543. {
  1544. //First check, if our object can do this special power.
  1545. if( !obj->hasSpecialPower( spTemplate->getSpecialPowerType() ) )
  1546. {
  1547. return false;
  1548. }
  1549. }
  1550. SpecialPowerModuleInterface *mod = obj->getSpecialPowerModule( spTemplate );
  1551. if( mod )
  1552. {
  1553. if (checkSourceRequirements)
  1554. {
  1555. if( mod->getPercentReady() < 1.0f )
  1556. {
  1557. //Not fully ready
  1558. return false;
  1559. }
  1560. }
  1561. switch( spTemplate->getSpecialPowerType() )
  1562. {
  1563. case SPECIAL_MISSILE_DEFENDER_LASER_GUIDED_MISSILES:
  1564. case SPECIAL_TANKHUNTER_TNT_ATTACK:
  1565. case SPECIAL_BOOBY_TRAP:
  1566. case SPECIAL_DAISY_CUTTER:
  1567. case AIRF_SPECIAL_DAISY_CUTTER:
  1568. case SPECIAL_PARADROP_AMERICA:
  1569. case SPECIAL_TANK_PARADROP:
  1570. case INFA_SPECIAL_PARADROP_AMERICA:
  1571. case SPECIAL_CARPET_BOMB:
  1572. case SPECIAL_CHINA_CARPET_BOMB:
  1573. case SPECIAL_LEAFLET_DROP:
  1574. case EARLY_SPECIAL_LEAFLET_DROP:
  1575. case EARLY_SPECIAL_CHINA_CARPET_BOMB:
  1576. case AIRF_SPECIAL_CARPET_BOMB:
  1577. case SUPR_SPECIAL_CRUISE_MISSILE:
  1578. case SPECIAL_CLUSTER_MINES:
  1579. case NUKE_SPECIAL_CLUSTER_MINES:
  1580. case SPECIAL_NAPALM_STRIKE:
  1581. case SPECIAL_TERROR_CELL:
  1582. case SPECIAL_NEUTRON_MISSILE:
  1583. case NUKE_SPECIAL_NEUTRON_MISSILE:
  1584. case SUPW_SPECIAL_NEUTRON_MISSILE:
  1585. case SPECIAL_BLACK_MARKET_NUKE:
  1586. case SPECIAL_ANTHRAX_BOMB:
  1587. case SPECIAL_SPY_SATELLITE:
  1588. case SPECIAL_SPY_DRONE:
  1589. case SPECIAL_RADAR_VAN_SCAN:
  1590. case SPECIAL_TIMED_CHARGES:
  1591. case SPECIAL_SCUD_STORM:
  1592. case SPECIAL_A10_THUNDERBOLT_STRIKE:
  1593. case AIRF_SPECIAL_A10_THUNDERBOLT_STRIKE:
  1594. case SPECIAL_SPECTRE_GUNSHIP:
  1595. case AIRF_SPECIAL_SPECTRE_GUNSHIP:
  1596. case SPECIAL_ARTILLERY_BARRAGE:
  1597. case SPECIAL_FRENZY:
  1598. case EARLY_SPECIAL_FRENZY:
  1599. case SPECIAL_DISGUISE_AS_VEHICLE:
  1600. case SPECIAL_REPAIR_VEHICLES:
  1601. case EARLY_SPECIAL_REPAIR_VEHICLES:
  1602. case SPECIAL_GPS_SCRAMBLER:
  1603. case SLTH_SPECIAL_GPS_SCRAMBLER:
  1604. case SPECIAL_PARTICLE_UPLINK_CANNON:
  1605. case SPECIAL_CASH_BOUNTY:
  1606. case SPECIAL_CLEANUP_AREA:
  1607. case SPECIAL_HELIX_NAPALM_BOMB:
  1608. case SPECIAL_SNEAK_ATTACK:
  1609. case SPECIAL_EMP_PULSE:
  1610. case SPECIAL_CASH_HACK:
  1611. //These all require object or location targets.
  1612. return false;
  1613. case SPECIAL_REMOTE_CHARGES:
  1614. case SPECIAL_CIA_INTELLIGENCE:
  1615. case SPECIAL_COMMUNICATIONS_DOWNLOAD:
  1616. case SPECIAL_DETONATE_DIRTY_NUKE:
  1617. case SPECIAL_CHANGE_BATTLE_PLANS:
  1618. case SPECIAL_LAUNCH_BAIKONUR_ROCKET:
  1619. //Detonate's any existing charges
  1620. return true;
  1621. }
  1622. }
  1623. return false;
  1624. }
  1625. //------------------------------------------------------------------------------------------------
  1626. Bool ActionManager::canFireWeaponAtLocation( const Object *obj, const Coord3D *loc, CommandSourceType commandSource, const WeaponSlotType slot, const Object *objectInWay )
  1627. {
  1628. //Sanity check
  1629. if( obj == NULL || loc == NULL )
  1630. {
  1631. return false;
  1632. }
  1633. //Make sure we have the right weapon.
  1634. Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
  1635. if( !weapon )
  1636. {
  1637. return false;
  1638. }
  1639. return true;
  1640. }
  1641. //------------------------------------------------------------------------------------------------
  1642. Bool ActionManager::canFireWeaponAtObject( const Object *obj, const Object *target, CommandSourceType commandSource, const WeaponSlotType slot )
  1643. {
  1644. //Sanity check
  1645. if( obj == NULL || target == NULL )
  1646. {
  1647. return FALSE;
  1648. }
  1649. //Make sure we have the right weapon.
  1650. Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
  1651. if( !weapon )
  1652. {
  1653. return FALSE;
  1654. }
  1655. Bool sniper = FALSE;
  1656. if( weapon->getDamageType() == DAMAGE_KILLPILOT )
  1657. {
  1658. if( !canSnipeVehicle( obj, target, commandSource ) )
  1659. {
  1660. return FALSE;
  1661. }
  1662. sniper = TRUE;
  1663. }
  1664. CanAttackResult result;
  1665. if( sniper )
  1666. result = obj->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET, target, commandSource, slot );
  1667. else
  1668. result = obj->getAbleToAttackSpecificObject( ATTACK_NEW_TARGET, target, commandSource );
  1669. if( result == ATTACKRESULT_POSSIBLE || result == ATTACKRESULT_POSSIBLE_AFTER_MOVING )
  1670. {
  1671. return weapon->estimateWeaponDamage( obj, target ) != 0.0f;
  1672. }
  1673. return FALSE;
  1674. }
  1675. //------------------------------------------------------------------------------------------------
  1676. Bool ActionManager::canFireWeapon( const Object *obj, const WeaponSlotType slot, CommandSourceType commandSource )
  1677. {
  1678. //Sanity check
  1679. if( obj == NULL )
  1680. {
  1681. return false;
  1682. }
  1683. //Make sure we have the right weapon.
  1684. Weapon *weapon = obj->getWeaponInWeaponSlot( slot );
  1685. if( !weapon )
  1686. {
  1687. return false;
  1688. }
  1689. return true;
  1690. }
  1691. //------------------------------------------------------------------------------------------------
  1692. Bool ActionManager::canGarrison( const Object *obj, const Object *target, CommandSourceType commandSource )
  1693. {
  1694. if (!(obj && target))
  1695. return false;
  1696. // The object was not an infantry, or is disallowed from being allowed to garrison stuff.
  1697. if (obj->isKindOf(KINDOF_INFANTRY) == false || obj->isKindOf(KINDOF_NO_GARRISON))
  1698. return false;
  1699. if (target->isKindOf(KINDOF_STRUCTURE) == false)
  1700. return false;
  1701. ContainModuleInterface *objCMI = obj->getContain();
  1702. if (!objCMI)
  1703. return false;
  1704. ContainModuleInterface *cmi = target->getContain();
  1705. if (cmi == NULL)
  1706. return false;
  1707. if (cmi->isGarrisonable() == false)
  1708. return false;
  1709. if (obj->getControllingPlayer() == target->getControllingPlayer())
  1710. {
  1711. return cmi->isValidContainerFor(obj, true);
  1712. }
  1713. if (obj->getControllingPlayer()->getRelationship(target->getTeam()) == NEUTRAL)
  1714. {
  1715. // needs to be empty if its not already ours.
  1716. return (cmi->getContainCount() == 0 && cmi->isValidContainerFor(obj, true));
  1717. }
  1718. return false;
  1719. }
  1720. //------------------------------------------------------------------------------------------------
  1721. Bool ActionManager::canPlayerGarrison( const Player *player, const Object *target, CommandSourceType commandSource )
  1722. {
  1723. if (!(player && target))
  1724. return false;
  1725. if (target->isEffectivelyDead()) {
  1726. return false;
  1727. }
  1728. if (target->isKindOf(KINDOF_STRUCTURE) == false)
  1729. return false;
  1730. ContainModuleInterface *cmi = target->getContain();
  1731. if (cmi == NULL)
  1732. return false;
  1733. if (cmi->isGarrisonable() == false)
  1734. return false;
  1735. if (player == target->getControllingPlayer())
  1736. {
  1737. return true;
  1738. }
  1739. if (player->getRelationship(target->getTeam()) == NEUTRAL)
  1740. {
  1741. // needs to be empty if its not already ours.
  1742. return cmi->getContainCount() == 0;
  1743. }
  1744. return false;
  1745. }
  1746. //------------------------------------------------------------------------------------------------
  1747. Bool ActionManager::canOverrideSpecialPowerDestination( const Object *obj, const Coord3D *loc, SpecialPowerType spType, CommandSourceType commandSource )
  1748. {
  1749. SpecialPowerUpdateInterface* spuInterface = obj->findSpecialPowerWithOverridableDestinationActive( spType );
  1750. if( spuInterface )
  1751. {
  1752. //But so long as it's not in the black areas of the map.
  1753. return ThePartitionManager->getShroudStatusForPlayer( obj->getControllingPlayer()->getPlayerIndex(), loc ) != CELLSHROUD_SHROUDED;
  1754. }
  1755. return false;
  1756. }