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; }