void IdleAnimationTask::Init(idAI* owner, Subsystem& subsystem) { // Just init the base class Task::Init(owner, subsystem); //Memory& memory = owner->GetMemory(); // Read the animation set and interval from the owner's spawnarg _idleAnimationInterval = SEC2MS(owner->spawnArgs.GetInt("idle_animations_interval", "-1")); // Read the general-purpose animations first ParseAnimsToList(owner->spawnArgs.GetString("idle_animations"), _idleAnimations); // Now read the anims for the torso only ParseAnimsToList(owner->spawnArgs.GetString("idle_animations_torso"), _idleAnimationsTorso); // Now read the anims for sitting AI ParseAnimsToList(owner->spawnArgs.GetString("idle_animations_sitting"), _idleAnimationsSitting); if (_idleAnimationInterval > 0 && (_idleAnimations.Num() > 0 || _idleAnimationsTorso.Num() > 0 || _idleAnimationsSitting.Num() > 0)) { _nextAnimationTime = static_cast<int>(gameLocal.time + gameLocal.random.RandomFloat()*_idleAnimationInterval); } else { // No idle animation interval set or no animations, finish this task subsystem.FinishTask(); } }
void GreetingBarkTask::Init(idAI* owner, Subsystem& subsystem) { // Init the base class SingleBarkTask::Init(owner, subsystem); // Check the prerequisites - are both AI available for greeting? if ( !owner->CanGreet() || !_greetingTarget->CanGreet() || owner->m_isMute ) // grayman #3338 { // Owner or other AI cannot do greetings subsystem.FinishTask(); return; } // Allow state "waiting for greeting" for owner // Allow state "after Greeting" for the other AI if ( ( ( owner->greetingState != ENotGreetingAnybody ) && ( owner->greetingState != EWaitingForGreeting ) ) || ( ( _greetingTarget->greetingState != ENotGreetingAnybody ) && ( _greetingTarget->greetingState != EAfterGreeting ) ) ) { // Someone is busy DM_LOG(LC_AI, LT_INFO)LOGSTRING("Cannot greet: one of the actors is busy: %s to %s\r", owner->name.c_str(), _greetingTarget->name.c_str()); subsystem.FinishTask(); return; } // grayman #3415 - If both actors are sitting, disallow a greeting, on the // assumption that they've been that way for awhile, and any greetings would // already have happened. To keep pent-up greetings from occurring when one // actor stands up, move the allowed greeting time into the future. idAI* otherAI = static_cast<idAI*>(_greetingTarget); if ( (owner->GetMoveType() == MOVETYPE_SIT ) && (otherAI->GetMoveType() == MOVETYPE_SIT ) ) { int delay = (MINIMUM_TIME_BETWEEN_GREETING_SAME_ACTOR + gameLocal.random.RandomInt(EXTRA_DELAY_BETWEEN_GREETING_SAME_ACTOR))*1000; int nextGreetingTime = gameLocal.time + delay; owner->GetMemory().GetGreetingInfo(otherAI).nextGreetingTime = nextGreetingTime; otherAI->GetMemory().GetGreetingInfo(owner).nextGreetingTime = nextGreetingTime; subsystem.FinishTask(); return; } // Both AI are not greeting each other so far, continue owner->greetingState = EGoingToGreet; _greetingTarget->greetingState = EWaitingForGreeting; }
void ResolveMovementBlockTask::Init(idAI* owner, Subsystem& subsystem) { // Just init the base class Task::Init(owner, subsystem); owner->GetMemory().resolvingMovementBlock = true; if (_blockingEnt == NULL) { DM_LOG(LC_AI, LT_WARNING)LOGSTRING("AI %s cannot resolve a NULL blocking entity.\r", owner->name.c_str()); owner->PushMove(); // grayman #2706 - save movement state, because it gets popped in OnFinish() subsystem.FinishTask(); } // Get the direction we're pushing against _initialAngles = owner->viewAxis.ToAngles(); // Set the TTL for this task _endTime = gameLocal.time + 20000; // 20 seconds // Save the movement state owner->PushMove(); if (_blockingEnt->IsType(idAI::Type)) { //DM_LOG(LC_AI, LT_WARNING)LOGSTRING("AI %s starting to resolve blocking AI: %s\r", owner->name.c_str(), _blockingEnt->name.c_str()); InitBlockingAI(owner, subsystem); } else if (_blockingEnt->IsType(idStaticEntity::Type)) { //DM_LOG(LC_AI, LT_WARNING)LOGSTRING("AI %s starting to resolve static blocking entity: %s\r", owner->name.c_str(), _blockingEnt->name.c_str()); InitBlockingStatic(owner, subsystem); } else { // Unknown entity type, exit task //DM_LOG(LC_AI, LT_WARNING)LOGSTRING("AI %s cannot resolve blocking entity: %s\r", owner->name.c_str(), _blockingEnt->name.c_str()); subsystem.FinishTask(); } }
void PlayAnimationTask::Init(idAI* owner, Subsystem& subsystem) { // Just init the base class Task::Init(owner, subsystem); // Parse animation spawnargs here if (_animName.IsEmpty()) { gameLocal.Warning("%s cannot start PlayAnimationTask with empty animation name.",owner->name.c_str()); subsystem.FinishTask(); } StartAnim(owner); }
void InvestigateSpotTask::Init( idAI *owner, Subsystem &subsystem ) { // Just init the base class Task::Init( owner, subsystem ); // Get a shortcut reference Memory &memory = owner->GetMemory(); // Stop previous moves //owner->StopMove(MOVE_STATUS_DONE); if( memory.currentSearchSpot != idVec3( idMath::INFINITY, idMath::INFINITY, idMath::INFINITY ) ) { // Set the goal position SetNewGoal( memory.currentSearchSpot ); } else { // Invalid hiding spot, terminate task DM_LOG( LC_AI, LT_DEBUG )LOGSTRING( "memory.currentSearchSpot not set to something valid, terminating task.\r" ); subsystem.FinishTask(); } //_exitTime = 0; // grayman #3507 }
void InvestigateSpotTask::Init(idAI* owner, Subsystem& subsystem) { // Just init the base class Task::Init(owner, subsystem); // Get a shortcut reference Memory& memory = owner->GetMemory(); // Stop previous moves //owner->StopMove(MOVE_STATUS_DONE); if (memory.currentSearchSpot != idVec3(idMath::INFINITY, idMath::INFINITY, idMath::INFINITY)) { // Set the goal position SetNewGoal(memory.currentSearchSpot); memory.hidingSpotInvestigationInProgress = true; // grayman #3857 memory.stopHidingSpotInvestigation = false; } else { // Invalid hiding spot, terminate task subsystem.FinishTask(); } // grayman #3857 - Only the first searcher in a search is allowed to investigate // the spot closely. Am I it? if (_investigateClosely) { Search* search = gameLocal.m_searchManager->GetSearch(owner->m_searchID); if (search) { if (search->_searcherCount > 0) { Assignment *assignment = &search->_assignments[0]; // first AI assigned to the search if (assignment->_searcher != owner) { _investigateClosely = false; } } } } if (owner->HasSeenEvidence()) { // Draw weapon, if we haven't already if (!owner->GetAttackFlag(COMBAT_MELEE) && !owner->GetAttackFlag(COMBAT_RANGED)) { if ( ( owner->GetNumRangedWeapons() > 0 ) && !owner->spawnArgs.GetBool("unarmed_ranged","0") ) { owner->DrawWeapon(COMBAT_RANGED); } else if ( ( owner->GetNumMeleeWeapons() > 0 ) && !owner->spawnArgs.GetBool("unarmed_melee","0") ) { owner->DrawWeapon(COMBAT_MELEE); } } } //_exitTime = 0; // grayman #3507 }
void ResolveMovementBlockTask::InitBlockingStatic(idAI* owner, Subsystem& subsystem) { // Get the bounds of the blocking entity and see if there is a way around it idPhysics* blockingPhys = _blockingEnt->GetPhysics(); idBounds blockBounds = blockingPhys->GetAbsBounds(); // grayman #2356 - special case of being stuck inside a func_static, i.e. a rat under a bed that's not monster_clipped idVec3 ownerOrigin = owner->GetPhysics()->GetOrigin(); if (blockBounds.ContainsPoint(ownerOrigin)) { // Try to get out, otherwise you're stuck until your surroundings change. if (owner->movementSubsystem->AttemptToExtricate()) { owner->movementSubsystem->SetBlockedState(ai::MovementSubsystem::EResolvingBlock); // grayman #2706 - stay in EResolvingBlock return; } // oh boy, you're really stuck owner->StopMove(MOVE_STATUS_DONE); owner->AI_BLOCKED = false; owner->AI_DEST_UNREACHABLE = false; subsystem.FinishTask(); return; } blockBounds[0].z = blockBounds[1].z = 0; // Check if there is space to the right of the obstacle idBounds bounds = owner->GetPhysics()->GetBounds(); if (owner->GetAAS() == NULL) { return; } // angua: move the bottom of the bounds up a bit, to avoid finding small objects on the ground that are "in the way" // grayman #2684 - except for AI whose bounding box height is less than maxStepHeight, otherwise applying the bump up // causes the clipmodel to be "upside-down", which isn't good. In that case, give the bottom a bump up equal to half // of the clipmodel's height so it at least gets a small bump. float ht = owner->GetAAS()->GetSettings()->maxStepHeight; if (bounds[0].z + ht < bounds[1].z) { bounds[0].z += ht; } else { bounds[0].z += (bounds[1].z - bounds[0].z)/2.0; } // Set all attachments to nonsolid, temporarily owner->SaveAttachmentContents(); owner->SetAttachmentContents(0); // check if there is a way around idTraceModel trm(bounds); idClipModel clip(trm); idVec3 ownerRight, ownerForward; _initialAngles.ToVectors(&ownerForward, &ownerRight); // Take a point to the right idVec3 testPoint = blockingPhys->GetOrigin(); testPoint.z = ownerOrigin.z; // Move one AAS bounding box size outwards from the model float blockBoundsWidth = blockBounds.GetRadius(blockBounds.GetCenter()); idBounds aasBounds = owner->GetAAS()->GetSettings()->boundingBoxes[0]; aasBounds[0].z = aasBounds[1].z = 0; float aasBoundsWidth = aasBounds.GetRadius(); testPoint += ownerRight * (blockBoundsWidth + aasBoundsWidth); int contents = gameLocal.clip.Contents(testPoint, &clip, mat3_identity, CONTENTS_SOLID, owner); if (cv_ai_debug_blocked.GetBool()) { idVec3 temp = blockingPhys->GetOrigin(); temp.z = ownerOrigin.z; gameRenderWorld->DebugArrow(colorWhite, temp, temp + idVec3(0,0,10), 1, 1000); temp += ownerRight * (blockBoundsWidth + aasBoundsWidth + 5); gameRenderWorld->DebugArrow(colorLtGrey, temp, temp + idVec3(0,0,10), 1, 1000); gameRenderWorld->DebugBounds(contents ? colorRed : colorGreen, bounds, testPoint, 1000); } // grayman #2345 - the point tested might be in the VOID, so let's check for a valid AAS area int areaNum = owner->PointReachableAreaNum(testPoint); if ((contents != 0) || (areaNum == 0)) { // Right side is blocked, look at the left. testPoint = blockingPhys->GetOrigin(); testPoint.z = ownerOrigin.z; testPoint -= ownerRight * (blockBoundsWidth + aasBoundsWidth + 5); contents = gameLocal.clip.Contents(testPoint, &clip, mat3_identity, CONTENTS_SOLID, owner); if (cv_ai_debug_blocked.GetBool()) { gameRenderWorld->DebugBounds(contents ? colorRed : colorGreen, bounds, testPoint, 1000); } areaNum = owner->PointReachableAreaNum(testPoint); // testPoint must not be in the VOID if ((contents != 0) || (areaNum == 0)) { // Neither left nor right has free space // grayman #2345 - before declaring failure, let's try extrication owner->RestoreAttachmentContents(); // AttemptToExtricate() will do an attachment save/restore, so we must restore here first owner->movementSubsystem->AttemptToExtricate(); } else { // Move to left position owner->MoveToPosition(testPoint); owner->RestoreAttachmentContents(); } } else { // Move to right position owner->MoveToPosition(testPoint); owner->RestoreAttachmentContents(); } owner->movementSubsystem->SetBlockedState(ai::MovementSubsystem::EResolvingBlock); // grayman #2706 - stay in EResolvingBlock }