void CBuildModeDialogMgr::Add( BuildModeDialog *pDlg )
{
	if ( m_vecBuildDialogs.Find( pDlg ) == m_vecBuildDialogs.InvalidIndex() )
	{
		m_vecBuildDialogs.AddToTail( pDlg );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : origin - 
//			radius - 
//			list - 
//-----------------------------------------------------------------------------
void CFuncLadder::FindNearbyDismountPoints( const Vector& origin, float radius, CUtlVector< CInfoLadderDismountHandle >& list )
{
#if !defined( CLIENT_DLL )
	CBaseEntity *pEntity = NULL;
	while ( (pEntity = gEntList.FindEntityByClassnameWithin( pEntity, "info_ladder_dismount", origin, radius)) != NULL )
	{
		CInfoLadderDismount *landingspot = static_cast< CInfoLadderDismount * >( pEntity );
		Assert( landingspot );

		// If spot has a target, then if the target is not this ladder, don't add to our list.
		if ( landingspot->m_target != NULL_STRING )
		{
			if ( landingspot->GetNextTarget() != this )
			{
				continue;
			}
		}

		CInfoLadderDismountHandle handle;
		handle = landingspot;
		if ( list.Find( handle ) == list.InvalidIndex() )
		{
			list.AddToTail( handle  );
		}
	}
#endif
}
//------------------------------------------------------------------------------
// Purpose:
//------------------------------------------------------------------------------
void CPointPlayerMoveConstraint::InputTurnOn( inputdata_t &inputdata )
{
	// Find all players within our radius and constraint them
	float flRadius = m_flRadius;
	// If we're in singleplayer, blow the radius a bunch
	if ( gpGlobals->maxClients == 1 )
	{
		flRadius = MAX_COORD_RANGE;
	}
	CBaseEntity *pEntity = NULL;
	while ( (pEntity = gEntList.FindEntityByClassnameWithin( pEntity, "player", GetLocalOrigin(), flRadius)) != NULL )
	{
		CBasePlayer *pPlayer = ToBasePlayer( pEntity );
		Assert( pPlayer );
		
		// Only add him if he's not already constrained
		if ( m_hConstrainedPlayers.Find( pPlayer ) == m_hConstrainedPlayers.InvalidIndex() )
		{
			m_hConstrainedPlayers.AddToTail( pPlayer );

			pPlayer->ActivateMovementConstraint( this, GetAbsOrigin(), m_flRadius, m_flConstraintWidth, m_flSpeedFactor );
		}
	}

	// Only think if we found any
	if ( m_hConstrainedPlayers.Count() )
	{
		SetThink( &CPointPlayerMoveConstraint::ConstraintThink );
		SetNextThink( gpGlobals->curtime + 0.1f );
	}
}
示例#4
0
void CClientLeafSystem::RemoveRenderable( ClientRenderHandle_t handle )
{
	// This can happen upon level shutdown
	if (!m_Renderables.IsValidIndex(handle))
		return;

	// Reset the render handle in the entity.
	IClientRenderable *pRenderable = m_Renderables[handle].m_pRenderable;
	Assert( handle == pRenderable->RenderHandle() );
	pRenderable->RenderHandle() = INVALID_CLIENT_RENDER_HANDLE;

	// Reemove the renderable from the dirty list
	if ( m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED )
	{
		// NOTE: This isn't particularly fast (linear search),
		// but I'm assuming it's an unusual case where we remove 
		// renderables that are changing or that m_DirtyRenderables usually
		// only has a couple entries
		int i = m_DirtyRenderables.Find( handle );
		Assert( i != m_DirtyRenderables.InvalidIndex() );
		m_DirtyRenderables.FastRemove( i ); 
	}

	if ( IsViewModelRenderGroup( (RenderGroup_t)m_Renderables[handle].m_RenderGroup ) )
	{
		RemoveFromViewModelList( handle );
	}

	RemoveFromTree( handle );
	m_Renderables.Remove( handle );
}
示例#5
0
//-----------------------------------------------------------------------------
// Purpose: Checks to see if a weapon is already known
// Input  : *pWeapon - weapon to check for
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool CTriggerWeaponDissolve::HasWeapon( CBaseCombatWeapon *pWeapon )
{
	if ( m_pWeapons.Find( pWeapon ) == m_pWeapons.InvalidIndex() )
		return false;

	return true;
}
示例#6
0
//-----------------------------------------------------------------------------
// Purpose: Constructor
//-----------------------------------------------------------------------------
CBitmapFont::CBitmapFont()
{
	m_scalex = 1.0f;
	m_scaley = 1.0f;

	m_bitmapFontHandle = g_BitmapFontTable.InvalidIndex();
}
示例#7
0
//-----------------------------------------------------------------------------
// Purpose: Static method
// Input  : *event - 
//			soundlist - 
//-----------------------------------------------------------------------------
void CSceneCache::PrecacheSceneEvent( CChoreoEvent *event, CUtlVector< unsigned short >& soundlist )
{
	if ( !event || event->GetType() != CChoreoEvent::SPEAK )
		return;

	int idx = soundemitterbase->GetSoundIndex( event->GetParameters() );
	if ( idx != -1 )
	{
		MEM_ALLOC_CREDIT();
		Assert( idx <= 65535 );
		soundlist.AddToTail( (unsigned short)idx );
	}

	if ( event->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
	{
		char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
		if ( event->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
		{
			int idx = soundemitterbase->GetSoundIndex( tok );
			if ( idx != -1 && soundlist.Find( idx ) == soundlist.InvalidIndex() )
			{
				MEM_ALLOC_CREDIT();
				Assert( idx <= 65535 );
				soundlist.AddToTail( (unsigned short)idx );
			}
		}
	}
}
void CSecobModportal1List::RemoveFromList( CNPC_SecobModportal1 *pSecobModportal1 )
{
	int index = m_list.Find( pSecobModportal1 );
	if ( index != m_list.InvalidIndex() )
	{
		m_list.FastRemove( index );
	}
}
示例#9
0
void CBullseyeList::RemoveFromList( CNPC_Bullseye *pBullseye )
{
	int index = m_list.Find( pBullseye );
	if ( index != m_list.InvalidIndex() )
	{
		m_list.FastRemove( index );
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void C_TeamTrainWatcher::Spawn( void )
{
	BaseClass::Spawn();

	if ( g_hTrainWatchers.Find( this ) == g_hTrainWatchers.InvalidIndex() )
	{
		g_hTrainWatchers.AddToTail( this );
	}
}
示例#11
0
static bool FindAndRemoveExecutionMarker( int iCode )
{
	int i = g_ExecutionMarkers.Find( iCode );
	if ( i == g_ExecutionMarkers.InvalidIndex() )
		return false;
	
	g_ExecutionMarkers.Remove( i );
	return true;
}
static int CC_asw_teleport_autocomplete( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
{
	if ( !g_pGameRules )
	{
		return 0;
	}

	char const *cmdname = "asw_teleport";

	char *substring = (char *)partial;
	if ( Q_strstr( partial, cmdname ) )
	{
		substring = (char *)partial + strlen( cmdname ) + 1;
	}

	int checklen = Q_strlen( substring );
	CUtlSymbolTable entries( 0, 0, true );
	CUtlVector< CUtlSymbol > symbols;

	CBaseEntity *pos = NULL;
	while ( ( pos = gEntList.NextEnt( pos ) ) != NULL )
	{
		// Check target name against partial string
		if ( pos->GetEntityName() == NULL_STRING )
			continue;

		if ( Q_strnicmp( STRING( pos->GetEntityName() ), substring, checklen ) )
			continue;

		CUtlSymbol sym = entries.AddString( STRING( pos->GetEntityName() ) );

		int idx = symbols.Find( sym );
		if ( idx == symbols.InvalidIndex() )
		{
			symbols.AddToTail( sym );
		}

		// Too many
		if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
			break;
	}

	// Now fill in the results
	for ( int i = 0; i < symbols.Count(); i++ )
	{
		char const *name = entries.String( symbols[ i ] );

		char buf[ 512 ];
		Q_strncpy( buf, name, sizeof( buf ) );
		Q_strlower( buf );

		Q_snprintf( commands[ i ], COMMAND_COMPLETION_ITEM_LENGTH, "%s %s",
			cmdname, buf );
	}

	return symbols.Count();
}
// If the table's ID is -1, writes its info into the buffer and increments curID.
void DataTable_MaybeCreateReceiveTable( CUtlVector< SendTable * >& visited, SendTable *pTable, bool bNeedDecoder )
{
	// Already sent?
	if ( visited.Find( pTable ) != visited.InvalidIndex() )
		return;

	visited.AddToTail( pTable );

	DataTable_SetupReceiveTableFromSendTable( pTable, bNeedDecoder );
}
//-----------------------------------------------------------------------------
// Purpose: 
//-----------------------------------------------------------------------------
void CTriggerPortal::DisableForIncomingEntity( CBaseEntity *pEntity )
{
	EHANDLE hHandle;
	hHandle = pEntity;
	Assert( m_hDisabledForEntities.Find(hHandle) == m_hDisabledForEntities.InvalidIndex() );
	m_hDisabledForEntities.AddToTail( hHandle );

	// Start thinking, and remove the other as soon as it's not touching me.
	// Needs to be done in addition to EndTouch, because entities may move fast
	// enough through the portal to come out not touching the other portal.
	SetContextThink( &CTriggerPortal::DisabledThink, gpGlobals->curtime + 0.1, TRIGGER_DISABLED_THINK );
}
//-----------------------------------------------------------------------------
// Purpose: Static method
// Input  : sounds - 
//			*soundname - 
//-----------------------------------------------------------------------------
void CModelSoundsCache::FindOrAddScriptSound( CUtlVector< unsigned short >& sounds, char const *soundname )
{
	int soundindex = soundemitterbase->GetSoundIndex( soundname );
	if ( soundindex != -1 )
	{
		// Only add it once per model...
		if ( sounds.Find( soundindex ) == sounds.InvalidIndex() )
		{
			MEM_ALLOC_CREDIT();
			sounds.AddToTail( soundindex );
		}
	}
}
示例#16
0
//-----------------------------------------------------------------------------
// Helper for crawling events to determine sounds
//-----------------------------------------------------------------------------
void FindSoundsInEvent( CChoreoEvent *pEvent, CUtlVector< short >& soundList )
{
	if ( !pEvent || pEvent->GetType() != CChoreoEvent::SPEAK )
		return;

	unsigned short stringId = g_ChoreoStringPool.FindOrAddString( pEvent->GetParameters() );
	if ( soundList.Find( stringId ) == soundList.InvalidIndex() )
	{
		soundList.AddToTail( stringId );
	}

	if ( pEvent->GetCloseCaptionType() == CChoreoEvent::CC_MASTER )
	{
		char tok[ CChoreoEvent::MAX_CCTOKEN_STRING ];
		if ( pEvent->GetPlaybackCloseCaptionToken( tok, sizeof( tok ) ) )
		{
			stringId = g_ChoreoStringPool.FindOrAddString( tok );
			if ( soundList.Find( stringId ) == soundList.InvalidIndex() )
			{
				soundList.AddToTail( stringId );
			}
		}
	}
}
bool CASW_Location_Group::IsGroupLocked( CUtlVector<int> &completedMissions )
{
    if ( asw_unlock_all_locations.GetBool() )
        return false;

    if ( m_UnlockedBy.Count() <= 0 )
        return false;

    for ( int i = 0; i < m_UnlockedBy.Count(); i++ )
    {
        if ( completedMissions.Find( m_UnlockedBy[i] ) != completedMissions.InvalidIndex() )	// this mission has been completed, so it won't make this group locked
            continue;

        // one of our required missions is incomplete, so this group is locked
        return true;
    }
    return false;
}
示例#18
0
//-----------------------------------------------------------------------------
// Call this when the renderable moves
//-----------------------------------------------------------------------------
void CClientLeafSystem::RenderableChanged( ClientRenderHandle_t handle )
{
	Assert ( handle != INVALID_CLIENT_RENDER_HANDLE );
	Assert( m_Renderables.IsValidIndex( handle ) );
	if ( !m_Renderables.IsValidIndex( handle ) )
		return;

	if ( (m_Renderables[handle].m_Flags & RENDER_FLAGS_HASCHANGED ) == 0 )
	{
		m_Renderables[handle].m_Flags |= RENDER_FLAGS_HASCHANGED;
		m_DirtyRenderables.AddToTail( handle );
	}
#if _DEBUG
	else
	{
		// It had better be in the list
		Assert( m_DirtyRenderables.Find( handle ) != m_DirtyRenderables.InvalidIndex() );
	}
#endif
}
示例#19
0
//-----------------------------------------------------------------------------
// Purpose: Fills in a list of commands based on specified subdirectory and extension into the format:
//  commandname subdir/filename.ext
//  commandname subdir/filename2.ext
// Returns number of files in list for autocompletion
//-----------------------------------------------------------------------------
int CBaseAutoCompleteFileList::AutoCompletionFunc( char const *partial, char commands[ COMMAND_COMPLETION_MAXITEMS ][ COMMAND_COMPLETION_ITEM_LENGTH ] )
{
	char const *cmdname = m_pszCommandName;

	char *substring = (char *)partial;
	if ( Q_strstr( partial, cmdname ) )
	{
		substring = (char *)partial + strlen( cmdname ) + 1;
	}

	// Search the directory structure.
	char searchpath[MAX_QPATH];
	if ( m_pszSubDir && m_pszSubDir[0] && Q_strcasecmp( m_pszSubDir, "NULL" ) )
	{
		Q_snprintf(searchpath,sizeof(searchpath),"%s/*.%s", m_pszSubDir, m_pszExtension );
	}
	else
	{
		Q_snprintf(searchpath,sizeof(searchpath),"*.%s", m_pszExtension );
	}

	CUtlSymbolTable entries( 0, 0, true );
	CUtlVector< CUtlSymbol > symbols;
    FileFindHandle_t hfind = FILESYSTEM_INVALID_FIND_HANDLE;
    const char* findfn = g_pFullFileSystem->FindFirst(searchpath, &hfind);
	while ( findfn )
	{
		char sz[ MAX_QPATH ];
		Q_snprintf( sz, sizeof( sz ), "%s", findfn );

		bool add = false;
		// Insert into lookup
		if ( substring[0] )
		{
			if ( !Q_strncasecmp( findfn, substring, strlen( substring ) ) )
			{
				add = true;
			}
		}
		else
		{
			add = true;
		}

		if ( add )
		{
			CUtlSymbol sym = entries.AddString( findfn );

			int idx = symbols.Find( sym );
			if ( idx == symbols.InvalidIndex() )
			{
				symbols.AddToTail( sym );
			}
		}

        findfn = g_pFullFileSystem->FindNext(hfind);

		// Too many
		if ( symbols.Count() >= COMMAND_COMPLETION_MAXITEMS )
			break;
	}

    g_pFullFileSystem->FindClose(hfind);
    hfind = FILESYSTEM_INVALID_FIND_HANDLE;

	for ( int i = 0; i < symbols.Count(); i++ )
	{
		char const *filename = entries.String( symbols[ i ] );

		Q_snprintf( commands[ i ], sizeof( commands[ i ] ), "%s %s", cmdname, filename );
		// Remove ".momrec"
		commands[ i ][ strlen( commands[ i ] ) - 7 ] = 0;
	}

	return symbols.Count();
}
示例#20
0
//-----------------------------------------------------------------------------
// Invokes methods on all installed game systems
//-----------------------------------------------------------------------------
bool IGameSystem::InitAllSystems()
{
	int i;

	{
		// first add any auto systems to the end
		CAutoGameSystem *pSystem = s_pSystemList;
		while ( pSystem )
		{
			if ( s_GameSystems.Find( pSystem ) == s_GameSystems.InvalidIndex() )
			{
				Add( pSystem );
			}
			else
			{
				DevWarning( 1, "AutoGameSystem already added to game system list!!!\n" );
			}
			pSystem = pSystem->m_pNext;
		}
		s_pSystemList = NULL;
	}

	{
		CAutoGameSystemPerFrame *pSystem = s_pPerFrameSystemList;
		while ( pSystem )
		{
			if ( s_GameSystems.Find( pSystem ) == s_GameSystems.InvalidIndex() )
			{
				Add( pSystem );
			}
			else
			{
				DevWarning( 1, "AutoGameSystem already added to game system list!!!\n" );
			}

			pSystem = pSystem->m_pNext;
		}
		s_pSystemList = NULL;
	}
	// Now remember that we are initted so new CAutoGameSystems will add themselves automatically.
	s_bSystemsInitted = true;

	for ( i = 0; i < s_GameSystems.Count(); ++i )
	{
		MDLCACHE_CRITICAL_SECTION();

		IGameSystem *sys = s_GameSystems[i];

#if defined( _X360 )
		char sz[128];
		Q_snprintf( sz, sizeof( sz ), "%s->Init():Start", sys->Name() );
		XBX_rTimeStampLog( Plat_FloatTime(), sz );
#endif
		bool valid = sys->Init();

#if defined( _X360 )
		Q_snprintf( sz, sizeof( sz ), "%s->Init():Finish", sys->Name() );
		XBX_rTimeStampLog( Plat_FloatTime(), sz );
#endif
		if ( !valid )
			return false;
	}

	return true;
}
示例#21
0
//-----------------------------------------------------------------------------
// Adds, removes renderables from view model list
//-----------------------------------------------------------------------------
void CClientLeafSystem::AddToViewModelList( ClientRenderHandle_t handle )
{
	MEM_ALLOC_CREDIT();
	Assert( m_ViewModels.Find( handle ) == m_ViewModels.InvalidIndex() );
	m_ViewModels.AddToTail( handle );
}
示例#22
0
void CClientLeafSystem::RemoveFromViewModelList( ClientRenderHandle_t handle )
{
	int i = m_ViewModels.Find( handle );
	Assert( i != m_ViewModels.InvalidIndex() );
	m_ViewModels.FastRemove( i );
}
示例#23
0
//-----------------------------------------------------------------------------
// Purpose: Upon touching a non-filtered entity, CTriggerPortal teleports them to it's
//			remote portal location.
// Input  : *pOther - 
//-----------------------------------------------------------------------------
void CTriggerPortal::Touch( CBaseEntity *pOther )
{
	// If we are enabled, and allowed to react to the touched entity
	if ( PassesTriggerFilters(pOther) )
	{
		// If we somehow lost our pointer to the remote portal, get a new one
		if ( m_hRemotePortal == NULL )
		{
			Disable();
			return;
		}

		bool bDebug = portal_debug.GetBool();
		if ( bDebug )
		{
			Msg("%s TOUCH: for %s\n", GetDebugName(), pOther->GetDebugName() );
		}

		// Don't touch entities that came through us and haven't left us yet.
		EHANDLE hHandle;
		hHandle = pOther;
		if ( m_hDisabledForEntities.Find(hHandle) != m_hDisabledForEntities.InvalidIndex() )
		{
			Msg("    IGNORED\n", GetDebugName(), pOther->GetDebugName() );
			return;
		}

		Pickup_ForcePlayerToDropThisObject( pOther );

		// de-ground this entity
        pOther->SetGroundEntity( NULL );

		// Build a this --> remote transformation
		VMatrix matMyModelToWorld, matMyInverse;
		matMyModelToWorld = this->EntityToWorldTransform();
		MatrixInverseGeneral ( matMyModelToWorld, matMyInverse );

		// Teleport our object
		VMatrix matRemotePortalTransform = m_hRemotePortal->EntityToWorldTransform();
		Vector ptNewOrigin, vLook, vRight, vUp, vNewLook;
		pOther->GetVectors( &vLook, &vRight, &vUp );

		// Move origin
		ptNewOrigin = matMyInverse * pOther->GetAbsOrigin();
		ptNewOrigin = matRemotePortalTransform * Vector( ptNewOrigin.x, -ptNewOrigin.y, ptNewOrigin.z );

		// Re-aim camera
		vNewLook	= matMyInverse.ApplyRotation( vLook );
		vNewLook	= matRemotePortalTransform.ApplyRotation( Vector( -vNewLook.x, -vNewLook.y, vNewLook.z ) );

		// Reorient the physics
	 	Vector vVelocity, vOldVelocity;
		pOther->GetVelocity( &vOldVelocity );
		vVelocity = matMyInverse.ApplyRotation( vOldVelocity );
		vVelocity = matRemotePortalTransform.ApplyRotation( Vector( -vVelocity.x, -vVelocity.y, vVelocity.z ) );

		QAngle qNewAngles;
		VectorAngles( vNewLook, qNewAngles );
		
		if ( pOther->IsPlayer() )
		{
			((CBasePlayer*)pOther)->SnapEyeAngles(qNewAngles);
		}

		Vector vecOldPos = pOther->WorldSpaceCenter();
		if ( bDebug )
		{
			NDebugOverlay::Box( pOther->GetAbsOrigin(), pOther->WorldAlignMins(), pOther->WorldAlignMaxs(), 255,0,0, 8, 20 );
			NDebugOverlay::Axis( pOther->GetAbsOrigin(), pOther->GetAbsAngles(), 10.0f, true, 50 );
		}

		// place player at the new destination
		CTriggerPortal *pPortal = m_hRemotePortal.Get();
		pPortal->DisableForIncomingEntity( pOther );
		pOther->Teleport( &ptNewOrigin, &qNewAngles, &vVelocity );

		if ( bDebug )
		{
			NDebugOverlay::Box( pOther->GetAbsOrigin(), pOther->WorldAlignMins(), pOther->WorldAlignMaxs(), 0,255,0, 8, 20 );
			NDebugOverlay::Line( vecOldPos, pOther->WorldSpaceCenter(), 0,255,0, true, 20 );
			NDebugOverlay::Axis( pOther->GetAbsOrigin(), pOther->GetAbsAngles(), 10.0f, true, 50 );

			Msg("%s TELEPORTED: %s\n", GetDebugName(), pOther->GetDebugName() );
		}

		// test collision on the new teleport location
		Vector vMin, vMax, vCenter;
		pOther->CollisionProp()->WorldSpaceAABB( &vMin, &vMax );
		vCenter = (vMin + vMax) * 0.5f;
		vMin -= vCenter;
		vMax -= vCenter;

		Vector vStart, vEnd;
		vStart	= ptNewOrigin;
		vEnd	= ptNewOrigin;

		Ray_t ray;
		ray.Init( vStart, vEnd, vMin, vMax );
		trace_t tr;
		pPortal->TestCollision( ray, pOther->PhysicsSolidMaskForEntity(), tr );

		// Teleportation caused us to hit something, deal with it.
		if ( tr.DidHit() )
		{
			
		}

		
	}
}
//-----------------------------------------------------------------------------
// Purpose: 
// Input  : *pTask - 
//-----------------------------------------------------------------------------
void CNPC_CraneDriver::StartTask( const Task_t *pTask )
{
	switch( pTask->iTask )
	{
	case TASK_WAIT_FOR_MOVEMENT:
		break;

	case TASK_CRANE_GET_POSITION_OVER_ENEMY:
		{
			if ( !GetEnemy() )
			{
				TaskFail(FAIL_NO_ROUTE);
				return;
			}

			SetDesiredPosition( GetEnemy()->GetAbsOrigin() );
			TaskComplete();
		}
		break;

	case TASK_CRANE_GET_POSITION_OVER_OBJECT:
		{
			if ( !m_hPickupTarget )
			{
				TaskFail("No object to pickup!");
				return;
			}

			SetDesiredPosition( m_hPickupTarget->GetAbsOrigin() );
			TaskComplete();
		}
		break;

	case TASK_CRANE_GET_POSITION_OVER_LASTPOSITION:
		{
			SetDesiredPosition( m_vecLastPosition );
			TaskComplete();
		}
		break;

	case TASK_CRANE_TURN_MAGNET_OFF:
		{
			// If we picked up something, and we were being forced to pick something up, fire our output
			if ( m_hCrane->GetTotalMassOnCrane() > 0 && m_bForcedDropoff )
			{
				// Are we supposed to pause first?
				if ( m_flReleasePause )
				{
					m_flReleaseAt = gpGlobals->curtime + m_flReleasePause;
					m_OnPausingBeforeDrop.FireOutput( this, this );
					return;
				}

				m_OnDroppedObject.FireOutput( this, this );
			}

			m_hCrane->TurnMagnetOff();
			TaskComplete();
		}
		break;

	case TASK_END_FORCED_DROP:
		{
			m_bForcedDropoff = false;
			TaskComplete();
		}
		break;

	case TASK_CRANE_FIND_OBJECT_TO_PICKUP:
		{
			Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );

			// Find a large physics object within our reach to pickup
			float flLargestMass = 0;
			CBaseEntity *pLargestEntity = NULL;
			
			CBaseEntity *pList[1024];
			Vector delta( m_flDistTooFar, m_flDistTooFar, m_flDistTooFar*2 );
			int count = UTIL_EntitiesInBox( pList, 1024, m_hCrane->GetAbsOrigin() - delta, m_hCrane->GetAbsOrigin() + delta, 0 );
			for ( int i = 0; i < count; i++ )
			{
				if ( !pList[i] ) 
					continue;
				// Ignore the crane & the magnet
				if ( pList[i] == m_hCrane || pList[i] == m_hCrane->GetMagnet() )
					continue;
				if ( m_PreviouslyPickedUpObjects.Find( pList[i] ) != m_PreviouslyPickedUpObjects.InvalidIndex() )
					continue;

				// Get the VPhysics object
				IPhysicsObject *pPhysics = pList[i]->VPhysicsGetObject();
				if ( pPhysics && pList[i]->GetMoveType() == MOVETYPE_VPHYSICS )
				{
					float flMass = pPhysics->GetMass();
					if ( flMass > flLargestMass && (flMass < MAXIMUM_CRANE_PICKUP_MASS) && (flMass > MINIMUM_CRANE_PICKUP_MASS) )
					{
						// Biggest one we've found so far

						// Now make sure it's within our reach
						// Do our distance check in 2D
						Vector2D vecOrigin2D( m_hCrane->GetAbsOrigin().x, m_hCrane->GetAbsOrigin().y );
						Vector2D vecEnemy2D( pList[i]->GetAbsOrigin().x, pList[i]->GetAbsOrigin().y );
						float flDist = (vecOrigin2D - vecEnemy2D).Length();
						// Maximum & Minimum size of the crane's reach
						if ( flDist > MAX_CRANE_FLAT_REACH )
							continue;
						if ( flDist < MIN_CRANE_FLAT_REACH )
							continue;

						flLargestMass = flMass;
						pLargestEntity = pList[i];
					}
				}
			}

			// If we didn't find anything new, clear our list of targets
			if ( !pLargestEntity )
			{
				m_PreviouslyPickedUpObjects.Purge();
			}

			if ( !pLargestEntity )
			{
				TaskFail("Couldn't find anything to pick up!");
				return;
			}

			m_hPickupTarget = pLargestEntity;
			TaskComplete();
		}
		break;

	case TASK_CRANE_DROP_MAGNET:
		{
			// Drop the magnet, but only end the task once the magnet's back up
			m_pVehicleInterface->NPC_SecondaryFire();

			// Don't check to see if drop's finished until this time is up.
			// This is necessary because the crane won't start dropping this
			// frame, and our cranedriver will think it's finished immediately.
			m_flDropWait = gpGlobals->curtime + 0.5;
		}
		break;

	default:
		BaseClass::StartTask( pTask );
		break;
	}
}