EventDesiredResult<CTFBot> CTFBotMedicRetreat::OnMoveToFailure(CTFBot *actor, const Path *path, MoveToFailureType fail)
{
	CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
	this->m_PathFollower.Compute(actor, actor->m_HomeArea.GetCenter(), cost_func, 0.0f, true);
	
	return EventDesiredResult<CTFBot>::Continue();
}
EventDesiredResult<CTFBot> CTFBotMedicRetreat::OnStuck(CTFBot *actor)
{
	CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
	this->m_PathFollower.Compute(actor, actor->m_HomeArea.GetCenter(), cost_func, 0.0f, true);
	
	return EventDesiredResult<CTFBot>::Continue();
}
Exemple #3
0
	ActionResult<CTFBot> CTFBotMarkGiants::Update(CTFBot *actor, float dt)
	{
		if (this->m_hTarget == nullptr || !this->m_hTarget->IsAlive()) {
			return ActionResult<CTFBot>::Done("Mark target is no longer valid.");
		}
		
		if (!IsPlayerMarkable(actor, this->m_hTarget)) {
			return ActionResult<CTFBot>::Done("Mark target is no longer markable.");
		}
		
		auto nextbot = rtti_cast<INextBot *>(actor);
		
		if (this->m_ctRecomputePath.IsElapsed()) {
			this->m_ctRecomputePath.Start(RandomFloat(0.4f, 0.6f));
			
			CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
			this->m_PathFollower.Compute(nextbot, this->m_hTarget->GetAbsOrigin(), cost_func, 0.0f, true);
			
			// TODO: handle Path::Compute failure
		}
		
		float dist_to_target = (actor->GetAbsOrigin() - this->m_hTarget->GetAbsOrigin()).Length();
		if (dist_to_target < 512.0f) {
			actor->GetBodyInterface()->AimHeadTowards(this->m_hTarget->WorldSpaceCenter(),
				IBody::LookAtPriorityType::CRITICAL, 0.1f, nullptr, "Look at our mark-for-death target");
		}
		
		if (dist_to_target > actor->GetDesiredAttackRange()) {
			this->m_PathFollower.Update(nextbot);
		}
		
		return ActionResult<CTFBot>::Continue();
	}
ActionResult<CTFBot> CTFBotMedicRetreat::OnResume(CTFBot *actor, Action<CTFBot> *action)
{
	CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
	this->m_PathFollower.Compute(actor, actor->m_HomeArea.GetCenter(), cost_func, 0.0f, true);
	
	return ActionResult<CTFBot>::Continue();
}
Exemple #5
0
int grow_vertex(int *c, int m,
		 int *movement,
		 int min_bound, int max_bound,
		 double (*cost_func)(int *)){
  
  int changeflag = 1;
  int i,count=0;
  double cost = cost_func(c);

  while(changeflag){
    changeflag=0;
    for(i=0;i<m;i++){
      if(movement[i]){
	c[i] += movement[i];
	double test_cost = lift_cost(c);
	if(test_cost>cost){
	  changeflag=1;
	  cost=test_cost;
	  count++;
	}else{
	  c[i] -= movement[i];
	}
      }
    }
  }

  return count;
}
ActionResult<CTFBot> CTFBotEscort::Update(CTFBot *actor, float dt)
{
	const CKnownEntity *threat = actor->GetVisionInterface()->GetPrimaryKnownThreat(false);
	if (threat != nullptr && threat->IsVisibleInFOVNow()) {
		return ActionResult<CTFBot>::SuspendFor(new CTFBotAttack(),
			"Attacking nearby threat");
	}
	
	if (this->m_hWho != nullptr) {
		if (actor->IsRangeGreaterThan(this->m_hWho, tf_bot_escort_range.GetFloat())) {
			if (this->m_ctRecomputePath.IsElapsed()) {
				CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
				this->m_PathFollower.Compute(actor, this->m_hWho, cost_func, 0.0f, true);
				
				this->m_ctRecomputePath.Start(RandomFloat(2.0f, 3.0f));
			}
			
			this->m_PathFollower.Update(actor);
		} else if (CTFBotPrepareStickybombTrap::IsPossible(actor)) {
			return ActionResult<CTFBot>::SuspendFor(new CTFBotPrepareStickybombTrap(),
				"Laying sticky bombs!");
		}
	}
	
	if (actor->m_hTargetSentry != nullptr && CTFBotDestroyEnemySentry::IsPossible(actor)) {
		return ActionResult<CTFBot>::SuspendFor(new CTFBotDestroyEnemySentry(),
			"Going after an enemy sentry to destroy it");
	}
	
	return ActionResult<CTFBot>::Continue();
}
		virtual ActionResult<CTFBot> Update(CTFBot *actor, float dt) override
		{
			TRACE("[this: %08x] [actor: #%d]", (uintptr_t)this, ENTINDEX(actor));
			
			if (this->m_hHint == nullptr) {
				return ActionResult<CTFBot>::Done("No hint entity");
			}
			
			INextBot *nextbot = rtti_cast<INextBot *>(actor);
			
			if (nextbot->IsRangeGreaterThan(this->m_hHint->GetAbsOrigin(), 25.0f)) {
				TRACE_MSG("range_to_hint > 25: pathing\n");
				
				if (this->m_ctRecomputePath.IsElapsed()) {
					TRACE_MSG("recomputing path\n");
					
					this->m_ctRecomputePath.Start(RandomFloat(1.0f, 2.0f));
					
					CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
					this->m_PathFollower.Compute(nextbot, this->m_hHint->GetAbsOrigin(), cost_func, 0.0f, true);
				}
				
				this->m_PathFollower.Update(nextbot);
				if (!this->m_PathFollower.IsValid()) {
					return ActionResult<CTFBot>::Done("Path failed");
				}
				
				return ActionResult<CTFBot>::Continue();
			}
			
			TRACE_MSG("at hint: creating dispenser entity\n");
			
			CBaseEntity *ent = CreateEntityByName("obj_dispenser");
			if (ent == nullptr) {
				return ActionResult<CTFBot>::Done("Couldn't create entity");
			}
			
			auto dispenser = rtti_cast<CObjectDispenser *>(ent);
			dispenser->SetName(this->m_hHint->GetEntityName());
			dispenser->m_nDefaultUpgradeLevel = 2;
			dispenser->SetAbsOrigin(this->m_hHint->GetAbsOrigin());
			dispenser->SetAbsAngles(this->m_hHint->GetAbsAngles());
			dispenser->Spawn();
			
			dispenser->StartPlacement(actor);
			
			suppress_speak = true;
			dispenser->StartBuilding(actor);
			suppress_speak = false;
			
			this->m_hHint->SetOwnerEntity(dispenser);
			
			actor->SpeakConceptIfAllowed(MP_CONCEPT_BUILDING_OBJECT, "objtype:dispenser");
			
			return ActionResult<CTFBot>::Done("Built a dispenser");
		}
ActionResult<CTFBot> CTFBotMedicRetreat::OnStart(CTFBot *actor, Action<CTFBot> *action)
{
	if (actor->m_HomeArea == nullptr) {
		return ActionResult<CTFBot>::Done("No home area!");
	}
	
	CTFBotPathCost cost_func(actor, FASTEST_ROUTE);
	this->m_PathFollower.Compute(actor, actor->m_HomeArea.GetCenter(), cost_func, 0.0f, true);
	
	return ActionResult<CTFBot>::Continue();
}
Exemple #9
0
double gradient_walk(int *c, int m,
		     int min_bound, int max_bound,
		     double (*cost_func)(int *)){
  
  int last_change = m-1;
  int cur_dim = 0;
  double cost = cost_func(c);

  while(1){
    double val = c[cur_dim];
    c[cur_dim] = val+1;
    double up_cost = lift_cost(c);
    c[cur_dim] = val-1;
    double down_cost = lift_cost(c);

    if(up_cost<cost && val+1 <= max_bound){

      c[cur_dim] = val+1;
      last_change = cur_dim;
      cost = up_cost;
      
    }else if (down_cost<cost && val-1 >= min_bound){

      c[cur_dim] = val-1;
      last_change = cur_dim;
      cost = down_cost;
      
    }else{

      c[cur_dim] = val;
      if(cur_dim == last_change)break;

    }

    cur_dim++;
    if(cur_dim >= m) cur_dim = 0;

  }

  return cost;
}
ActionResult<CTFBot> CTFBotMeleeAttack::Update(CTFBot *actor, float dt)
{
	const CKnownEntity *threat = actor->GetPrimaryKnownThreat(false);
	if (threat == nullptr) {
		return ActionResult<CTFBot>::Done("No threat");
	}
	
	if ((threat->GetLastKnownPosition() - actor->GetAbsOrigin()).LengthSqr() > Square(this->m_flAbandonRange)) {
		return ActionResult<CTFBot>::Done("Threat is too far away for a melee attack");
	}
	
	CBaseCombatWeapon *melee = actor->Weapon_GetSlot(2);
	if (melee != nullptr) {
		actor->Weapon_Switch(melee);
	}
	
	actor->PressFireButton();
	
	CTFBotCostFunc cost_func(actor, FASTEST_ROUTE);
	this->m_ChasePath.Update(actor, threat->GetEntity(), cost_func, nullptr);
	
	return ActionResult<CTFBot>::Continue();
}
ActionResult<CTFBot> CTFBotAttack::Update(CTFBot *actor, float dt)
{
	bool is_melee = false;
	
	CTFWeaponBase *weapon = actor->GetActiveTFWeapon();
	if (weapon != nullptr) {
		if (weapon->IsWeapon(TF_WEAPON_FLAMETHROWER) || weapon->IsMeleeWeapon()) {
			is_melee = true;
		}
	}
	
	const CKnownEntity *threat = actor->GetVisionInterface()->GetPrimaryKnownThreat();
	if (threat == nullptr || threat->IsObsolete() || actor->GetIntentionInterface()->ShouldAttack(actor, threat) == QueryResponse::NO) {
		return ActionResult<CTFBot>::Done("No threat");
	}
	
	actor->EquipBestWeaponForThreat(threat);
	
	if (is_melee && threat->IsVisibleRecently() && actor->IsRangeLessThan(threat->GetLastKnownPosition(),
		1.1f * actor->GetDesiredAttackRange())) {
		if (actor->TransientlyConsistentRandomValue(3.0f, 0) < 0.5f) {
			actor->PressLeftButton();
		} else {
			actor->PressRightButton();
		}
	}
	
	if (threat->IsVisibleRecently() && !actor->IsRangeGreaterThan(threat->GetEntity()->GetAbsOrigin(),
		actor->GetDesiredAttackRange()) && actor->IsLineOfFireClear(threat->GetEntity()->EyePosition())) {
		return ActionResult<CTFBot>::Continue();
	}
	
	if (threat->IsVisibleRecently()) {
		CTFBotPathCost cost_func(actor, (is_melee && TFGameRules()->IsMannVsMachineMode() ? SAFEST_ROUTE : DEFAULT_ROUTE));
		this->m_ChasePath.Update(actor, threat->GetEntity(), cost_func, nullptr);
		
		return ActionResult<CTFBot>::Continue();
	}
	
	this->m_ChasePath.Invalidate();
	
	if (actor->IsRangeLessThan(threat->GetLastKnownPosition(), 20.0f)) {
		actor->GetVisionInterface()->ForgetEntity(threat->GetEntity());
		
		return ActionResult<CTFBot>::Done("I lost my target!");
	}
	
	if (actor->IsRangeLessThan(threat->GetLastKnownPosition(), actor->GetMaxAttackRange())) {
		// HumanEyeHeight = 62.0f, from nav.h; value is from CS:S and is actually a bit wrong for TF2
		Vector eye = threat->GetLastKnownPosition() + Vector(0.0f, 0.0f, HumanEyeHeight);
		
		actor->GetBodyInterface()->AimHeadTowards(eye, IBody::LookAtPriorityType::IMPORTANT, 0.2f, nullptr, "Looking towards where we lost sight of our victim");
	}
	
	this->m_PathFollower.Update(actor);
	
	if (this->m_ctRecomputePath.IsElapsed()) {
		this->m_ctRecomputePath.Start(RandomFloat(3.0f, 5.0f));
		
		CTFBotPathCost cost_func(actor, (is_melee && TFGameRules()->IsMannVsMachineMode() ? SAFEST_ROUTE : DEFAULT_ROUTE));
		this->m_PathFollower.Compute(actor, threat->GetLastKnownPosition(), cost_func, 0.0f, true);
		
		return ActionResult<CTFBot>::Continue();
	}
}
ActionResult<CTFBot> CTFBotMvMEngineerBuildSentryGun::Update(CTFBot *actor, float dt)
{
	if (this->m_hintEntity == nullptr) {
		return ActionResult<CTFBot>::Done("No hint entity");
	}
	
	float range_to_hint = actor->GetRangeTo(this->m_hintEntity->GetAbsOrigin());
	
	if (range_to_hint < 200.0f) {
		actor->PressCrouchButton();
		actor->GetBodyInterface()->AimHeadTowards(this->m_hintEntity->GetAbsOrigin(),
			IBody::LookAtPriorityType::OVERRIDE_ALL, 0.1f, nullptr, "Placing sentry");
	}
	
	if (range_to_hint > 25.0f) {
		if (this->m_ctRecomputePath.IsElapsed()) {
			this->m_ctRecomputePath.Start(RandomFloat(1.0f, 2.0f));
			
			CTFBotPathCost cost_func(actor, SAFEST_ROUTE);
			this->m_PathFollower.Compute<CTFBotPathCost>(actor,
				this->m_hintEntity->GetAbsOrigin(), cost_func, 0.0f, true);
		}
		
		this->m_PathFollower.Update(actor);
		if (!this->m_PathFollower.IsValid()) {
			/* BUG: one path failure ends the entire behavior...
			 * could this be why engiebots sometimes zone out? */
			return ActionResult<CTFBot>::Done("Path failed");
		}
		
		return ActionResult<CTFBot>::Continue();
	}
	
	if (!this->m_ctPushAway.HasStarted()) {
		this->m_ctPushAway.Start(0.1f);
		
		if (this->m_hintEntity != nullptr) {
			TFGameRules()->PushAllPlayersAway(this->m_hintEntity->GetAbsOrigin(),
				400.0f, 500.0f, TF_TEAM_RED, nullptr);
		}
		
		return ActionResult<CTFBot>::Continue();
	}
	
	if (!this->m_ctPushAway.IsElapsed()) {
		return ActionResult<CTFBot>::Continue();
	}
	
	actor->DetonateObjectOfType(OBJ_SENTRYGUN, 0, true);
	
	CBaseEntity *ent = CreateEntityByName("obj_sentrygun");
	if (ent == nullptr) {
		/* BUG: no we didn't */
		return ActionResult<CTFBot>::Done("Built a sentry");
	}
	
	this->m_hSentry = static_cast<CObjectSentrygun *>(ent);
	this->m_hSentry->SetName(this->m_hintEntity->GetEntityName());
	
	// TODO:
	// ++this->m_hintEntity->dword_0x370
	
	this->m_hSentry->m_nDefaultUpgradeLevel = 2;
	
	this->m_hSentry->SetAbsOrigin(this->m_hintEntity->GetAbsOrigin());
	this->m_hSentry->SetAbsAngles(this->m_hintEntity->GetAbsAngles());
	this->m_hSentry->Spawn();
	
	this->m_hSentry->StartPlacement(actor);
	this->m_hSentry->StartBuilding(actor);
	
	this->m_hintEntity->SetOwnerEntity(this->m_hSentry);
	
	this->m_hSentry = nullptr;
	return ActionResult<CTFBot>::Done("Built a sentry");
}
ActionResult<CTFBot> CTFBotCapturePoint::Update(CTFBot *actor, float dt)
{
	if (TFGameRules()->InSetup()) {
		this->m_PathFollower.Invalidate();
		this->m_ctRecomputePath.Start(RandomFloat(1.0f, 2.0f));
		
		return ActionResult<CTFBot>::Continue();
	}
	
	CTeamControlPoint *point = actor->GetMyControlPoint();
	if (point == nullptr) {
		return ActionResult<CTFBot>::SuspendFor(new CTFBotSeekAndDestroy(10.0f),
			"Seek and destroy until a point becomes available");
	}
	
	if (point->GetTeamNumber() == actor->GetTeamNumber()) {
		return ActionResult<CTFBot>::ChangeTo(new CTFBotDefendPoint(),
			"We need to defend our point(s)");
	}
	
	const CKnownEntity *threat = actor->GetVisionInterface()->GetPrimaryKnownThreat(false);
	if (threat != nullptr && threat->IsVisibleRecently()) {
		actor->EquipBestWeaponForThreat(threat);
	}
	
	if ((!actor->IsPointBeingCaptured(point) || actor->GetTimeSinceWeaponFired() < 2.0f) &&
		!actor->IsCapturingPoint() && !TFGameRules()->InOvertime() &&
		actor->GetTimeLeftToCapture() >= tf_bot_offense_must_push_time.GetFloat() &&
		!TFGameRules()->IsInTraining() && !actor->IsNearPoint(point) &&
		threat != nullptr && threat->IsVisibleRecently()) {
		float duration = RandomFloat(tf_bot_capture_seek_and_destroy_min_duration.GetFloat(),
			tf_bot_capture_seek_and_destroy_max_duration.GetFloat());
		
		return ActionResult<CTFBot>::SuspendFor(new CTFBotSeekAndDestroy(duration),
			"Too early to capture - hunting");
	}
	
	if (actor->IsCapturingPoint()) {
		if (point->GetPointIndex() > 7) {
			return ActionResult<CTFBot>::Continue();
		}
		
		// TODO
		
		// ...
		
		// Path::Compute
	}
	
	if (this->m_ctRecomputePath.IsElapsed()) {
		VPROF_BUDGET("CTFBotCapturePoint::Update( repath )", "NextBot");
		
		CTFBotPathCost cost_func(actor, SAFEST_ROUTE);
		this->m_PathFollower.Compute(actor, point->GetAbsOrigin(), cost_func, 0.0f, true);
		
		this->m_ctRecomputePath.Start(RandomFloat(2.0f, 3.0f));
	}
	
	if (TFGameRules()->IsInTraining() && !actor->IsAnyPointBeingCaptured() &&
		this->m_PathFollower.GetLength() < 1000.0f) {
		actor->SpeakConceptIfAllowed(MP_CONCEPT_PLAYER_GO);
	} else {
		this->m_PathFollower.Update(actor);
	}
	
	return ActionResult<CTFBot>::Continue();
}
		virtual ActionResult<CTFBot> Update(CTFBot *actor, float dt) override
		{
			TRACE("[this: %08x] [actor: #%d]", (uintptr_t)this, ENTINDEX(actor));
			
			if (this->m_hHint == nullptr) {
				return ActionResult<CTFBot>::Done("No hint entity");
			}
			
			INextBot *nextbot = rtti_cast<INextBot *>(actor);
			
			float range_to_hint = nextbot->GetRangeTo(this->m_hHint->GetAbsOrigin());
			
			if (range_to_hint < 200.0f) {
				TRACE_MSG("range_to_hint < 200: crouching/aiming\n");
				actor->PressCrouchButton();
				actor->GetBodyInterface()->AimHeadTowards(this->m_hHint->GetAbsOrigin(),
					IBody::LookAtPriorityType::OVERRIDE_ALL, 0.1f, nullptr, "Placing dispenser");
				
				if (!this->m_bNearHint) {
					this->m_bNearHint = true;
					//TFGameRules()->VoiceCommand(actor, 1, 4);
					//actor->SpeakConceptIfAllowed(MP_CONCEPT_PLAYER_DISPENSERHERE);
				}
			} else {
				this->m_bNearHint = false;
			}
			
			if (range_to_hint > 25.0f) {
				TRACE_MSG("range_to_hint > 25: pathing\n");
				
				if (this->m_ctRecomputePath.IsElapsed()) {
					TRACE_MSG("recomputing path\n");
					
					this->m_ctRecomputePath.Start(RandomFloat(1.0f, 2.0f));
					
					CTFBotPathCost cost_func(actor, SAFEST_ROUTE);
					this->m_PathFollower.Compute(nextbot, this->m_hHint->GetAbsOrigin(), cost_func, 0.0f, true);
				}
				
				this->m_PathFollower.Update(nextbot);
				if (!this->m_PathFollower.IsValid()) {
					return ActionResult<CTFBot>::Done("Path failed");
				}
				
				return ActionResult<CTFBot>::Continue();
			}
			
			TRACE_MSG("at hint: creating dispenser entity\n");
			
			CBaseEntity *ent = CreateEntityByName("obj_dispenser");
			if (ent == nullptr) {
				return ActionResult<CTFBot>::Done("Couldn't create entity");
			}
			
			// TODO: increment hint dword 0x370 (not important for mvm)
			
			auto dispenser = rtti_cast<CObjectDispenser *>(ent);
			dispenser->SetName(this->m_hHint->GetEntityName());
			dispenser->m_nDefaultUpgradeLevel = 2;
			dispenser->SetAbsOrigin(this->m_hHint->GetAbsOrigin());
			dispenser->SetAbsAngles(this->m_hHint->GetAbsAngles());
			dispenser->Spawn();
			
			dispenser->StartPlacement(actor);
			
			suppress_speak = true;
			dispenser->StartBuilding(actor);
			suppress_speak = false;
			
			this->m_hHint->SetOwnerEntity(dispenser);
			
			actor->SpeakConceptIfAllowed(MP_CONCEPT_BUILDING_OBJECT, "objtype:dispenser");
			
			return ActionResult<CTFBot>::Done("Built a dispenser");
		}