Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

788 lines
21 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "ai_network.h"
  9. #include "ai_default.h"
  10. #include "ai_schedule.h"
  11. #include "ai_hull.h"
  12. #include "ai_node.h"
  13. #include "ai_task.h"
  14. #include "ai_senses.h"
  15. #include "ai_navigator.h"
  16. #include "ai_route.h"
  17. #include "entitylist.h"
  18. #include "soundenvelope.h"
  19. #include "gamerules.h"
  20. #include "ndebugoverlay.h"
  21. #include "soundflags.h"
  22. #include "trains.h"
  23. #include "globalstate.h"
  24. #include "vehicle_base.h"
  25. #include "npc_vehicledriver.h"
  26. #include "vehicle_crane.h"
  27. #include "saverestore_utlvector.h"
  28. // memdbgon must be the last include file in a .cpp file!!!
  29. #include "tier0/memdbgon.h"
  30. extern ConVar g_debug_vehicledriver;
  31. //=========================================================
  32. // Custom schedules
  33. //=========================================================
  34. enum
  35. {
  36. SCHED_CRANE_RANGE_ATTACK1 = LAST_VEHICLEDRIVER_SCHED,
  37. SCHED_CRANE_FIND_LARGE_OBJECT,
  38. SCHED_CRANE_PICKUP_OBJECT,
  39. SCHED_CRANE_FORCED_GO,
  40. SCHED_CRANE_CHASE_ENEMY,
  41. SCHED_CRANE_FORCED_DROP,
  42. };
  43. //=========================================================
  44. // Custom tasks
  45. //=========================================================
  46. enum
  47. {
  48. TASK_CRANE_GET_POSITION_OVER_ENEMY = LAST_VEHICLEDRIVER_TASK,
  49. TASK_CRANE_GET_POSITION_OVER_LASTPOSITION,
  50. TASK_CRANE_GET_POSITION_OVER_OBJECT,
  51. TASK_CRANE_TURN_MAGNET_OFF,
  52. TASK_CRANE_FIND_OBJECT_TO_PICKUP,
  53. TASK_CRANE_DROP_MAGNET,
  54. TASK_END_FORCED_DROP,
  55. };
  56. //-----------------------------------------------------------------------------
  57. // Purpose:
  58. //-----------------------------------------------------------------------------
  59. class CNPC_CraneDriver : public CNPC_VehicleDriver
  60. {
  61. DECLARE_CLASS( CNPC_CraneDriver, CNPC_VehicleDriver );
  62. public:
  63. DECLARE_DATADESC();
  64. DEFINE_CUSTOM_AI;
  65. void Spawn( void );
  66. void Activate( void );
  67. // AI
  68. int RangeAttack1Conditions( float flDot, float flDist );
  69. int TranslateSchedule( int scheduleType );
  70. int SelectSchedule( void );
  71. void StartTask( const Task_t *pTask );
  72. void RunTask( const Task_t *pTask );
  73. void SetDesiredPosition( const Vector &vecPosition );
  74. // Driving
  75. void DriveVehicle( void );
  76. bool OverrideMove( float flInterval );
  77. // Inputs
  78. void InputForcePickup( inputdata_t &inputdata );
  79. void InputForceDrop( inputdata_t &inputdata );
  80. protected:
  81. CHandle<CPropCrane> m_hCrane;
  82. EHANDLE m_hPickupTarget;
  83. float m_flDistanceToTarget;
  84. CUtlVector< EHANDLE > m_PreviouslyPickedUpObjects;
  85. bool m_bForcedPickup;
  86. bool m_bForcedDropoff;
  87. float m_flDropWait;
  88. float m_flReleasePause;
  89. float m_flReleaseAt;
  90. // Outputs
  91. COutputEvent m_OnPickedUpObject;
  92. COutputEvent m_OnDroppedObject;
  93. COutputEvent m_OnPausingBeforeDrop;
  94. };
  95. BEGIN_DATADESC( CNPC_CraneDriver )
  96. // Inputs
  97. DEFINE_INPUTFUNC( FIELD_STRING, "ForcePickup", InputForcePickup ),
  98. DEFINE_INPUTFUNC( FIELD_STRING, "ForceDrop", InputForceDrop ),
  99. //DEFINE_FIELD( m_hCrane, FIELD_EHANDLE ),
  100. DEFINE_FIELD( m_hPickupTarget, FIELD_EHANDLE ),
  101. DEFINE_FIELD( m_flDistanceToTarget, FIELD_FLOAT ),
  102. DEFINE_UTLVECTOR( m_PreviouslyPickedUpObjects, FIELD_EHANDLE ),
  103. DEFINE_FIELD( m_bForcedPickup, FIELD_BOOLEAN ),
  104. DEFINE_FIELD( m_bForcedDropoff, FIELD_BOOLEAN ),
  105. DEFINE_FIELD( m_flDropWait, FIELD_FLOAT ),
  106. DEFINE_KEYFIELD( m_flReleasePause, FIELD_FLOAT, "releasepause" ),
  107. DEFINE_FIELD( m_flReleaseAt, FIELD_FLOAT ),
  108. // Outputs
  109. DEFINE_OUTPUT( m_OnPickedUpObject, "OnPickedUpObject" ),
  110. DEFINE_OUTPUT( m_OnDroppedObject, "OnDroppedObject" ),
  111. DEFINE_OUTPUT( m_OnPausingBeforeDrop, "OnPausingBeforeDrop" ),
  112. END_DATADESC()
  113. LINK_ENTITY_TO_CLASS( npc_cranedriver, CNPC_CraneDriver );
  114. //------------------------------------------------------------------------------
  115. // Purpose :
  116. //------------------------------------------------------------------------------
  117. void CNPC_CraneDriver::Spawn( void )
  118. {
  119. BaseClass::Spawn();
  120. CapabilitiesClear();
  121. CapabilitiesAdd( bits_CAP_INNATE_RANGE_ATTACK1 );
  122. m_flDistTooFar = 2048.0;
  123. SetDistLook( 2048 );
  124. m_PreviouslyPickedUpObjects.Purge();
  125. m_hPickupTarget = NULL;
  126. m_bForcedPickup = false;
  127. m_bForcedDropoff = false;
  128. }
  129. //-----------------------------------------------------------------------------
  130. // Purpose:
  131. //-----------------------------------------------------------------------------
  132. void CNPC_CraneDriver::Activate( void )
  133. {
  134. BaseClass::Activate();
  135. m_hCrane = dynamic_cast<CPropCrane*>((CBaseEntity*)m_hVehicleEntity);
  136. if ( !m_hCrane )
  137. {
  138. Warning( "npc_cranedriver %s couldn't find his crane named %s.\n", STRING(GetEntityName()), STRING(m_iszVehicleName) );
  139. UTIL_Remove( this );
  140. return;
  141. }
  142. }
  143. //-----------------------------------------------------------------------------
  144. // Purpose:
  145. // Input :
  146. // Output :
  147. //-----------------------------------------------------------------------------
  148. int CNPC_CraneDriver::RangeAttack1Conditions( float flDot, float flDist )
  149. {
  150. if ( !HasCondition( COND_SEE_ENEMY ) )
  151. return COND_NONE;
  152. // Do our distance check in 2D
  153. Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );
  154. Vector2D vecEnemy2D( GetEnemy()->GetAbsOrigin().x, GetEnemy()->GetAbsOrigin().y );
  155. flDist = (vecOrigin2D - vecEnemy2D).Length();
  156. // Maximum & Minimum size of the crane's reach
  157. if ( flDist > MAX_CRANE_FLAT_REACH )
  158. return COND_TOO_FAR_TO_ATTACK;
  159. // Crane can't reach any closer than this
  160. if ( flDist < MIN_CRANE_FLAT_REACH )
  161. return COND_TOO_CLOSE_TO_ATTACK;
  162. return COND_CAN_RANGE_ATTACK1;
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose:
  166. //-----------------------------------------------------------------------------
  167. int CNPC_CraneDriver::SelectSchedule( void )
  168. {
  169. if ( HasSpawnFlags(SF_VEHICLEDRIVER_INACTIVE) )
  170. return BaseClass::SelectSchedule();
  171. // If we've got an object to pickup, so go get it
  172. if ( m_hPickupTarget )
  173. {
  174. // Only clear the pickup target if we managed to pick something up
  175. if ( m_hCrane->GetTotalMassOnCrane() > 0 )
  176. {
  177. if ( m_bForcedPickup )
  178. {
  179. m_OnPickedUpObject.FireOutput( m_hPickupTarget, this );
  180. }
  181. // Remember what we dropped so we go try something else if we can.
  182. m_PreviouslyPickedUpObjects.AddToTail( m_hPickupTarget );
  183. m_hPickupTarget = NULL;
  184. }
  185. else
  186. {
  187. if ( m_NPCState == NPC_STATE_IDLE )
  188. {
  189. SetIdealState( NPC_STATE_ALERT );
  190. }
  191. return SCHED_CRANE_PICKUP_OBJECT;
  192. }
  193. }
  194. // If we're currently being forced to pickup something, do only that
  195. if ( m_bForcedPickup )
  196. {
  197. if ( m_hPickupTarget )
  198. return SCHED_CRANE_PICKUP_OBJECT;
  199. // We've picked up our target, we're waiting to be told where to put it
  200. return SCHED_IDLE_STAND;
  201. }
  202. // If we've been told to drop something off, do that
  203. if ( m_bForcedDropoff )
  204. return SCHED_CRANE_FORCED_DROP;
  205. switch ( m_NPCState )
  206. {
  207. case NPC_STATE_IDLE:
  208. break;
  209. case NPC_STATE_ALERT:
  210. break;
  211. case NPC_STATE_COMBAT:
  212. if ( HasCondition( COND_CAN_RANGE_ATTACK1 ) )
  213. {
  214. // Do we have anything on the crane? If not, look for something
  215. if ( m_hCrane->GetTotalMassOnCrane() == 0 )
  216. return SCHED_CRANE_FIND_LARGE_OBJECT;
  217. // We've got something on the crane, so try and drop it on the enemy
  218. return SCHED_CRANE_RANGE_ATTACK1;
  219. }
  220. // We can't attack him, so if we don't have anything on the crane, grab something
  221. if ( m_hCrane->GetTotalMassOnCrane() == 0 )
  222. return SCHED_CRANE_FIND_LARGE_OBJECT;
  223. }
  224. return BaseClass::SelectSchedule();
  225. }
  226. //-----------------------------------------------------------------------------
  227. // Purpose:
  228. //-----------------------------------------------------------------------------
  229. int CNPC_CraneDriver::TranslateSchedule( int scheduleType )
  230. {
  231. switch ( scheduleType )
  232. {
  233. case SCHED_COMBAT_FACE:
  234. // Vehicles can't rotate, so don't try and face
  235. return TranslateSchedule( SCHED_CHASE_ENEMY );
  236. case SCHED_ALERT_FACE:
  237. // Vehicles can't rotate, so don't try and face
  238. return SCHED_ALERT_STAND;
  239. case SCHED_FORCED_GO:
  240. return SCHED_CRANE_FORCED_GO;
  241. case SCHED_CHASE_ENEMY:
  242. return SCHED_CRANE_CHASE_ENEMY;
  243. }
  244. return BaseClass::TranslateSchedule(scheduleType);
  245. }
  246. //-----------------------------------------------------------------------------
  247. // Purpose:
  248. // Input : *pTask -
  249. //-----------------------------------------------------------------------------
  250. void CNPC_CraneDriver::StartTask( const Task_t *pTask )
  251. {
  252. switch( pTask->iTask )
  253. {
  254. case TASK_WAIT_FOR_MOVEMENT:
  255. break;
  256. case TASK_CRANE_GET_POSITION_OVER_ENEMY:
  257. {
  258. if ( !GetEnemy() )
  259. {
  260. TaskFail(FAIL_NO_ROUTE);
  261. return;
  262. }
  263. SetDesiredPosition( GetEnemy()->GetAbsOrigin() );
  264. TaskComplete();
  265. }
  266. break;
  267. case TASK_CRANE_GET_POSITION_OVER_OBJECT:
  268. {
  269. if ( !m_hPickupTarget )
  270. {
  271. TaskFail("No object to pickup!");
  272. return;
  273. }
  274. SetDesiredPosition( m_hPickupTarget->GetAbsOrigin() );
  275. TaskComplete();
  276. }
  277. break;
  278. case TASK_CRANE_GET_POSITION_OVER_LASTPOSITION:
  279. {
  280. SetDesiredPosition( m_vecLastPosition );
  281. TaskComplete();
  282. }
  283. break;
  284. case TASK_CRANE_TURN_MAGNET_OFF:
  285. {
  286. // If we picked up something, and we were being forced to pick something up, fire our output
  287. if ( m_hCrane->GetTotalMassOnCrane() > 0 && m_bForcedDropoff )
  288. {
  289. // Are we supposed to pause first?
  290. if ( m_flReleasePause )
  291. {
  292. m_flReleaseAt = gpGlobals->curtime + m_flReleasePause;
  293. m_OnPausingBeforeDrop.FireOutput( this, this );
  294. return;
  295. }
  296. m_OnDroppedObject.FireOutput( this, this );
  297. }
  298. m_hCrane->TurnMagnetOff();
  299. TaskComplete();
  300. }
  301. break;
  302. case TASK_END_FORCED_DROP:
  303. {
  304. m_bForcedDropoff = false;
  305. TaskComplete();
  306. }
  307. break;
  308. case TASK_CRANE_FIND_OBJECT_TO_PICKUP:
  309. {
  310. Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );
  311. // Find a large physics object within our reach to pickup
  312. float flLargestMass = 0;
  313. CBaseEntity *pLargestEntity = NULL;
  314. CBaseEntity *pList[1024];
  315. Vector delta( m_flDistTooFar, m_flDistTooFar, m_flDistTooFar*2 );
  316. int count = UTIL_EntitiesInBox( pList, 1024, m_hCrane->GetAbsOrigin() - delta, m_hCrane->GetAbsOrigin() + delta, 0 );
  317. for ( int i = 0; i < count; i++ )
  318. {
  319. if ( !pList[i] )
  320. continue;
  321. // Ignore the crane & the magnet
  322. if ( pList[i] == m_hCrane || pList[i] == m_hCrane->GetMagnet() )
  323. continue;
  324. if ( m_PreviouslyPickedUpObjects.Find( pList[i] ) != m_PreviouslyPickedUpObjects.InvalidIndex() )
  325. continue;
  326. // Get the VPhysics object
  327. IPhysicsObject *pPhysics = pList[i]->VPhysicsGetObject();
  328. if ( pPhysics && pList[i]->GetMoveType() == MOVETYPE_VPHYSICS )
  329. {
  330. float flMass = pPhysics->GetMass();
  331. if ( flMass > flLargestMass && (flMass < MAXIMUM_CRANE_PICKUP_MASS) && (flMass > MINIMUM_CRANE_PICKUP_MASS) )
  332. {
  333. // Biggest one we've found so far
  334. // Now make sure it's within our reach
  335. // Do our distance check in 2D
  336. Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );
  337. Vector2D vecEnemy2D( pList[i]->GetAbsOrigin().x, pList[i]->GetAbsOrigin().y );
  338. float flDist = (vecOrigin2D - vecEnemy2D).Length();
  339. // Maximum & Minimum size of the crane's reach
  340. if ( flDist > MAX_CRANE_FLAT_REACH )
  341. continue;
  342. if ( flDist < MIN_CRANE_FLAT_REACH )
  343. continue;
  344. flLargestMass = flMass;
  345. pLargestEntity = pList[i];
  346. }
  347. }
  348. }
  349. // If we didn't find anything new, clear our list of targets
  350. if ( !pLargestEntity )
  351. {
  352. m_PreviouslyPickedUpObjects.Purge();
  353. }
  354. if ( !pLargestEntity )
  355. {
  356. TaskFail("Couldn't find anything to pick up!");
  357. return;
  358. }
  359. m_hPickupTarget = pLargestEntity;
  360. TaskComplete();
  361. }
  362. break;
  363. case TASK_CRANE_DROP_MAGNET:
  364. {
  365. // Drop the magnet, but only end the task once the magnet's back up
  366. m_pVehicleInterface->NPC_SecondaryFire();
  367. // Don't check to see if drop's finished until this time is up.
  368. // This is necessary because the crane won't start dropping this
  369. // frame, and our cranedriver will think it's finished immediately.
  370. m_flDropWait = gpGlobals->curtime + 0.5;
  371. }
  372. break;
  373. default:
  374. BaseClass::StartTask( pTask );
  375. break;
  376. }
  377. }
  378. //-----------------------------------------------------------------------------
  379. // Purpose:
  380. //-----------------------------------------------------------------------------
  381. void CNPC_CraneDriver::RunTask( const Task_t *pTask )
  382. {
  383. switch( pTask->iTask )
  384. {
  385. case TASK_WAIT_FOR_MOVEMENT:
  386. {
  387. // Is the magnet over the target, and are we not moving too fast?
  388. AngularImpulse angVel;
  389. Vector vecVelocity;
  390. CBaseEntity *pMagnet = m_hCrane->GetMagnet();
  391. IPhysicsObject *pVehiclePhysics = pMagnet->VPhysicsGetObject();
  392. pVehiclePhysics->GetVelocity( &vecVelocity, &angVel );
  393. float flVelocity = 100;
  394. float flDistance = 90;
  395. // More accurate on forced drops
  396. if ( m_bForcedPickup || m_bForcedDropoff )
  397. {
  398. flVelocity = 10;
  399. flDistance = 30;
  400. }
  401. if ( m_flDistanceToTarget < flDistance && m_hCrane->GetTurnRate() < 0.1 && vecVelocity.Length() < flVelocity )
  402. {
  403. TaskComplete();
  404. }
  405. }
  406. break;
  407. case TASK_CRANE_DROP_MAGNET:
  408. {
  409. // Wait for the magnet to get back up
  410. if ( m_flDropWait < gpGlobals->curtime && !m_hCrane->IsDropping() )
  411. {
  412. TaskComplete();
  413. }
  414. }
  415. break;
  416. case TASK_CRANE_TURN_MAGNET_OFF:
  417. {
  418. // We're waiting for the pause length before dropping whatever's on our magnet
  419. if ( gpGlobals->curtime > m_flReleaseAt )
  420. {
  421. if ( m_bForcedDropoff )
  422. {
  423. m_OnDroppedObject.FireOutput( this, this );
  424. }
  425. m_hCrane->TurnMagnetOff();
  426. TaskComplete();
  427. }
  428. }
  429. break;
  430. default:
  431. BaseClass::RunTask( pTask );
  432. break;
  433. }
  434. }
  435. //-----------------------------------------------------------------------------
  436. // Purpose:
  437. //-----------------------------------------------------------------------------
  438. bool CNPC_CraneDriver::OverrideMove( float flInterval )
  439. {
  440. return true;
  441. }
  442. //-----------------------------------------------------------------------------
  443. // Purpose:
  444. //-----------------------------------------------------------------------------
  445. void CNPC_CraneDriver::SetDesiredPosition( const Vector &vecPosition )
  446. {
  447. m_vecDesiredPosition = vecPosition;
  448. m_flDistanceToTarget = 999;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose: This takes the current place the NPC's trying to get to, figures out
  452. // what keys to press to get the vehicle to go there, and then sends
  453. // them to the vehicle.
  454. //-----------------------------------------------------------------------------
  455. void CNPC_CraneDriver::DriveVehicle( void )
  456. {
  457. // No targets?
  458. if ( !GetEnemy() && m_vecDesiredPosition == vec3_origin )
  459. return;
  460. Vector vecTarget = m_vecDesiredPosition;
  461. // Track our targets
  462. if ( m_hPickupTarget )
  463. {
  464. vecTarget = m_hPickupTarget->GetAbsOrigin();
  465. }
  466. else if ( !m_bForcedPickup && !m_bForcedDropoff && GetEnemy() )
  467. {
  468. vecTarget = GetEnemy()->GetAbsOrigin();
  469. }
  470. // Move the crane over the target
  471. // Use the crane type as a targeting point
  472. Vector vecCraneTip = m_hCrane->GetCraneTipPosition();
  473. Vector2D vecCraneTip2D( vecCraneTip.x, vecCraneTip.y );
  474. Vector2D vecTarget2D( vecTarget.x, vecTarget.y );
  475. Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );
  476. if ( g_debug_vehicledriver.GetInt() )
  477. {
  478. NDebugOverlay::Box( vecTarget, -Vector(50,50,50), Vector(50,50,50), 0,255,0, true, 0.1 );
  479. NDebugOverlay::Box( vecCraneTip, -Vector(2,2,5000), Vector(2,2,5), 0,255,0, true, 0.1 );
  480. NDebugOverlay::Box( vecTarget, -Vector(2,2,5), Vector(2,2,5000), 0,255,0, true, 0.1 );
  481. }
  482. // Store off the distance to our target
  483. m_flDistanceToTarget = (vecTarget2D - vecCraneTip2D).Length();
  484. // First determine whether we need to extend / retract the arm
  485. float flDistToTarget = (vecOrigin2D - vecTarget2D).LengthSqr();
  486. float flDistToCurrent = (vecOrigin2D - vecCraneTip2D).LengthSqr();
  487. float flDelta = fabs(flDistToTarget - flDistToCurrent);
  488. // Slow down as we get closer, but do it based upon our current extension rate
  489. float flMinDelta = 50 + (50 * fabs(m_hCrane->GetExtensionRate() / CRANE_EXTENSION_RATE_MAX));
  490. flMinDelta *= flMinDelta;
  491. if ( flDelta > flMinDelta )
  492. {
  493. if ( flDistToCurrent > flDistToTarget )
  494. {
  495. // Retract
  496. m_pVehicleInterface->NPC_ThrottleReverse();
  497. }
  498. else if ( flDistToCurrent < flDistToTarget )
  499. {
  500. // Extend
  501. m_pVehicleInterface->NPC_ThrottleForward();
  502. }
  503. }
  504. else
  505. {
  506. m_pVehicleInterface->NPC_ThrottleCenter();
  507. }
  508. // Then figure out if we need to rotate. Do it all in 2D space.
  509. Vector vecRight, vecForward;
  510. m_hCrane->GetVectors( &vecForward, &vecRight, NULL );
  511. vecRight.z = 0;
  512. vecForward.z = 0;
  513. VectorNormalize( vecRight );
  514. VectorNormalize( vecForward );
  515. Vector vecToTarget = ( vecTarget - m_hCrane->GetAbsOrigin() );
  516. vecToTarget.z = 0;
  517. VectorNormalize( vecToTarget );
  518. float flDotRight = DotProduct( vecRight, vecToTarget );
  519. float flDotForward = DotProduct( vecForward, vecToTarget );
  520. // Start slowing if we're going to hit the point soon
  521. float flTurnInDeg = RAD2DEG( acos(flDotForward) );
  522. float flSpeed = m_hCrane->GetMaxTurnRate() * (flTurnInDeg / 15.0);
  523. flSpeed = MIN( m_hCrane->GetMaxTurnRate(), flSpeed );
  524. if ( fabs(flSpeed) < 0.05 )
  525. {
  526. // We're approaching the target, so stop turning
  527. m_pVehicleInterface->NPC_TurnCenter();
  528. }
  529. else
  530. {
  531. if ( flDotRight < 0 )
  532. {
  533. // Turn right
  534. m_pVehicleInterface->NPC_TurnRight( flSpeed );
  535. }
  536. else if ( flDotRight > 0 )
  537. {
  538. // Turn left
  539. m_pVehicleInterface->NPC_TurnLeft( flSpeed );
  540. }
  541. }
  542. }
  543. //-----------------------------------------------------------------------------
  544. // Purpose: Force the driver to pickup a specific entity
  545. // Input : &inputdata -
  546. //-----------------------------------------------------------------------------
  547. void CNPC_CraneDriver::InputForcePickup( inputdata_t &inputdata )
  548. {
  549. string_t iszPickupName = inputdata.value.StringID();
  550. if ( iszPickupName != NULL_STRING )
  551. {
  552. // Turn the magnet off now to drop anything we might have already on the magnet
  553. m_hCrane->TurnMagnetOff();
  554. m_hPickupTarget = gEntList.FindEntityByName( NULL, iszPickupName, NULL, inputdata.pActivator, inputdata.pCaller );
  555. m_bForcedPickup = true;
  556. m_bForcedDropoff = false;
  557. SetCondition( COND_PROVOKED );
  558. CLEARBITS( m_spawnflags, SF_VEHICLEDRIVER_INACTIVE );
  559. }
  560. }
  561. //-----------------------------------------------------------------------------
  562. // Purpose: Force the driver to drop his held entity at a specific point
  563. // Input : &inputdata -
  564. //-----------------------------------------------------------------------------
  565. void CNPC_CraneDriver::InputForceDrop( inputdata_t &inputdata )
  566. {
  567. string_t iszDropName = inputdata.value.StringID();
  568. if ( iszDropName != NULL_STRING )
  569. {
  570. CBaseEntity *pEntity = gEntList.FindEntityByName( NULL, iszDropName, NULL, inputdata.pActivator, inputdata.pCaller );
  571. if ( !pEntity )
  572. {
  573. Warning("Crane couldn't find entity named %s\n", STRING(iszDropName) );
  574. return;
  575. }
  576. m_bForcedPickup = false;
  577. m_bForcedDropoff = true;
  578. SetDesiredPosition( pEntity->GetAbsOrigin() );
  579. SetCondition( COND_PROVOKED );
  580. CLEARBITS( m_spawnflags, SF_VEHICLEDRIVER_INACTIVE );
  581. }
  582. }
  583. //-----------------------------------------------------------------------------
  584. //
  585. // Schedules
  586. //
  587. //-----------------------------------------------------------------------------
  588. AI_BEGIN_CUSTOM_NPC( npc_cranedriver, CNPC_CraneDriver )
  589. //Tasks
  590. DECLARE_TASK( TASK_CRANE_GET_POSITION_OVER_ENEMY )
  591. DECLARE_TASK( TASK_CRANE_GET_POSITION_OVER_LASTPOSITION )
  592. DECLARE_TASK( TASK_CRANE_GET_POSITION_OVER_OBJECT )
  593. DECLARE_TASK( TASK_CRANE_TURN_MAGNET_OFF )
  594. DECLARE_TASK( TASK_END_FORCED_DROP )
  595. DECLARE_TASK( TASK_CRANE_FIND_OBJECT_TO_PICKUP )
  596. DECLARE_TASK( TASK_CRANE_DROP_MAGNET )
  597. //Schedules
  598. //==================================================
  599. // SCHED_ANTLION_CHASE_ENEMY_BURROW
  600. //==================================================
  601. DEFINE_SCHEDULE
  602. (
  603. SCHED_CRANE_RANGE_ATTACK1,
  604. " Tasks"
  605. " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_CHASE_ENEMY"
  606. " TASK_CRANE_GET_POSITION_OVER_ENEMY 0"
  607. " TASK_WAIT_FOR_MOVEMENT 0"
  608. " TASK_CRANE_TURN_MAGNET_OFF 0"
  609. " "
  610. " Interrupts"
  611. " COND_ENEMY_DEAD"
  612. " COND_NEW_ENEMY"
  613. " COND_ENEMY_OCCLUDED"
  614. " COND_ENEMY_TOO_FAR"
  615. " COND_PROVOKED"
  616. )
  617. DEFINE_SCHEDULE
  618. (
  619. SCHED_CRANE_FIND_LARGE_OBJECT,
  620. " Tasks"
  621. " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_CHASE_ENEMY"
  622. " TASK_CRANE_FIND_OBJECT_TO_PICKUP 0"
  623. " "
  624. " Interrupts"
  625. " COND_ENEMY_DEAD"
  626. " COND_NEW_ENEMY"
  627. " COND_ENEMY_OCCLUDED"
  628. " COND_ENEMY_TOO_FAR"
  629. )
  630. DEFINE_SCHEDULE
  631. (
  632. SCHED_CRANE_PICKUP_OBJECT,
  633. " Tasks"
  634. " TASK_SET_FAIL_SCHEDULE SCHEDULE:SCHED_CHASE_ENEMY"
  635. " TASK_CRANE_GET_POSITION_OVER_OBJECT 0"
  636. " TASK_WAIT_FOR_MOVEMENT 0"
  637. " TASK_CRANE_DROP_MAGNET 0"
  638. " "
  639. " Interrupts"
  640. " COND_ENEMY_DEAD"
  641. " COND_NEW_ENEMY"
  642. " COND_ENEMY_OCCLUDED"
  643. " COND_ENEMY_TOO_FAR"
  644. " COND_PROVOKED"
  645. )
  646. DEFINE_SCHEDULE
  647. (
  648. SCHED_CRANE_FORCED_GO,
  649. " Tasks"
  650. " TASK_CRANE_GET_POSITION_OVER_LASTPOSITION 0"
  651. " TASK_WAIT_FOR_MOVEMENT 0"
  652. " TASK_CRANE_TURN_MAGNET_OFF 0"
  653. " TASK_WAIT 2"
  654. " "
  655. " Interrupts"
  656. )
  657. DEFINE_SCHEDULE
  658. (
  659. SCHED_CRANE_CHASE_ENEMY,
  660. " Tasks"
  661. " TASK_CRANE_GET_POSITION_OVER_ENEMY 0"
  662. " TASK_WAIT_FOR_MOVEMENT 0"
  663. " TASK_WAIT 5"
  664. " "
  665. " Interrupts"
  666. " COND_NEW_ENEMY"
  667. " COND_ENEMY_DEAD"
  668. " COND_ENEMY_UNREACHABLE"
  669. " COND_CAN_RANGE_ATTACK1"
  670. " COND_TOO_CLOSE_TO_ATTACK"
  671. " COND_TASK_FAILED"
  672. " COND_LOST_ENEMY"
  673. " COND_PROVOKED"
  674. )
  675. DEFINE_SCHEDULE
  676. (
  677. SCHED_CRANE_FORCED_DROP,
  678. " Tasks"
  679. " TASK_WAIT_FOR_MOVEMENT 0"
  680. " TASK_CRANE_TURN_MAGNET_OFF 0"
  681. " TASK_END_FORCED_DROP 0"
  682. " TASK_WAIT 2"
  683. " "
  684. " Interrupts"
  685. )
  686. AI_END_CUSTOM_NPC()