Skip to content

Commit

Permalink
Engineer & MvM Stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
caxanga334 committed Jun 19, 2024
1 parent 1c17888 commit 58c82cf
Show file tree
Hide file tree
Showing 15 changed files with 296 additions and 52 deletions.
30 changes: 26 additions & 4 deletions extension/bot/interfaces/movement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ bool IMovement::IsGap(const Vector& pos, const Vector& forward)
* (ie: blocked by an entity that can be destroyed)
* @return true if the bot can walk, false otherwise
*/
bool IMovement::IsPotentiallyTraversable(const Vector& from, const Vector& to, float& fraction, const bool now)
bool IMovement::IsPotentiallyTraversable(const Vector& from, const Vector& to, float* fraction, const bool now, CBaseEntity** obstacle)
{
float heightdiff = to.z - from.z;

Expand All @@ -482,7 +482,11 @@ bool IMovement::IsPotentiallyTraversable(const Vector& from, const Vector& to, f
along.NormalizeInPlace();
if (along.z > GetTraversableSlopeLimit()) // too high, can't climb this ramp
{
fraction = 0.0f;
if (fraction != nullptr)
{
*fraction = 0.0f;
}

return false;
}
}
Expand Down Expand Up @@ -516,7 +520,15 @@ bool IMovement::IsPotentiallyTraversable(const Vector& from, const Vector& to, f
}
}

fraction = result.fraction;
if (fraction != nullptr)
{
*fraction = result.fraction;
}

if (obstacle != nullptr)
{
*obstacle = result.m_pEnt;
}

return result.fraction >= 1.0f && !result.startsolid;
}
Expand All @@ -525,7 +537,7 @@ bool IMovement::HasPotentialGap(const Vector& from, const Vector& to, float& fra
{
// get movement fraction
float traversableFraction = 0.0f;
IsPotentiallyTraversable(from, to, traversableFraction, true);
IsPotentiallyTraversable(from, to, &traversableFraction, true);

Vector end = from + (to - from) * traversableFraction;
Vector forward = to - from;
Expand Down Expand Up @@ -736,6 +748,16 @@ void IMovement::TryToUnstuck()
}
}

void IMovement::TryToAvoidObstacleInPath(const Vector& from, const Vector& to, const float& fraction, CBaseEntity* obstacle)
{
int index = gamehelpers->EntityToBCompatRef(obstacle);

if (index == 0)
{
return; // worldspawn entity
}
}

void IMovement::StuckMonitor()
{
auto bot = GetBot();
Expand Down
4 changes: 3 additions & 1 deletion extension/bot/interfaces/movement.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class IMovement : public IBotInterface
virtual bool IsAscendingOrDescendingLadder();
virtual bool IsOnLadder(); // true if the bot is on a ladder right now
virtual bool IsGap(const Vector& pos, const Vector& forward);
virtual bool IsPotentiallyTraversable(const Vector& from, const Vector& to, float &fraction, const bool now = true);
virtual bool IsPotentiallyTraversable(const Vector& from, const Vector& to, float* fraction, const bool now = true, CBaseEntity** obstacle = nullptr);
// Checks if there is a possible gap/hole on the ground between 'from' and 'to' vectors
virtual bool HasPotentialGap(const Vector& from, const Vector& to, float& fraction);

Expand All @@ -219,6 +219,8 @@ class IMovement : public IBotInterface
virtual void AdjustPathCrossingPoint(const CNavArea* fromArea, const CNavArea* toArea, const Vector& fromPos, Vector* crosspoint);
// Called when the bot is determined to be stuck, try to unstuck it (IE: jumping)
virtual void TryToUnstuck();
// Called when an obstacle is found between 'from' and 'to'. Try to avoid it (IE: by jumping)
virtual void TryToAvoidObstacleInPath(const Vector& from, const Vector& to, const float& fraction, CBaseEntity* obstacle);

protected:
CountdownTimer m_jumptimer; // Jump timer
Expand Down
17 changes: 11 additions & 6 deletions extension/bot/interfaces/path/meshnavigator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,9 +164,8 @@ void CMeshNavigator::Update(CBaseBot* bot)

if (mover->IsStuck() || to.IsLengthLessThan(CLOSE_RANGE))
{
float fraction;
auto next = GetNextSegment(m_goal);
if (mover->IsStuck() || !next || (next->goal.z - origin.z > mover->GetMaxJumpHeight()) || !mover->IsPotentiallyTraversable(origin, next->goal, fraction))
if (mover->IsStuck() || !next || (next->goal.z - origin.z > mover->GetMaxJumpHeight()) || !mover->IsPotentiallyTraversable(origin, next->goal, nullptr))
{
bot->OnMoveToFailure(this, IEventListener::FAIL_FELL_OFF_PATH);

Expand Down Expand Up @@ -320,7 +319,7 @@ bool CMeshNavigator::IsAtGoal(CBaseBot* bot)

// If it's reachable, then the bot reached it
if (toGoal.z < mover->GetStepHeight() &&
mover->IsPotentiallyTraversable(origin, next->goal, fraction, false) == true &&
mover->IsPotentiallyTraversable(origin, next->goal, &fraction, false) == true &&
mover->HasPotentialGap(origin, next->goal, fraction) == false)
{
return true;
Expand Down Expand Up @@ -419,7 +418,9 @@ const CBasePathSegment* CMeshNavigator::CheckSkipPath(CBaseBot* bot, const CBase
}

float fraction;
if (mover->IsPotentiallyTraversable(origin, next->goal, fraction, false) && mover->HasPotentialGap(origin, next->goal, fraction) == false)
CBaseEntity* obstacle = nullptr;
bool IsPotentiallyTraversable = mover->IsPotentiallyTraversable(origin, next->goal, &fraction, false, &obstacle);
if (IsPotentiallyTraversable && mover->HasPotentialGap(origin, next->goal, fraction) == false)
{
// only skip a segment if the bot is able to move directly to it from it's current position
// and there isn't any holes on the ground
Expand All @@ -434,6 +435,11 @@ const CBasePathSegment* CMeshNavigator::CheckSkipPath(CBaseBot* bot, const CBase
}
else
{
if (!IsPotentiallyTraversable && obstacle != nullptr)
{
mover->TryToAvoidObstacleInPath(origin, next->goal, fraction, obstacle);
}

break; // unreachable, just keep following the path
}
}
Expand Down Expand Up @@ -566,10 +572,9 @@ bool CMeshNavigator::Climbing(CBaseBot* bot, const CBasePathSegment* segment, co

Vector toGoal = m_goal->goal - origin;
toGoal.NormalizeInPlace();
float fraction = 0.0f;

if (toGoal.z < mover->GetTraversableSlopeLimit() && m_goal->type != AIPath::SegmentType::SEGMENT_CLIMB_UP &&
mover->IsPotentiallyTraversable(origin, origin * ledgeLookAheadDist * toGoal, fraction, true))
mover->IsPotentiallyTraversable(origin, origin * ledgeLookAheadDist * toGoal, nullptr, true))
{
return false;
}
Expand Down
125 changes: 122 additions & 3 deletions extension/bot/tf2/tasks/engineer/tf2bot_engineer_nest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@
#include "tf2bot_engineer_upgrade_object.h"
#include "tf2bot_engineer_nest.h"

static ConVar c_navbot_tf_engineer_tele_entrance_build_range("sm_navbot_tf_engineer_teleentrance_build_range", "3000.0", FCVAR_GAMEDLL, "Maximum distance the engineer will build a teleporter entrance.");
static ConVar c_navbot_tf_engineer_tele_entrance_build_range("sm_navbot_tf_engineer_teleentrance_build_range", "2048.0", FCVAR_GAMEDLL, "Maximum distance the engineer will build a teleporter entrance.");

static ConVar c_navbot_tf_engineer_tele_exit_build_range("sm_navbot_tf_engineer_teleexit_build_range", "1200.0", FCVAR_GAMEDLL, "Maximum distance the tele exit should be from the sentry gun.");

class EngineerBuildableLocationCollector : public INavAreaCollector<CTFNavArea>
{
Expand All @@ -27,6 +29,20 @@ class EngineerBuildableLocationCollector : public INavAreaCollector<CTFNavArea>
CTF2Bot* m_me;
};

inline static Vector GetSpotBehindSentry(edict_t* sentry)
{
tfentities::HBaseObject sentrygun(sentry);
Vector origin = sentrygun.GetAbsOrigin();
QAngle angle = sentrygun.GetAbsAngles();
Vector forward;

AngleVectors(angle, &forward);
forward.NormalizeInPlace();

Vector point = (origin - (forward * CTF2BotEngineerNestTask::behind_sentry_distance()));
return point;
}

bool EngineerBuildableLocationCollector::ShouldCollect(CTFNavArea* area)
{
if (!area->IsBuildable())
Expand All @@ -53,6 +69,25 @@ TaskResult<CTF2Bot> CTF2BotEngineerNestTask::OnTaskUpdate(CTF2Bot* bot)
return PauseFor(nextTask, "Taking care of my own nest!");
}

/* TO-DO:
* Check if buildings are still useful, if not, move them
*/

// At this point, the bot has fully upgraded everything, time to idle near the sentry

m_goal = GetSpotBehindSentry(bot->GetMySentryGun());

if (bot->GetRangeTo(m_goal) > 32.0f)
{
if (!m_nav.IsValid() || m_nav.GetAge() > 3.0f)
{
CTF2BotPathCost cost(bot);
m_nav.ComputePathToPosition(bot, m_goal, cost);
}

m_nav.Update(bot);
}

return Continue();
}

Expand All @@ -69,6 +104,10 @@ TaskResult<CTF2Bot> CTF2BotEngineerNestTask::OnTaskResume(CTF2Bot* bot, AITask<C

TaskEventResponseResult<CTF2Bot> CTF2BotEngineerNestTask::OnMoveToFailure(CTF2Bot* bot, CPath* path, IEventListener::MovementFailureType reason)
{
m_nav.Invalidate();
CTF2BotPathCost cost(bot);
m_nav.ComputePathToPosition(bot, m_goal, cost);

return TryContinue();
}

Expand Down Expand Up @@ -106,6 +145,15 @@ AITask<CTF2Bot>* CTF2BotEngineerNestTask::NestTask(CTF2Bot* me)
return new CTF2BotEngineerBuildObjectTask(CTF2BotEngineerBuildObjectTask::OBJECT_DISPENSER, goal);
}
}
else if (me->GetMyTeleporterExit() == nullptr)
{
Vector goal;

if (FindSpotToBuildTeleExit(me, goal))
{
return new CTF2BotEngineerBuildObjectTask(CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_EXIT, goal);
}
}

if (me->GetMySentryGun() != nullptr)
{
Expand All @@ -127,6 +175,17 @@ AITask<CTF2Bot>* CTF2BotEngineerNestTask::NestTask(CTF2Bot* me)
}
}

// For now we assume the exit is closer to the bot
if (me->GetMyTeleporterExit() != nullptr)
{
tfentities::HBaseObject exit(me->GetMyTeleporterExit());

if (!exit.IsAtMaxLevel())
{
return new CTF2BotEngineerUpgradeObjectTask(gamehelpers->ReferenceToEntity(exit.GetIndex()));
}
}

return nullptr;
}

Expand Down Expand Up @@ -154,7 +213,8 @@ bool CTF2BotEngineerNestTask::FindSpotToBuildDispenser(CTF2Bot* me, Vector& out)
AngleVectors(angle, &forward);
forward.NormalizeInPlace();

Vector point = (origin - (forward * behind_sentry_distance()));
static constexpr auto DISPENSER_OFFSET = 32.0f;
Vector point = (origin - (forward * (behind_sentry_distance() + DISPENSER_OFFSET)));
trace::CTraceFilterNoNPCsOrPlayers filter(me->GetEntity(), COLLISION_GROUP_NONE);
Vector mins(-36.0f, -36.0f, 0.0f);
Vector maxs(36.0f, 36.0f, 84.0f);
Expand Down Expand Up @@ -248,7 +308,66 @@ bool CTF2BotEngineerNestTask::FindSpotToBuildTeleEntrance(CTF2Bot* me, Vector& o

bool CTF2BotEngineerNestTask::FindSpotToBuildTeleExit(CTF2Bot* me, Vector& out)
{
return false;
edict_t* mysentry = me->GetMySentryGun();

if (mysentry == nullptr)
{
// Must build sentry first
return false;
}

tfentities::HBaseObject sentrygun(mysentry);
Vector origin = sentrygun.GetAbsOrigin();

CNavArea* start = TheNavMesh->GetNearestNavArea(origin, 512.0f, false, false);

if (start == nullptr)
{
return false;
}

EngineerBuildableLocationCollector collector(me, static_cast<CTFNavArea*>(start));

collector.SetTravelLimit(c_navbot_tf_engineer_tele_exit_build_range.GetFloat());
collector.Execute();

if (collector.IsCollectedAreasEmpty())
{
return false;
}

auto& areas = collector.GetCollectedAreas();

CTFNavArea* buildGoal = nullptr;
std::vector<CTFNavArea*> hintAreas;
hintAreas.reserve(32);

for (auto tfarea : areas)
{
if (tfarea->HasTFAttributes(CTFNavArea::TFNAV_TELE_EXIT_HINT) && !tfarea->IsTFAttributesRestrictedForTeam(me->GetMyTFTeam()))
{
hintAreas.push_back(tfarea);
}
}

if (hintAreas.empty())
{
// no hints were found, pick a random one
buildGoal = areas[randomgen->GetRandomInt<size_t>(0, areas.size() - 1)];
}
else
{
buildGoal = hintAreas[randomgen->GetRandomInt<size_t>(0, hintAreas.size() - 1)];
}

out = buildGoal->GetRandomPoint();

if (me->IsDebugging(BOTDEBUG_TASKS))
{
buildGoal->DrawFilled(0, 128, 0, 255, 5.0f, true);
}

return true;
}

bool CTF2BotEngineerNestTask::GetRandomSentrySpot(CTF2Bot* me, Vector& out)
Expand Down
12 changes: 6 additions & 6 deletions extension/bot/tf2/tasks/engineer/tf2bot_engineer_nest.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ class CTF2BotEngineerNestTask : public AITask<CTF2Bot>
TaskEventResponseResult<CTF2Bot> OnMoveToFailure(CTF2Bot* bot, CPath* path, IEventListener::MovementFailureType reason) override;
TaskEventResponseResult<CTF2Bot> OnMoveToSuccess(CTF2Bot* bot, CPath* path) override;

const char* GetName() const override { return "EngineerNest"; }

// Engineers don't retreat for health and ammo
QueryAnswerType ShouldRetreat(CBaseBot* me) override { return ANSWER_NO; }

const char* GetName() const override { return "EngineerNest"; }

static constexpr auto max_travel_distance() { return 2048.0f; }
static constexpr auto behind_sentry_distance() { return 96.0f; }
static constexpr auto max_dispenser_to_sentry_range() { return 750.0f; }
private:
CMeshNavigator m_nav;
Vector m_goal;
Expand All @@ -37,10 +41,6 @@ class CTF2BotEngineerNestTask : public AITask<CTF2Bot>
bool FindSpotToBuildTeleExit(CTF2Bot* me, Vector& out);
bool GetRandomSentrySpot(CTF2Bot* me, Vector& out);
bool GetRandomDispenserSpot(CTF2Bot* me, const Vector& start, Vector& out);

static constexpr auto max_travel_distance() { return 2048.0f; }
static constexpr auto behind_sentry_distance() { return 200.0f; }
static constexpr auto max_dispenser_to_sentry_range() { return 750.0f; }
};

#endif // !NAVBOT_TF2BOT_TASKS_ENGINEER_NEST_H_
10 changes: 10 additions & 0 deletions extension/bot/tf2/tasks/scenario/mvm/tf2bot_mvm_idle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <mods/tf2/nav/tfnavmesh.h>
#include <mods/tf2/nav/tfnavarea.h>
#include <bot/tf2/tf2bot.h>
#include <bot/tf2/tasks/engineer/tf2bot_engineer_main.h>
#include <bot/tf2/tasks/medic/tf2bot_medic_main_task.h>
#include "tf2bot_mvm_upgrade.h"
#include "tf2bot_mvm_idle.h"

Expand All @@ -32,6 +34,14 @@ TaskResult<CTF2Bot> CTF2BotMvMIdleTask::OnTaskUpdate(CTF2Bot* bot)
// Buy upgrades
return PauseFor(new CTF2BotMvMUpgradeTask, "Going to use an upgrade station!");
}
else if (bot->GetMyClassType() == TeamFortress2::TFClass_Engineer)
{
return SwitchTo(new CTF2BotEngineerMainTask, "Starting engineer behavior!");
}
else if (bot->GetMyClassType() == TeamFortress2::TFClass_Medic)
{
return SwitchTo(new CTF2BotMedicMainTask, "Starting medic behavior!");
}

if (bot->GetBehaviorInterface()->IsReady(bot) == ANSWER_YES)
{
Expand Down
Loading

0 comments on commit 58c82cf

Please sign in to comment.