Esempio n. 1
0
// Gets called each time the mind is thinking
void IdleSleepState::Think(idAI* owner)
{
	Memory& memory = owner->GetMemory();

	if (_startSleeping && owner->GetMoveType() == MOVETYPE_ANIM)
	{
		if (owner->ReachedPos(memory.idlePosition, MOVE_TO_POSITION) 
			&& owner->GetCurrentYaw() == memory.idleYaw)
		{
			owner->AI_LAY_DOWN_LEFT = owner->spawnArgs.GetBool("lay_down_left", "1");
			owner->LayDown();
		}
	}
	else if (owner->GetMoveType() == MOVETYPE_GET_UP_FROM_LYING)
	{
		owner->GetMind()->SwitchState(owner->backboneStates[ERelaxed]);
		owner->commSubsystem->ClearTasks();
		return;
	}

	UpdateAlertLevel();

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner)) return;
}
// Gets called each time the mind is thinking
void AgitatedSearchingStateLanternBot::Think(idAI* owner)
{
	UpdateAlertLevel();

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
//		owner->GetMind()->EndState(); // grayman #3182 - already done in CheckAlertLevel()
		return;
	}

	// Move (if alert position has changed)
	MoveTowardAlertPos(owner);

	if (owner->GetMoveStatus() == MOVE_STATUS_DONE)
	{
		// Look at alert position, now that we've finished moving
		owner->TurnToward(_curAlertPos);

		// Let the alertness decrease from now on
		CalculateAlertDecreaseRate(owner);
	}
	else
	{
		// Moving along, ensure that we're not dropping out of this state as long as we're moving
		_alertLevelDecreaseRate = 0;
		return;
	}
}
Esempio n. 3
0
void IdleSleepState::Init(idAI* owner)
{
	// Init base class first
	State::Init(owner);

	DM_LOG(LC_AI, LT_INFO)LOGSTRING("IdleSleepState initialised.\r");
	assert(owner);

	// Memory shortcut
	Memory& memory = owner->GetMemory();
	memory.alertClass = EAlertNone;
	memory.alertType = EAlertTypeNone;

	if (owner->HasSeenEvidence() && !owner->spawnArgs.GetBool("disable_alert_idle", "0"))
	{
		owner->GetMind()->SwitchState(STATE_ALERT_IDLE);
		return;
	}

	if (owner->GetMoveType() != MOVETYPE_SLEEP && 
		(!owner->ReachedPos(memory.idlePosition, MOVE_TO_POSITION) 
			|| owner->GetCurrentYaw() != memory.idleYaw))
	{
		// we need to get to the bed first before starting to sleep, back to idle state
		owner->GetMind()->SwitchState(owner->backboneStates[ERelaxed]);
		return;
	}

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner)) return;

	_startSleeping = owner->spawnArgs.GetBool("sleeping", "0");
	_startSitting = owner->spawnArgs.GetBool("sitting", "0");

	_alertLevelDecreaseRate = 0.01f;

	// owner->SheathWeapon();

	owner->actionSubsystem->ClearTasks();
	owner->senseSubsystem->ClearTasks();
	owner->commSubsystem->ClearTasks();

	InitialiseMovement(owner);

	int idleBarkIntervalMin = SEC2MS(owner->spawnArgs.GetInt("sleep_bark_interval_min", "10"));
	int idleBarkIntervalMax = SEC2MS(owner->spawnArgs.GetInt("sleep_bark_interval_max", "30"));

	owner->commSubsystem->AddCommTask(
		CommunicationTaskPtr(new RepeatedBarkTask("snd_sleeping", idleBarkIntervalMin, idleBarkIntervalMax))
	);

	// Let the AI update their weapons (make them nonsolid)
	owner->UpdateAttachmentContents(false);
}
void AgitatedSearchingStateLanternBot::Init(idAI* owner)
{
	// Init base class first
	State::Init(owner);

	DM_LOG(LC_AI, LT_INFO)LOGSTRING("AgitatedSearchingStateLanternBot initialised.\r");
	assert(owner);

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
		return;
	}

	owner->movementSubsystem->ClearTasks();
	owner->senseSubsystem->ClearTasks();
	owner->actionSubsystem->ClearTasks();
	owner->commSubsystem->ClearTasks(); // grayman #3182
	owner->searchSubsystem->ClearTasks(); // grayman #3857

	owner->StopMove(MOVE_STATUS_DONE);

	// Start with an invalid position
	_curAlertPos = idVec3(idMath::INFINITY, idMath::INFINITY, idMath::INFINITY);

	// Move to a position where we can light up the alert position from
	MoveTowardAlertPos(owner);

	owner->GetMemory().currentSearchEventID = owner->LogSuspiciousEvent( E_EventTypeMisc, owner->GetPhysics()->GetOrigin(), NULL, true ); // grayman #3857

	// This will hold the message to be delivered with the inaudible bark
	CommMessagePtr message(new CommMessage(
		CommMessage::RequestForHelp_CommType, // grayman #3857 - asking for a response
		//CommMessage::DetectedEnemy_CommType,  // grayman #3857 - this does nothing when no entity (parameter 4) is provided
		owner, NULL,// from this AI to anyone 
		NULL,
		_curAlertPos,
		owner->GetMemory().currentSearchEventID // grayman #3857 (was '0')
	));

	// The communication system plays starting bark
	owner->commSubsystem->AddCommTask(
		CommunicationTaskPtr(new RepeatedBarkTask("snd_spotted_noise", 3000, 4000, message))
	);

	// Add the script task blowing the alarm whistle
	owner->actionSubsystem->PushTask(TaskPtr(new ScriptTask("startAlarmWhistle")));
}
Esempio n. 5
0
// Gets called each time the mind is thinking
void ObservantState::Think(idAI* owner)
{
	UpdateAlertLevel();
	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
		return;
	}
	
	// grayman #3520 - look at alert spots
	if (owner->m_lookAtAlertSpot)
	{
		owner->m_lookAtAlertSpot = false;
		if ( owner->GetMoveType() != MOVETYPE_SLEEP ) // grayman #3487 - not if asleep
		{
			idVec3 alertSpot = owner->m_lookAtPos;
			if ( alertSpot.x != idMath::INFINITY )
			{
				if (owner->CheckFOV(alertSpot))
				{
					owner->Event_LookAtPosition(alertSpot,((float)owner->AI_AlertLevel)/10.0f);
				}
			}
		}
		owner->m_lookAtPos = idVec3(idMath::INFINITY,idMath::INFINITY,idMath::INFINITY);
	}

	// grayman #2866 - zero alert decrease rate if handling a door or elevator

	if ((owner->m_HandlingDoor) || (owner->m_HandlingElevator))
	{
		_alertLevelDecreaseRate = 0;
	}
	else
	{
		_alertLevelDecreaseRate = owner->GetMemory().savedAlertLevelDecreaseRate;
	}

	if (owner->GetMoveType() != MOVETYPE_SLEEP)
	{
		// Let the AI check its senses
		owner->PerformVisualScan();
	}
}
void SearchingState::Init( idAI *owner ) {
	// Init base class first
	State::Init( owner );
	DM_LOG( LC_AI, LT_INFO )LOGSTRING( "SearchingState initialised.\r" );
	assert( owner );
	// Ensure we are in the correct alert level
	if( !CheckAlertLevel( owner ) ) {
		return;
	}
	if( owner->GetMoveType() == MOVETYPE_SIT || owner->GetMoveType() == MOVETYPE_SLEEP ) {
		owner->GetUp();
	}
	// Shortcut reference
	Memory &memory = owner->GetMemory();
	float alertTime = owner->atime3 + owner->atime3_fuzzyness * ( gameLocal.random.RandomFloat() - 0.5 );
	_alertLevelDecreaseRate = ( owner->thresh_4 - owner->thresh_3 ) / alertTime;
	if( owner->AlertIndexIncreased() || memory.mandatory ) { // grayman #3331
		// Setup a new hiding spot search
		StartNewHidingSpotSearch( owner );
	}
	if( owner->AlertIndexIncreased() ) {
		// grayman #3423 - when the alert level is ascending, kill the repeated bark task
		owner->commSubsystem->ClearTasks();
		// Play bark if alert level is ascending
		// grayman #3496 - enough time passed since last alert bark?
		if( gameLocal.time >= memory.lastTimeAlertBark + MIN_TIME_BETWEEN_ALERT_BARKS ) {
			idStr bark;
			if( ( memory.alertedDueToCommunication == false ) && ( ( memory.alertType == EAlertTypeSuspicious ) || ( memory.alertType == EAlertTypeEnemy ) ) ) {
				bool friendsNear = ( ( MS2SEC( gameLocal.time - memory.lastTimeFriendlyAISeen ) ) <= MAX_FRIEND_SIGHTING_SECONDS_FOR_ACCOMPANIED_ALERT_BARK );
				if( ( memory.alertClass == EAlertVisual_1 ) ||
						( memory.alertClass == EAlertVisual_2 ) ||    // grayman #2603, #3424
						// (memory.alertClass == EAlertVisual_3) ) || // grayman #3472 - no longer needed
						( memory.alertClass == EAlertVisual_4 ) ) {   // grayman #3498
					if( friendsNear ) {
						bark = "snd_alert3sc";
					} else {
						bark = "snd_alert3s";
					}
				} else if( memory.alertClass == EAlertAudio ) {
					if( friendsNear ) {
						bark = "snd_alert3hc";
					} else {
						bark = "snd_alert3h";
					}
				} else if( friendsNear ) {
					bark = "snd_alert3c";
				} else {
					bark = "snd_alert3";
				}
				// Allocate a SingleBarkTask, set the sound and enqueue it
				owner->commSubsystem->AddCommTask( CommunicationTaskPtr( new SingleBarkTask( bark ) ) );
				memory.lastTimeAlertBark = gameLocal.time; // grayman #3496
				if( cv_ai_debug_transition_barks.GetBool() ) {
					gameLocal.Printf( "%d: %s rises to Searching state, barks '%s'\n", gameLocal.time, owner->GetName(), bark.c_str() );
				}
			}
		} else {
			if( cv_ai_debug_transition_barks.GetBool() ) {
				gameLocal.Printf( "%d: %s rises to Searching state, can't bark 'snd_alert3{s/sc/h/hc/c}' yet\n", gameLocal.time, owner->GetName() );
			}
		}
	} else if( memory.alertType == EAlertTypeEnemy ) {
		// reduce the alert type, so we can react to other alert types (such as a dead person)
		memory.alertType = EAlertTypeSuspicious;
	}
	// grayman #3472 - When ascending, set up a repeated bark
	if( owner->AlertIndexIncreased() ) {
		owner->commSubsystem->AddSilence( 5000 + gameLocal.random.RandomInt( 3000 ) ); // grayman #3424
		// This will hold the message to be delivered with the bark
		CommMessagePtr message( new CommMessage(
									CommMessage::DetectedEnemy_CommType,
									owner, NULL,// from this AI to anyone
									NULL,
									idVec3( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY ),
									0
								) );
		int minTime = SEC2MS( owner->spawnArgs.GetFloat( "searchbark_delay_min", "10" ) );
		int maxTime = SEC2MS( owner->spawnArgs.GetFloat( "searchbark_delay_max", "15" ) );
		owner->commSubsystem->AddCommTask( CommunicationTaskPtr( new RepeatedBarkTask( "snd_state3", minTime, maxTime, message ) ) );
	} else { // descending
		// Allow repeated barks from Agitated Searching to continue.
	}
	if( !owner->HasSeenEvidence() ) {
		owner->SheathWeapon();
		owner->UpdateAttachmentContents( false );
	} else {
		// Let the AI update their weapons (make them solid)
		owner->UpdateAttachmentContents( true );
	}
}
// Gets called each time the mind is thinking
void SearchingState::Think( idAI *owner ) {
	UpdateAlertLevel();
	// Ensure we are in the correct alert level
	if( !CheckAlertLevel( owner ) ) {
		return;
	}
	// grayman #3063 - move up so it gets done each time,
	// regardless of what state the hiding spot search is in.
	// Let the AI check its senses
	owner->PerformVisualScan();
	if( owner->GetMoveType() == MOVETYPE_SIT
			|| owner->GetMoveType() == MOVETYPE_SLEEP
			|| owner->GetMoveType() == MOVETYPE_SIT_DOWN
			|| owner->GetMoveType() == MOVETYPE_LAY_DOWN ) {
		owner->GetUp();
		return;
	}
	Memory &memory = owner->GetMemory();
	owner->MarkEventAsSearched( memory.currentSearchEventID ); // grayman #3424
	// grayman #3520 - look at alert spots
	if( owner->m_lookAtAlertSpot ) {
		owner->m_lookAtAlertSpot = false;
		idVec3 alertSpot = owner->m_lookAtPos;
		if( alertSpot.x != idMath::INFINITY ) { // grayman #3438
			if( !owner->CheckFOV( alertSpot ) ) {
				// Search spot is not within FOV, turn towards the position
				owner->TurnToward( alertSpot );
				owner->Event_LookAtPosition( alertSpot, 2.0f );
			} else {
				owner->Event_LookAtPosition( alertSpot, 2.0f );
			}
		}
		owner->m_lookAtPos = idVec3( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY );
	}
	// grayman #3200 - if asked to restart the hiding spot search, don't continue with the current hiding spot search
	if( memory.restartSearchForHidingSpots ) {
		// We should restart the search (probably due to a new incoming stimulus)
		// Setup a new hiding spot search
		StartNewHidingSpotSearch( owner );
	} else if( !memory.hidingSpotSearchDone ) { // Do we have an ongoing hiding spot search?
		// Let the hiding spot search do its task
		PerformHidingSpotSearch( owner );
		// Let the AI check its senses
		//		owner->PerformVisualScan(); // grayman #3063 - moved to front
		/*
				// angua: commented this out, problems with getting up from sitting
				idStr waitState(owner->WaitState());
				if (waitState.IsEmpty())
				{
					// Waitstate is not matching, this means that the animation
					// can be started.
					owner->SetAnimState(ANIMCHANNEL_TORSO, "Torso_LookAround", 5);
					//owner->SetAnimState(ANIMCHANNEL_LEGS, "Legs_LookAround", 5);

					// Set the waitstate, this gets cleared by
					// the script function when the animation is done.
					owner->SetWaitState("look_around");
				}
		*/
	}
	// Is a hiding spot search in progress?
	else if( !memory.hidingSpotInvestigationInProgress ) {
		// Spot search and investigation done, what next?
		// Have run out of hiding spots?
		if( memory.noMoreHidingSpots ) {
			if( gameLocal.time >= memory.nextTime2GenRandomSpot ) {
				memory.nextTime2GenRandomSpot = gameLocal.time + DELAY_RANDOM_SPOT_GEN * ( 1 + ( gameLocal.random.RandomFloat() - 0.5 ) / 3 );
				// grayman #2422
				// Generate a random search point, but make sure it's inside an AAS area
				// and that it's also inside the search volume.
				idVec3 p;		// random point
				int areaNum;	// p's area number
				idVec3 searchSize = owner->m_searchLimits.GetSize();
				idVec3 searchCenter = owner->m_searchLimits.GetCenter();
				//gameRenderWorld->DebugBox(colorWhite, idBox(owner->m_searchLimits), MS2SEC(memory.nextTime2GenRandomSpot - gameLocal.time));
				bool validPoint = false;
				for( int i = 0 ; i < 6 ; i++ ) {
					p = searchCenter;
					p.x += gameLocal.random.RandomFloat() * ( searchSize.x ) - searchSize.x / 2;
					p.y += gameLocal.random.RandomFloat() * ( searchSize.y ) - searchSize.y / 2;
					p.z += gameLocal.random.RandomFloat() * ( searchSize.z ) - searchSize.z / 2;
					//p.z += gameLocal.random.RandomFloat()*(searchSize.z/2) - searchSize.z/4;
					areaNum = owner->PointReachableAreaNum( p );
					if( areaNum == 0 ) {
						//gameRenderWorld->DebugArrow(colorRed, owner->GetEyePosition(), p, 1, MS2SEC(memory.nextTime2GenRandomSpot - gameLocal.time));
						continue;
					}
					owner->GetAAS()->PushPointIntoAreaNum( areaNum, p ); // if this point is outside this area, it will be moved to one of the area's edges
					if( !owner->m_searchLimits.ContainsPoint( p ) ) {
						//gameRenderWorld->DebugArrow(colorPink, owner->GetEyePosition(), p, 1, MS2SEC(memory.nextTime2GenRandomSpot - gameLocal.time));
						continue;
					}
					//gameRenderWorld->DebugArrow(colorGreen, owner->GetEyePosition(), p, 1, MS2SEC(memory.nextTime2GenRandomSpot - gameLocal.time));
					validPoint = true;
					break;
				}
				if( validPoint ) {
					// grayman #2422 - the point chosen
					memory.currentSearchSpot = p;
					// Choose to investigate spots closely on a random basis
					// grayman #2801 - and only if you weren't hit by a projectile
					memory.investigateStimulusLocationClosely = ( ( gameLocal.random.RandomFloat() < 0.3f ) && ( memory.alertType != EAlertTypeHitByProjectile ) );
					owner->actionSubsystem->PushTask( TaskPtr( InvestigateSpotTask::CreateInstance() ) );
					//gameRenderWorld->DebugArrow(colorGreen, owner->GetEyePosition(), memory.currentSearchSpot, 1, 500);
					// Set the flag to TRUE, so that the sensory scan can be performed
					memory.hidingSpotInvestigationInProgress = true;
				}
				if( !validPoint ) { // no valid random point found
					// Stop moving, the algorithm will choose another spot the next round
					owner->StopMove( MOVE_STATUS_DONE );
					memory.StopReacting(); // grayman #3559
					// grayman #2422 - at least turn toward and look at the last invalid point some of the time
					// grayman #3492 - do it every time
					//if ( gameLocal.random.RandomFloat() < 0.5 )
					//{
					p.z += 60; // look up a bit, to simulate searching for the player's head
					if( !owner->CheckFOV( p ) ) {
						owner->TurnToward( p );
					}
					owner->Event_LookAtPosition( p, MS2SEC( memory.nextTime2GenRandomSpot - gameLocal.time + 100 ) );
					//gameRenderWorld->DebugArrow(colorPink, owner->GetEyePosition(), p, 1, MS2SEC(memory.nextTime2GenRandomSpot - gameLocal.time + 100));
					//}
				}
			}
		}
		// We should have more hiding spots, try to get the next one
		else if( !ChooseNextHidingSpotToSearch( owner ) ) {
			// No more hiding spots to search
			DM_LOG( LC_AI, LT_INFO )LOGSTRING( "No more hiding spots!\r" );
			// Stop moving, the algorithm will choose another spot the next round
			owner->StopMove( MOVE_STATUS_DONE );
			memory.StopReacting(); // grayman #3559
		} else {
			// ChooseNextHidingSpot returned TRUE, so we have memory.currentSearchSpot set
			//gameRenderWorld->DebugArrow(colorBlue, owner->GetEyePosition(), memory.currentSearchSpot, 1, 2000);
			// Delegate the spot investigation to a new task, this will take the correct action.
			owner->actionSubsystem->PushTask( InvestigateSpotTask::CreateInstance() );
			// Prevent falling into the same hole twice
			memory.hidingSpotInvestigationInProgress = true;
		}
	}
	/* grayman #3200 - moved up
		else if (memory.restartSearchForHidingSpots)
		{
			// We should restart the search (probably due to a new incoming stimulus)
			// Setup a new hiding spot search
			StartNewHidingSpotSearch(owner);
		}

		else // grayman #3063 - moved to front
		{
			// Move to Hiding spot is ongoing, do additional sensory tasks here

			// Let the AI check its senses
			owner->PerformVisualScan();
		}
	 */
}
Esempio n. 8
0
// Gets called each time the mind is thinking
void CombatState::Think(idAI* owner)
{
	// Do we have an expiry date?
	if (_endTime > 0)
	{
		if (gameLocal.time >= _endTime)
		{
			owner->GetMind()->EndState();
		}

		return;
	}

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
//		owner->GetMind()->EndState(); // grayman #3182 - already done in CheckAlertLevel()
		return;
	}

	// grayman #3331 - make sure you're still fighting the same enemy.
	// grayman #3355 - fight the closest enemy
	idActor* enemy = _enemy.GetEntity();
	idActor* newEnemy = owner->GetEnemy();

	if ( enemy )
	{
		if ( newEnemy && ( newEnemy != enemy ) )
		{
			idVec3 ownerOrigin = owner->GetPhysics()->GetOrigin();
			float dist2EnemySqr = ( enemy->GetPhysics()->GetOrigin() - ownerOrigin ).LengthSqr();
			float dist2NewEnemySqr = ( newEnemy->GetPhysics()->GetOrigin() - ownerOrigin ).LengthSqr();
			if ( dist2NewEnemySqr < dist2EnemySqr )
			{
				owner->GetMind()->EndState();
				return; // state has ended
			}
		}
	}
	else
	{
		enemy = newEnemy;
	}

	if (!CheckEnemyStatus(enemy, owner))
	{
		owner->GetMind()->EndState();
		return; // state has ended
	}

	// grayman #3520 - don't look toward new alerts
	if ( owner->m_lookAtAlertSpot )
	{
		owner->m_lookAtAlertSpot = false;
		owner->m_lookAtPos = idVec3(idMath::INFINITY,idMath::INFINITY,idMath::INFINITY);
	}

	// angua: look at enemy
	owner->Event_LookAtPosition(enemy->GetEyePosition(), gameLocal.msec);

	Memory& memory = owner->GetMemory();

	idVec3 vec2Enemy = enemy->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin();
	float dist2Enemy = vec2Enemy.LengthFast();

	// grayman #3331 - need to take vertical separation into account. It's possible to have the origins
	// close enough to be w/in the melee zone, but still be unable to hit the enemy.

	bool inMeleeRange = ( dist2Enemy <= ( 3 * owner->GetMeleeRange() ) );

	ECombatType newCombatType;
	
	if ( inMeleeRange && !_meleePossible ) // grayman #3355 - can't fight up close
	{
		owner->fleeingEvent = false; // grayman #3356
		owner->emitFleeBarks = false; // grayman #3474
		owner->GetMind()->SwitchState(STATE_FLEE);
		return;
	}

	if ( !inMeleeRange && _rangedPossible )
	{
		newCombatType = COMBAT_RANGED;
	}
	else
	{
		newCombatType = COMBAT_MELEE;
	}

	// Check for situation where you're in the melee zone, yet you're unable to hit
	// the enemy. This can happen if the enemy is above or below you and you can't
	// reach them.

	switch(_combatSubState)
	{
	case EStateReaction:
		{
		if ( gameLocal.time < _reactionEndTime )
		{
			return; // stay in this state until the reaction time expires
		}

		// Check to see if the enemy is still visible.
		// grayman #2816 - Visibility doesn't matter if you're in combat because
		// you bumped into your enemy.

		idEntity* tactEnt = owner->GetTactEnt();
		if ( ( tactEnt == NULL ) || !tactEnt->IsType(idActor::Type) || ( tactEnt != enemy ) || !owner->AI_TACTALERT ) 
		{
			if ( !owner->CanSee(enemy, true) )
			{
				owner->ClearEnemy();
				owner->SetAlertLevel(owner->thresh_5 - 0.1); // reset alert level just under Combat
				owner->GetMind()->EndState();
				return;
			}
		}

		owner->m_ignorePlayer = false; // grayman #3063 - clear flag that prevents mission statistics on player sightings

		// The AI has processed his reaction, and needs to move into combat, or flee.

		_criticalHealth = owner->spawnArgs.GetInt("health_critical", "0");

		// greebo: Check for weapons and flee if ...
		if ( ( !_meleePossible && !_rangedPossible )		 || // ... I'm unarmed
			 ( owner->spawnArgs.GetBool("is_civilian", "0")) || // ... I'm a civilian, and don't fight
			 ( owner->health < _criticalHealth ) )			    // grayman #3140 ... I'm very damaged and can't afford to engage in combat
		{
			owner->fleeingEvent = false; // grayman #3356
			owner->emitFleeBarks = true; // grayman #3474
			owner->GetMind()->SwitchState(STATE_FLEE);
			return;
		}

		memory.stopRelight = true; // grayman #2603 - abort a relight in progress
		memory.stopExaminingRope = true; // grayman #2872 - stop examining a rope
		memory.stopReactingToHit = true; // grayman #2816

		_combatSubState = EStateDoOnce;
		break;
		}

	case EStateDoOnce:
		{
		// Check for sitting or sleeping

		moveType_t moveType = owner->GetMoveType();
		if (   moveType == MOVETYPE_SIT 
			|| moveType == MOVETYPE_SLEEP
			|| moveType == MOVETYPE_SIT_DOWN
			|| moveType == MOVETYPE_LAY_DOWN )
		{
			owner->GetUp(); // okay if called multiple times
			return;
		}

		// grayman #3009 - check for getting up from sitting or sleeping
		if ( moveType == MOVETYPE_GET_UP || 
			 moveType == MOVETYPE_GET_UP_FROM_LYING )
		{
			return;
		}

		// not sitting or sleeping at this point

		// Stop what you're doing
		owner->StopMove(MOVE_STATUS_DONE);
		owner->movementSubsystem->ClearTasks();
		owner->senseSubsystem->ClearTasks();
		owner->actionSubsystem->ClearTasks();

		// Bark

		// This will hold the message to be delivered with the bark, if appropriate
		CommMessagePtr message;
	
		// Only alert the bystanders if we didn't receive the alert by message ourselves
		if (!memory.alertedDueToCommunication)
		{
			message = CommMessagePtr(new CommMessage(
				CommMessage::DetectedEnemy_CommType, 
				owner, NULL, // from this AI to anyone 
				enemy,
				memory.lastEnemyPos,
				0
			));
		}

		// grayman #3496 - This is an alert bark, but it's not subject to the delay
		// between alert barks because the previous bark will end before we get here.
		// It's also the culmination of a journey up from Idle State, and if the AI is
		// going to go after an enemy, this bark needs to be heard.
		// We'll still reset the last alert bark time, though.

		// The communication system plays starting bark

		// grayman #3343 - accommodate different barks for human and non-human enemies

		idPlayer* player(NULL);
		if (enemy->IsType(idPlayer::Type))
		{
			player = static_cast<idPlayer*>(enemy);
		}

		idStr bark = "";

		if (player && player->m_bShoulderingBody)
		{
			bark = "snd_spotted_player_with_body";
		}
		else if ((MS2SEC(gameLocal.time - memory.lastTimeFriendlyAISeen)) <= MAX_FRIEND_SIGHTING_SECONDS_FOR_ACCOMPANIED_ALERT_BARK)
		{
			idStr enemyAiUse = enemy->spawnArgs.GetString("AIUse");
			if ( ( enemyAiUse == AIUSE_MONSTER ) || ( enemyAiUse == AIUSE_UNDEAD ) )
			{
				bark = "snd_to_combat_company_monster";
			}
			else
			{
				bark = "snd_to_combat_company";
			}
		}
		else
		{
			idStr enemyAiUse = enemy->spawnArgs.GetString("AIUse");
			if ( ( enemyAiUse == AIUSE_MONSTER ) || ( enemyAiUse == AIUSE_UNDEAD ) )
			{
				bark = "snd_to_combat_monster";
			}
			else
			{
				bark = "snd_to_combat";
			}
		}

		owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(bark, message)));

		owner->GetMemory().lastTimeAlertBark = gameLocal.time; // grayman #3496

		if (cv_ai_debug_transition_barks.GetBool())
		{
			gameLocal.Printf("%d: %s starts combat, barks '%s'\n",gameLocal.time,owner->GetName(),bark.c_str());
		}

		_justDrewWeapon = false;
		_combatSubState = EStateCheckWeaponState;
		break;
		}

	case EStateCheckWeaponState:
		// check which combat type we should use
		{
		// Can you continue with your current combat type, and not have to switch weapons?

		// Check for case where melee combat has stalled. You're in the melee zone, but you're
		// unable to hit the enemy. Perhaps he's higher or lower than you and you can't reach him.

		if ( !owner->AI_FORWARD && // not moving
			 ( _combatType == COMBAT_MELEE ) && // in melee combat
			 _rangedPossible &&    // ranged combat is possible
			 !owner->TestMelee() ) // I can't hit the enemy
		{
			float        orgZ = owner->GetPhysics()->GetOrigin().z;
			float      height = owner->GetPhysics()->GetBounds().GetSize().z;
			float   enemyOrgZ = enemy->GetPhysics()->GetOrigin().z;
			float enemyHeight = enemy->GetPhysics()->GetBounds().GetSize().z;
			if ( ( (orgZ + height + owner->melee_range_vert) < enemyOrgZ ) || // enemy too high
							     ( (enemyOrgZ + enemyHeight) < orgZ ) ) // enemy too low
			{
				newCombatType = COMBAT_RANGED;
			}
		}

		if ( newCombatType == _combatType )
		{
			// yes - no need to run weapon-switching animations
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// Do you need to switch a melee or ranged weapon? You might already have one
		// drawn, or you might have none drawn, or you might have to change weapons,
		// or you might be using unarmed attacks, and you don't need a drawn weapon.

		// Check for unarmed combat.

		if ( _unarmedMelee && ( newCombatType == COMBAT_MELEE ) )
		{
			// unarmed combat doesn't need attached weapons
			_combatType = COMBAT_NONE; // clear ranged combat tasks and start melee combat tasks
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		if ( _unarmedRanged && ( newCombatType == COMBAT_RANGED ) )
		{
			// unarmed combat doesn't need attached weapons
			_combatType = COMBAT_NONE; // clear melee combat tasks and start ranged combat tasks
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// Do you have a drawn weapon?

		if ( owner->GetAttackFlag(COMBAT_MELEE) && ( newCombatType == COMBAT_MELEE ) )
		{
			// melee weapon is already drawn
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		if ( owner->GetAttackFlag(COMBAT_RANGED) && ( newCombatType == COMBAT_RANGED ) )
		{
			// ranged weapon is already drawn
			_combatSubState = EStateCombatAndChecks;
			return;
		}

		// At this point, we know we need to draw a weapon that's not already drawn.
		// See if you need to sheathe a drawn weapon.

		if ( ( ( newCombatType == COMBAT_RANGED ) && owner->GetAttackFlag(COMBAT_MELEE)  ) ||
		     ( ( newCombatType == COMBAT_MELEE  ) && owner->GetAttackFlag(COMBAT_RANGED) ) )
		{
			// switch from one type of weapon to another
			owner->movementSubsystem->ClearTasks();
			owner->actionSubsystem->ClearTasks();
			_combatType = COMBAT_NONE;

			// sheathe current weapon so you can draw the other weapon
			owner->SheathWeapon();
			_waitEndTime = gameLocal.time + 2000; // safety net
			_combatSubState = EStateSheathingWeapon;
			return;
		}

		// No need to sheathe a weapon
		_combatSubState = EStateDrawWeapon;

		break;
		}

	case EStateSheathingWeapon:
		{
		// if you're sheathing a weapon, stay in this state until it's done, or until the timer expires
		// grayman #3355 - check wait state
		if ( ( gameLocal.time < _waitEndTime ) && ( idStr(owner->WaitState()) == "sheath") )
		{
			return;
		}

		_combatSubState = EStateDrawWeapon;

		break;
		}

	case EStateDrawWeapon:
		{
		// grayman #3331 - if you don't already have the correct weapon drawn,
		// draw a ranged weapon if you're far from the enemy, and you have a 
		// ranged weapon, otherwise draw your melee weapon

		bool drawingWeapon = false;

		if ( !inMeleeRange )
		{
			// beyond melee range
			if ( !owner->GetAttackFlag(COMBAT_RANGED) && _rangedPossible )
			{
				owner->DrawWeapon(COMBAT_RANGED);
				drawingWeapon = true;
			}
			else // no ranged weapon
			{
				owner->DrawWeapon(COMBAT_MELEE);
				drawingWeapon = true;
			}
		}
		else // in melee range
		{
			if ( _meleePossible && !owner->GetAttackFlag(COMBAT_MELEE) )
			{
				owner->DrawWeapon(COMBAT_MELEE);
				drawingWeapon = true;
			}
		}

		// grayman #3331 - if this is the first weapon draw, to make sure the weapon is drawn
		// before starting combat, delay some before starting to chase the enemy.
		// The farther away the enemy is, the better the chance that you'll start chasing before your
		// weapon is drawn. If he's close, this gives you time to completely draw your weapon before
		// engaging him. The interesting distance is how far you have to travel to get w/in melee range.

		if ( _needInitialDrawDelay ) // True if this is the first time through, and you don't already have a raised weapon
		{
			int delay = 0;

			if ( drawingWeapon )
			{
				delay = (int)(2064.0f - 20.0f*(dist2Enemy - owner->GetMeleeRange()));
				if ( delay < 0 )
				{
					delay = gameLocal.random.RandomInt(2064);
				}
				_waitEndTime = gameLocal.time + delay;
				_combatSubState = EStateDrawingWeapon;

				// grayman #3563 - safety net when drawing a weapon
				_drawEndTime = gameLocal.time + MAX_DRAW_DURATION;
			}
			else
			{
				_combatSubState = EStateCombatAndChecks;
			}
			_needInitialDrawDelay = false; // No need to do this again
		}
		else
		{
			if ( drawingWeapon )
			{
				_waitEndTime = gameLocal.time;
				_combatSubState = EStateDrawingWeapon;

				// grayman #3563 - safety net when drawing a weapon
				_drawEndTime = gameLocal.time + MAX_DRAW_DURATION;
			}
			else
			{
				_combatSubState = EStateCombatAndChecks;
			}
		}
		break;
		}

	case EStateDrawingWeapon:
		{
		// grayman #3355 - check wait state
		if ( idStr(owner->WaitState()) == "draw" )
		{
			if ( gameLocal.time < _drawEndTime ) // grayman #3563 - check safety net
			{
				return; // wait until weapon is drawn
			}
		}

		if ( gameLocal.time < _waitEndTime )
		{
			return; // wait until timer expires
		}

		// Weapon is now drawn

		_justDrewWeapon = true;
		_combatSubState = EStateCombatAndChecks;

		break;
		}

	case EStateCombatAndChecks:
		{
		// Need to check if a weapon that was just drawn is correct for the zone you're now in, in case
		// you started drawing the correct weapon for one zone, and while it was drawing, you switched
		// to the other zone.
		
		if ( _justDrewWeapon )
		{
			if ( newCombatType == COMBAT_RANGED )
			{
				// beyond melee range
				if ( !owner->GetAttackFlag(COMBAT_RANGED) && _rangedPossible )
				{
					// wrong weapon raised - go back and get the correct one
					_justDrewWeapon = false;
					_combatSubState = EStateCheckWeaponState;
					return;
				}
			}
			else // in melee combat
			{
				if ( !owner->GetAttackFlag(COMBAT_MELEE) && _meleePossible )
				{
					// wrong weapon raised - go back and get the correct one
					_justDrewWeapon = false;
					_combatSubState = EStateCheckWeaponState;
					return;
				}
			}
		}

		_justDrewWeapon = false;
		if ( _combatType == COMBAT_NONE ) // Either combat hasn't been initially set up, or you're switching weapons
		{
			if ( newCombatType == COMBAT_RANGED )
			{
				// Set up ranged combat
				owner->actionSubsystem->PushTask(RangedCombatTask::CreateInstance());
				owner->movementSubsystem->PushTask(ChaseEnemyRangedTask::CreateInstance());
				_combatType = COMBAT_RANGED;
			}
			else
			{
				// Set up melee combat
				ChaseEnemyTaskPtr chaseEnemy = ChaseEnemyTask::CreateInstance();
				chaseEnemy->SetEnemy(enemy);
				owner->movementSubsystem->PushTask(chaseEnemy);

				owner->actionSubsystem->PushTask(MeleeCombatTask::CreateInstance());
				_combatType = COMBAT_MELEE;
			}

			// Let the AI update their weapons (make them nonsolid)
			owner->UpdateAttachmentContents(false);
		}

		// Check the distance to the enemy, the subsystem tasks need it.
		memory.canHitEnemy = owner->CanHitEntity(enemy, _combatType);
		// grayman #3331 - willBeAbleToHitEnemy is only relevant if canHitEnemy is FALSE
		if ( owner->m_bMeleePredictProximity && !memory.canHitEnemy )
		{
			memory.willBeAbleToHitEnemy = owner->WillBeAbleToHitEntity(enemy, _combatType);
		}

		// Check whether the enemy can hit us in the near future
		memory.canBeHitByEnemy = owner->CanBeHitByEntity(enemy, _combatType);

		if ( !owner->AI_ENEMY_VISIBLE && 
			 ( ( ( _combatType == COMBAT_MELEE )  && !memory.canHitEnemy ) || ( _combatType == COMBAT_RANGED) ) )
		{
			// The enemy is not visible, let's keep track of him for a small amount of time
			if (gameLocal.time - memory.lastTimeEnemySeen < MAX_BLIND_CHASE_TIME)
			{
				// Cheat a bit and take the last reachable position as "visible & reachable"
				owner->lastVisibleReachableEnemyPos = owner->lastReachableEnemyPos;
			}
			else if (owner->ReachedPos(owner->lastVisibleReachableEnemyPos, MOVE_TO_POSITION) || 
					( ( gameLocal.time - memory.lastTimeEnemySeen ) > 2 * MAX_BLIND_CHASE_TIME) )
			{
				// BLIND_CHASE_TIME has expired, we have lost the enemy!
				owner->GetMind()->SwitchState(STATE_LOST_TRACK_OF_ENEMY);
				return;
			}
		}

		// Flee if you're damaged and the current melee action is finished
		if ( ( owner->health < _criticalHealth ) && ( owner->m_MeleeStatus.m_ActionState == MELEEACTION_READY ) )
		{
			DM_LOG(LC_AI, LT_INFO)LOGSTRING("I'm badly hurt, I'm afraid, and am fleeing!\r");
			owner->fleeingEvent = false; // grayman #3182
			owner->emitFleeBarks = true; // grayman #3474
			owner->GetMind()->SwitchState(STATE_FLEE);
			return;
		}

		_combatSubState = EStateCheckWeaponState;

		break;
		}

	default:
		break;
	}
}
Esempio n. 9
0
void CombatState::Init(idAI* owner)
{
	// Init base class first
	State::Init(owner);

	// Set end time to something invalid
	_endTime = -1;

	DM_LOG(LC_AI, LT_INFO)LOGSTRING("CombatState initialised.\r");
	assert(owner);

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
		return;
	}

	if (!owner->GetMind()->PerformCombatCheck())
	{
		return;
	}

	if ( ( owner->GetMoveType() == MOVETYPE_SIT ) || ( owner->GetMoveType() == MOVETYPE_SLEEP) )
	{
		owner->GetUp();
	}

	// grayman #3075 - if we're kneeling, doing close inspection of
	// a spot, stop the animation. Otherwise, the kneeling animation gets
	// restarted a few moments later.

	idStr torsoString = "Torso_KneelDown";
	idStr legsString = "Legs_KneelDown";
	bool torsoKneelingAnim = (torsoString.Cmp(owner->GetAnimState(ANIMCHANNEL_TORSO)) == 0);
	bool legsKneelingAnim = (legsString.Cmp(owner->GetAnimState(ANIMCHANNEL_LEGS)) == 0);

	if ( torsoKneelingAnim || legsKneelingAnim )
	{
		// Reset anims
		owner->StopAnim(ANIMCHANNEL_TORSO, 0);
		owner->StopAnim(ANIMCHANNEL_LEGS, 0);
	}

	// grayman #3472 - kill the repeated bark task
	owner->commSubsystem->ClearTasks(); // grayman #3182

	// grayman #3496
	// Enough time passed since last alert bark?

	if ( gameLocal.time >= owner->GetMemory().lastTimeAlertBark + MIN_TIME_BETWEEN_ALERT_BARKS )
	{
		// grayman #3496 - But only bark if you haven't recently spent time in Agitated Search.

		if ( !owner->GetMemory().agitatedSearched )
		{
			// The communication system plays reaction bark
			CommMessagePtr message;
			owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask("snd_alert5", message)));

			owner->GetMemory().lastTimeAlertBark = gameLocal.time; // grayman #3496

			if (cv_ai_debug_transition_barks.GetBool())
			{
				gameLocal.Printf("%d: %s enters Combat State, barks surprised reaction 'snd_alert5'\n",gameLocal.time,owner->GetName());
			}
		}
		else
		{
			if (cv_ai_debug_transition_barks.GetBool())
			{
				gameLocal.Printf("%d: %s enters Combat State after spending time in Agitated Searching, so won't bark 'snd_alert5'\n",gameLocal.time,owner->GetName());
			}
		}
	}
	else
	{
		if (cv_ai_debug_transition_barks.GetBool())
		{
			gameLocal.Printf("%d: %s enters Combat State, can't bark 'snd_alert5' yet\n",gameLocal.time,owner->GetName());
		}
	}

	// All remaining init code is moved into Think() and done in the EStateReaction substate,
	// because the things it does need to occur after the initial reaction delay.

	// grayman #3063
	// Add a delay before you process the remainder of Init().
	// The length of the delay depends on the distance to the enemy.

	// We have an enemy, store the enemy entity locally
	_enemy = owner->GetEnemy();
	idActor* enemy = _enemy.GetEntity();

	// grayman #3331 - clear combat state
	_combatType = COMBAT_NONE;
	
	// get melee possibilities

	_meleePossible  = ( owner->GetNumMeleeWeapons()  > 0 );
	_rangedPossible = ( owner->GetNumRangedWeapons() > 0 );

	/* grayman #3492 - should wait until after the reaction time before fleeing

	// grayman #3355 - flee if you have no weapons

	if (!_meleePossible && !_rangedPossible)
	{
		owner->fleeingEvent = false; // grayman #3356
		owner->emitFleeBarks = true; // grayman #3474
		owner->GetMind()->SwitchState(STATE_FLEE);
		return;
	} */

	// grayman #3331 - save combat possibilities
	_unarmedMelee = owner->spawnArgs.GetBool("unarmed_melee","0");
	_unarmedRanged = owner->spawnArgs.GetBool("unarmed_ranged","0");
	_armedMelee = _meleePossible && !_unarmedMelee;
	_armedRanged = _rangedPossible && !_unarmedRanged;

	// grayman #3331 - do we need an initial delay at weapon drawing?
	_needInitialDrawDelay = !( owner->GetAttackFlag(COMBAT_MELEE) || owner->GetAttackFlag(COMBAT_RANGED) ); // not if we have a weapon raised

	idVec3 vec2Enemy = enemy->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin();
	//vec2Enemy.z = 0; // ignore vertical component
	float dist2Enemy = vec2Enemy.LengthFast();
	int reactionTime =  REACTION_TIME_MIN + (dist2Enemy*(REACTION_TIME_MAX - REACTION_TIME_MIN))/(cv_ai_sight_combat_cutoff.GetFloat()/s_DOOM_TO_METERS);
	if ( reactionTime > REACTION_TIME_MAX )
	{
		reactionTime = REACTION_TIME_MAX;
	}

	// grayman #3331 - add a bit of variability so multiple AI spotting the enemy in the same frame aren't in sync

	reactionTime += gameLocal.random.RandomInt(REACTION_TIME_MAX/2);

	_combatSubState = EStateReaction;
	_reactionEndTime = gameLocal.time + reactionTime;
}
void AgitatedSearchingState::Init(idAI* owner)
{
	// Init base class first (note: we're not calling SearchingState::Init() on purpose here)
	State::Init(owner);

	DM_LOG(LC_AI, LT_INFO)LOGSTRING("AgitatedSearchingState initialised.\r");
	assert(owner);

	// Shortcut reference
	Memory& memory = owner->GetMemory();

	memory.leaveAlertState = false;

	// Ensure we are in the correct alert level
	if ( !CheckAlertLevel(owner) )
	{
		return;
	}

	// grayman #3496 - note that we spent time in Agitated Search

	memory.agitatedSearched = true;

	CalculateAlertDecreaseRate(owner);
	
	if (owner->GetMoveType() == MOVETYPE_SIT || owner->GetMoveType() == MOVETYPE_SLEEP)
	{
		owner->GetUp();
	}

	// Set up a new hiding spot search if not already assigned to one
	if (owner->m_searchID <= 0)
	{
		if (!StartNewHidingSpotSearch(owner)) // grayman #3857 - AI gets his assignment
		{
			// grayman - this section can't run because it causes
			// the stealth score to rise dramatically during player sightings
			//owner->SetAlertLevel(owner->thresh_3 - 0.1); // failed to create a search, so drop down to Suspicious mode
			//owner->GetMind()->EndState();
			//return;
		}
	}

	// kill the repeated and single bark tasks
	owner->commSubsystem->ClearTasks(); // grayman #3182
	memory.repeatedBarkState = ERBS_NULL; // grayman #3857

	if (owner->AlertIndexIncreased())
	{
		// grayman #3496 - enough time passed since last alert bark?
		// grayman #3857 - enough time passed since last visual stim bark?
		if ( ( gameLocal.time >= memory.lastTimeAlertBark + MIN_TIME_BETWEEN_ALERT_BARKS ) &&
			 ( gameLocal.time >= memory.lastTimeVisualStimBark + MIN_TIME_BETWEEN_ALERT_BARKS ) )
		{
			idStr soundName = "";
			if ( ( memory.alertedDueToCommunication == false ) && ( ( memory.alertType == EAlertTypeSuspicious ) || ( memory.alertType == EAlertTypeEnemy ) || ( memory.alertType == EAlertTypeFailedKO ) ) )
			{
				if (owner->HasSeenEvidence())
				{
					soundName = "snd_alert4";
				}
				else
				{
					soundName = "snd_alert4NoEvidence";
				}

				CommMessagePtr message = CommMessagePtr(new CommMessage(
					CommMessage::DetectedSomethingSuspicious_CommType, 
					owner, NULL, // from this AI to anyone
					NULL,
					memory.alertPos,
					memory.currentSearchEventID // grayman #3438
				));

				owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(soundName,message)));

				memory.lastTimeAlertBark = gameLocal.time; // grayman #3496

				if (cv_ai_debug_transition_barks.GetBool())
				{
					gameLocal.Printf("%d: %s rises to Agitated Searching state, barks '%s'\n",gameLocal.time,owner->GetName(),soundName.c_str());
				}
			}
			else if ( memory.respondingToSomethingSuspiciousMsg ) // grayman #3857
			{
				soundName = "snd_helpSearch";

				// Allocate a SingleBarkTask, set the sound and enqueue it
				owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(soundName)));

				memory.lastTimeAlertBark = gameLocal.time; // grayman #3496

				if (cv_ai_debug_transition_barks.GetBool())
				{
					gameLocal.Printf("%d: %s rises to Searching state, barks '%s'\n",gameLocal.time,owner->GetName(),soundName.c_str());
				}
			}
		}
		else
		{
			if (cv_ai_debug_transition_barks.GetBool())
			{
				gameLocal.Printf("%d: %s rises to Agitated Searching state, can't bark 'snd_alert4{NoEvidence}' yet\n",gameLocal.time,owner->GetName());
			}
		}
	}

	owner->commSubsystem->AddSilence(5000 + gameLocal.random.RandomInt(3000)); // grayman #3424

	SetRepeatedBark(owner); // grayman #3857
	
	DrawWeapon(owner); // grayman #3507

	// Let the AI update their weapons (make them solid)
	owner->UpdateAttachmentContents(true);

	// grayman #3857 - no idle search anims in this state
	owner->actionSubsystem->ClearTasks();
}
Esempio n. 11
0
void ObservantState::Init(idAI* owner)
{
	// Init base class first
	State::Init(owner);

	DM_LOG(LC_AI, LT_INFO)LOGSTRING("ObservantState initialised.\r");
	assert(owner);

	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner))
	{
		return;
	}

	// Shortcut reference
	Memory& memory = owner->GetMemory();

	float alertTime = owner->atime1 + owner->atime1_fuzzyness * (gameLocal.random.RandomFloat() - 0.5);
	_alertLevelDecreaseRate = (owner->thresh_2 - owner->thresh_1) / alertTime;

	// grayman #2866 - zero alert decrease rate if handling a door or elevator

	memory.savedAlertLevelDecreaseRate = _alertLevelDecreaseRate; // save for restoration later

	if ((owner->m_HandlingDoor) || (owner->m_HandlingElevator))
	{
		_alertLevelDecreaseRate = 0;
	}

	// Stop playing idle animation
	owner->actionSubsystem->ClearTasks();

	// grayman #3438 - kill the repeated bark task
	owner->commSubsystem->ClearTasks();

	owner->searchSubsystem->ClearTasks(); // grayman #3857
	memory.currentSearchEventID = -1;

	// grayman #3472 - Play bark if alert level is ascending
	// grayman #3487 - But not if asleep

	if (owner->GetMoveType() != MOVETYPE_SLEEP)
	{
		if (owner->AlertIndexIncreased())
		{
			// grayman #3496 - Enough time passed since last alert bark?
			// grayman #3857 - Enough time passed since last visual stim bark?
			if ( ( gameLocal.time >= memory.lastTimeAlertBark + MIN_TIME_BETWEEN_ALERT_BARKS ) &&
				 ( gameLocal.time >= memory.lastTimeVisualStimBark + MIN_TIME_BETWEEN_ALERT_BARKS ) )
			{
				if ( !memory.alertedDueToCommunication && ( memory.alertClass != EAlertVisual_4 ) ) // grayman #2920, grayman #3498
				{
					// barking
					idStr bark;

					if ((memory.alertClass == EAlertVisual_1) ||
						(memory.alertClass == EAlertVisual_2) )
						//(memory.alertClass == EAlertVisual_3) ) // grayman #2603, #3424, grayman #3472 - no longer needed
					{
						bark = "snd_alert1s";
					}
					else if (memory.alertClass == EAlertAudio)
					{
						bark = "snd_alert1h";
					}
					else
					{
						bark = "snd_alert1";
					}

					owner->commSubsystem->AddCommTask(CommunicationTaskPtr(new SingleBarkTask(bark)));

					memory.lastTimeAlertBark = gameLocal.time; // grayman #3496

					if (cv_ai_debug_transition_barks.GetBool())
					{
						gameLocal.Printf("%d: %s rises to Observant state, barks '%s'\n",gameLocal.time,owner->GetName(),bark.c_str());
					}
				}
				else
				{
					memory.alertedDueToCommunication = false; // reset
				}
			}
			else
			{
				if (cv_ai_debug_transition_barks.GetBool())
				{
					gameLocal.Printf("%d: %s rises to Observant state, can't bark 'snd_alert1s' yet\n",gameLocal.time,owner->GetName());
				}
			}
		}
	}

	// Let the AI update their weapons (make them nonsolid)
	owner->UpdateAttachmentContents(false);
}
Esempio n. 12
0
// Gets called each time the mind is thinking
void FleeDoneState::Think(idAI* owner)
{
	if ( owner->AI_DEAD || owner->AI_KNOCKEDOUT ) // grayman #3317 - quit if KO'ed or dead
	{
		WrapUp(owner);
		owner->GetMind()->EndState();
		return;
	}

	UpdateAlertLevel();
		
	// Ensure we are in the correct alert level
	if (!CheckAlertLevel(owner)) 
	{
		// terminate FleeDoneState when time is over
		WrapUp(owner);
		owner->GetMind()->EndState();
		return;
	}

	// Let the AI check its senses
	owner->PerformVisualScan();
	if (owner->AI_ALERTED)
	{
		// terminate FleeDoneState when the AI is alerted
		WrapUp(owner);

		owner->GetMind()->EndState();
		return; // grayman #3474
	}

	if ( !owner->emitFleeBarks ) // grayman #3474
	{
		// not crying for help, time to end this state
		WrapUp(owner);
		owner->GetMind()->EndState();
		return;
	}

	// Shortcut reference
	Memory& memory = owner->GetMemory();

	if (!_searchForFriendDone)
	{
		idActor* friendlyAI = owner->FindFriendlyAI(-1);
		if ( friendlyAI != NULL)
		{
			// We found a friend, cry for help to him
			DM_LOG(LC_AI, LT_INFO)LOGSTRING("%s found friendly AI %s, crying for help\r", owner->name.c_str(),friendlyAI->name.c_str());

			_searchForFriendDone = true;
			owner->movementSubsystem->ClearTasks();
			owner->SetTurnRate(_oldTurnRate);

			owner->TurnToward(friendlyAI->GetPhysics()->GetOrigin());
			//float distanceToFriend = (friendlyAI->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin()).LengthFast();

			// Cry for help
			// Create a new help message
			CommMessagePtr message(new CommMessage(
				CommMessage::RequestForHelp_CommType, 
				owner, friendlyAI,
				NULL,
				memory.alertPos,
				memory.currentSearchEventID // grayman #3857 (was '0')
			)); 

			CommunicationTaskPtr barkTask(new SingleBarkTask("snd_flee", message));

			if (cv_ai_debug_transition_barks.GetBool())
			{
				gameLocal.Printf("%d: %s flees, barks 'snd_flee'\n",gameLocal.time,owner->GetName());
			}

			owner->commSubsystem->AddCommTask(barkTask);
			memory.lastTimeVisualStimBark = gameLocal.time;
		}
		else if (gameLocal.time >= _turnEndTime)
		{
			// We didn't find a friend, stop looking for them after some time
			_searchForFriendDone = true;
			owner->movementSubsystem->ClearTasks();
			owner->SetTurnRate(_oldTurnRate);

			// Play the cowering animation
			owner->SetAnimState(ANIMCHANNEL_TORSO, "Torso_Cower", 4);
			owner->SetAnimState(ANIMCHANNEL_LEGS, "Legs_Cower", 4);
		}
	}
}