bool ResolveMovementBlockTask::PerformBlockingAI(idAI* owner)
{
	if (owner->AI_MOVE_DONE && !owner->movementSubsystem->IsWaiting()) // grayman #2345 - if already waiting, no need to do this section
	{
		idVec3 ownerRight, ownerForward;
		_initialAngles.ToVectors(&ownerForward, &ownerRight);
		owner->StopMove(MOVE_STATUS_WAITING);
		owner->TurnToward(owner->GetPhysics()->GetOrigin() - ownerRight);

		if (owner->FacingIdeal() && _preTaskContents == -1)
		{
			// grayman #2345 - don't become non-solid if your alert index is > ERelaxed. This is because
			// AI tend to bunch together when agitated, and it doesn't look good if one goes non-solid
			// and the others repeatedly walk through it.

			// If there's no room to get around you, become non-solid

			if ((owner->AI_AlertIndex == ERelaxed) && !Room2Pass(owner))
			{
				BecomeNonSolid(owner);
			}
			else
			{
				bool solid = true;
				owner->movementSubsystem->SetWaiting(solid);
			}
		}
	}

	if (owner->movementSubsystem->IsWaiting()) // grayman #2345
	{
		// We are waiting for the other AI to pass by
		idVec3 dist = _blockingEnt->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin();

		if (dist.LengthSqr() > Square(60))
		{
			// other AI has passed by, end the task
			return true;
		}
		
		if (_blockingEnt->IsType(idAI::Type))
		{
			// grayman #2345 - check to see if the other AI is standing still.
			// If they are, end the task.

			idAI *_blockingEntAI = static_cast<idAI*>(_blockingEnt);
			if (_blockingEntAI && !_blockingEntAI->AI_FORWARD)
			{
				return true; // end the task
			}

			// If we're EWaitingSolid, change to EWaitingNonSolid if the other AI is barely moving.
			// grayman #2422 - but not if the other AI is searching

			if ( !_blockingEntAI->IsSearching() )
			{
				if (owner->movementSubsystem->IsWaitingSolid())
				{
					float traveledPrev = _blockingEntAI->movementSubsystem->GetPrevTraveled();
					if (traveledPrev < 0.1) // grayman #2345
					{
						BecomeNonSolid(owner);
					} 
				}
			}
		}

		if (ai_showObstacleAvoidance.GetBool())
		{
			// waiting AI is watching blocking AI
			gameRenderWorld->DebugLine(colorPink,owner->GetPhysics()->GetOrigin() + idVec3(0,0,72),_blockingEnt->GetPhysics()->GetOrigin() + idVec3(0,0,64),100);
		}
	}

	return false;
}
bool ResolveMovementBlockTask::PerformBlockingAI( idAI *owner ) {
	idVec3 right, forward;
	if( owner->AI_MOVE_DONE && !_turning && !owner->movementSubsystem->IsWaiting() ) { // grayman #2345 - if already waiting, no need to do this section
		// grayman #3725 - turn perpendicular to the direction
		// _blockingEnt is looking
		idAngles angles;
		if( _blockingEnt->IsType( idAI::Type ) ) {
			angles = static_cast<idAI *>( _blockingEnt )->viewAxis.ToAngles();
		} else {
			angles = _initialAngles;
		}
		angles.ToVectors( &forward, &right );
		owner->StopMove( MOVE_STATUS_WAITING );
		owner->TurnToward( owner->GetPhysics()->GetOrigin() + right );
		_turning = true; // grayman #3725
	}
	if( _turning ) { // grayman #3725
		if( !owner->FacingIdeal() ) {
			return false;
		}
		_turning = false;
		if( _preTaskContents == -1 ) {
			// grayman #2345 - don't become non-solid if your alert index is > ERelaxed. This is because
			// AI tend to bunch together when agitated, and it doesn't look good if one goes non-solid
			// and the others repeatedly walk through it.
			// If there's no room to get around you, become non-solid
			if( ( owner->AI_AlertIndex == ERelaxed ) && !Room2Pass( owner ) ) {
				BecomeNonSolid( owner );
			} else {
				bool solid = true;
				owner->movementSubsystem->SetWaiting( solid );
			}
		}
	}
	if( owner->movementSubsystem->IsWaiting() ) { // grayman #2345
		// We are waiting for the other AI to pass by
		idVec3 dist = _blockingEnt->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin();
		if( dist.LengthSqr() > Square( 60 ) ) {
			// other AI has passed by, end the task
			// Be sure no one else is touching you when you want to return to being solid.
			// If there is, remain non-solid and let them pass by before you return to solid.
			// (This might not matter, but let's be safe.)
			idClipModel *clipModels[ MAX_GENTITIES ];
			idPhysics *phys = owner->GetPhysics();
			int num = gameLocal.clip.ClipModelsTouchingBounds( phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES );
			bool foundNeighbor = false;
			for( int i = 0 ; i < num ; i++ ) {
				idClipModel *cm = clipModels[ i ];
				// don't check render entities
				if( cm->IsRenderModel() ) {
					continue;
				}
				idEntity *hit = cm->GetEntity();
				if( hit == owner ) {
					continue;
				}
				if( !phys->ClipContents( cm ) ) {
					continue;
				}
				// touching
				if( hit->IsType( idActor::Type ) ) {
					_blockingEnt = hit;
					foundNeighbor = true;
					break;
				}
			}
			if( !foundNeighbor ) {
				// grayman #3725 - Return to your initial facing angle. This will
				// only matter if you were initially standing. If you were moving,
				// ending this task will return you to that, overriding this turn.
				_initialAngles.ToVectors( &forward, &right );
				owner->TurnToward( owner->GetPhysics()->GetOrigin() + forward );
				return true;
			}
		}
		if( _blockingEnt->IsType( idAI::Type ) ) {
			// grayman #2345 - check to see if the other AI is standing still.
			// If they are, end the task.
			idAI *_blockingEntAI = static_cast<idAI *>( _blockingEnt );
			if( _blockingEntAI && !_blockingEntAI->AI_FORWARD ) {
				// grayman #3725 - turn back to your initial facing angle
				_initialAngles.ToVectors( &forward, &right );
				owner->TurnToward( owner->GetPhysics()->GetOrigin() + forward );
				return true; // end the task
			}
			// If we're EWaitingSolid, change to EWaitingNonSolid if the other AI is barely moving.
			// grayman #2422 - but not if the other AI is searching
			if( !_blockingEntAI->IsSearching() ) {
				if( owner->movementSubsystem->IsWaitingSolid() ) {
					float traveledPrev = _blockingEntAI->movementSubsystem->GetPrevTraveled( false ).LengthFast(); // grayman #3647
					if( traveledPrev < 0.1 ) { // grayman #2345
						BecomeNonSolid( owner );
					}
				}
			}
		}
		if( ai_showObstacleAvoidance.GetBool() ) {
			// waiting AI is watching blocking AI
			gameRenderWorld->DebugLine( colorPink, owner->GetPhysics()->GetOrigin() + idVec3( 0, 0, 72 ), _blockingEnt->GetPhysics()->GetOrigin() + idVec3( 0, 0, 64 ), 100 );
		}
	}
	return false;
}