Skip to content

Commit

Permalink
Begin Engineer Behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
caxanga334 committed Jun 14, 2024
1 parent 8a459d1 commit db24b3b
Show file tree
Hide file tree
Showing 45 changed files with 1,690 additions and 169 deletions.
7 changes: 6 additions & 1 deletion extension/AMBuilder
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ sourceFiles = [
'util/librandom.cpp',
'util/prediction.cpp',
'util/ehandle_edict.cpp',
'util/sdkcalls.cpp',
# Base Bot stuff
'bot/interfaces/base_interface.cpp',
'bot/interfaces/behavior.cpp',
Expand Down Expand Up @@ -69,14 +70,18 @@ sourceFiles = [
'bot/tf2/tf2bot_upgrades.cpp',
'bot/tf2/tasks/tf2bot_maintask.cpp',
'bot/tf2/tasks/tf2bot_tactical.cpp',
'bot/tf2/tasks/tf2bot_scenario.cpp',
'bot/tf2/tasks/tf2bot_find_health_task.cpp',
'bot/tf2/tasks/tf2bot_find_ammo_task.cpp',
'bot/tf2/tasks/tf2bot_roam.cpp',
'bot/tf2/tasks/general/tf2bot_collect_item.cpp',
'bot/tf2/tasks/general/tf2bot_follow_entity.cpp',
'bot/tf2/tasks/medic/tf2bot_medic_main_task.cpp',
'bot/tf2/tasks/medic/tf2bot_medic_retreat_task.cpp',
'bot/tf2/tasks/engineer/tf2bot_engineer_main.cpp',
'bot/tf2/tasks/engineer/tf2bot_engineer_nest.cpp',
'bot/tf2/tasks/engineer/tf2bot_engineer_build_object.cpp',
'bot/tf2/tasks/engineer/tf2bot_engineer_repair_object.cpp',
'bot/tf2/tasks/engineer/tf2bot_engineer_upgrade_object.cpp',
'bot/tf2/tasks/scenario/tf2bot_map_ctf.cpp',
'bot/tf2/tasks/scenario/mvm/tf2bot_mvm_idle.cpp',
'bot/tf2/tasks/scenario/mvm/tf2bot_mvm_upgrade.cpp',
Expand Down
2 changes: 2 additions & 0 deletions extension/bot/basebot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <util/helpers.h>
#include <util/entprops.h>
#include <util/librandom.h>
#include <util/sdkcalls.h>
#include <bot/interfaces/base_interface.h>
#include <bot/interfaces/knownentity.h>
#include <bot/interfaces/playerinput.h>
Expand Down Expand Up @@ -685,3 +686,4 @@ const CBotWeapon* CBaseBot::GetActiveBotWeapon() const

return nullptr;
}

12 changes: 10 additions & 2 deletions extension/bot/interfaces/path/basepath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -703,13 +703,21 @@ bool CPath::ProcessSpecialLinksInPath(CBaseBot* bot, CBasePathSegment* from, CBa
auto between = CreateNewSegment();

between->CopySegment(from);
between->goal = link->GetPosition();
between->goal = link->GetStart();
between->how = GO_SPECIAL_LINK;
between->type = AIPath::SEGMENT_GROUND;
// add a segments between from and to.
// the bot will go to from, them move to between and then move to to.
// between goal is the special link position on the nav area.

auto post = CreateNewSegment();

post->CopySegment(between);
post->how = GO_SPECIAL_LINK;
post->goal = link->GetEnd();
post->type = AIPath::SEGMENT_GROUND;

pathinsert.emplace(to, post, false);
pathinsert.emplace(to, between, false); // insert before 'to'
break;
}
Expand All @@ -724,7 +732,7 @@ bool CPath::ProcessSpecialLinksInPath(CBaseBot* bot, CBasePathSegment* from, CBa
auto between = CreateNewSegment();

between->CopySegment(from);
between->goal = link->GetPosition();
between->goal = link->GetStart();
between->how = GO_SPECIAL_LINK;
between->type = AIPath::SEGMENT_GROUND;
// add a segments between from and to.
Expand Down
3 changes: 3 additions & 0 deletions extension/bot/interfaces/playercontrol.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class IPlayerController : public IBotInterface, public IPlayerInput
LOOK_DANGER, // Something dangerous
LOOK_OPERATE, // Operating a machine, buttons, levers, etc
LOOK_COMBAT, // Enemies
LOOK_VERY_IMPORTANT, // Something very important, more than enemies
LOOK_MOVEMENT, // Movement that requires looking in a specific direction (ie: ladders, jumps)
LOOK_CRITICAL, // Something of very high importance
LOOK_MANDATORY, // Nothing can interrupt this
Expand Down Expand Up @@ -96,6 +97,8 @@ inline const char* GetLookPriorityName(IPlayerController::LookPriority priority)
return "OPERATE";
case IPlayerController::LOOK_COMBAT:
return "COMBAT";
case IPlayerController::LOOK_VERY_IMPORTANT:
return "VERY IMPORTANT";
case IPlayerController::LOOK_MOVEMENT:
return "MOVEMENT";
case IPlayerController::LOOK_CRITICAL:
Expand Down
4 changes: 2 additions & 2 deletions extension/bot/interfaces/tasks.h
Original file line number Diff line number Diff line change
Expand Up @@ -568,7 +568,7 @@ class AITask : public IEventListener, public IDecisionQuery
* @brief The task that comes after this
* @return NULL for none or pointer to a task that will be added after this task
*/
virtual AITask<BotClass>* InitialNextTask(AITask<BotClass>* bot) { return nullptr; }
virtual AITask<BotClass>* InitialNextTask(BotClass* bot) { return nullptr; }

AITask<BotClass>* GetPreviousTask() const { return m_prevTask; }
AITask<BotClass>* GetNextTask() const { return m_nextTask; }
Expand Down Expand Up @@ -1335,7 +1335,7 @@ inline TaskResult<BotClass> AITask<BotClass>::ProcessTaskStart(BotClass* bot, AI

m_topTask = nullptr;

m_nextTask = InitialNextTask();
m_nextTask = InitialNextTask(bot);
if (m_nextTask)
{
// Build Task list
Expand Down
223 changes: 223 additions & 0 deletions extension/bot/tf2/tasks/engineer/tf2bot_engineer_build_object.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
#include <extension.h>
#include <util/librandom.h>
#include <util/helpers.h>
#include <entities/tf2/tf_entities.h>
#include <mods/tf2/tf2lib.h>
#include <bot/tf2/tf2bot.h>
#include <bot/tf2/tasks/tf2bot_find_ammo_task.h>
#include "tf2bot_engineer_build_object.h"

CTF2BotEngineerBuildObjectTask::CTF2BotEngineerBuildObjectTask(eObjectType type, const Vector& location)
{
m_type = type;
m_goal = location;
m_reachedGoal = false;
m_trydir = 0;

switch (type)
{
case CTF2BotEngineerBuildObjectTask::OBJECT_SENTRYGUN:
m_taskname.assign("BuildObject<SentryGun>");
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_DISPENSER:
m_taskname.assign("BuildObject<Dispenser>");
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_ENTRANCE:
m_taskname.assign("BuildObject<TeleEntrance>");
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_EXIT:
m_taskname.assign("BuildObject<TeleExit>");
break;
default:
m_taskname.assign("BuildObject<unknown>");
break;
}
}

TaskResult<CTF2Bot> CTF2BotEngineerBuildObjectTask::OnTaskStart(CTF2Bot* bot, AITask<CTF2Bot>* pastTask)
{
if (bot->GetAmmoOfIndex(TeamFortress2::TF_AMMO_METAL) < 150)
{
return PauseFor(new CTF2BotFindAmmoTask, "Need more metal to build!");
}

CTF2BotPathCost cost(bot);
if (!m_nav.ComputePathToPosition(bot, m_goal, cost))
{
return Done("Failed to build path to build location.");
}

m_repathTimer.Start(2.5f);

return Continue();
}

TaskResult<CTF2Bot> CTF2BotEngineerBuildObjectTask::OnTaskUpdate(CTF2Bot* bot)
{
switch (m_type)
{
case CTF2BotEngineerBuildObjectTask::OBJECT_SENTRYGUN:
{
if (bot->GetMySentryGun() != nullptr)
{
return Done("Object built!");
}

break;
}
case CTF2BotEngineerBuildObjectTask::OBJECT_DISPENSER:
{
if (bot->GetMyDispenser() != nullptr)
{
return Done("Object built!");
}

break;
}
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_ENTRANCE:
{
if (bot->GetMyTeleporterEntrance() != nullptr)
{
return Done("Object built!");
}

break;
}
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_EXIT:
{
if (bot->GetMyTeleporterExit() != nullptr)
{
return Done("Object built!");
}

break;
}
default:
return Done("Unknown object type!");
}

if (m_reachedGoal)
{
bot->FindMyBuildings();

if (m_giveupTimer.IsElapsed())
{
return Done("Giving up after many failed build attempts!");
}

// move randomly while trying to place
if (m_strafeTimer.IsElapsed())
{
m_strafeTimer.Start(randomgen->GetRandomReal<float>(3.0f, 4.0f));

if (randomgen->GetRandomInt<int>(0, 4) > 2)
{
bot->GetControlInterface()->PressMoveLeftButton(1.8f);
}
else
{
bot->GetControlInterface()->PressMoveRightButton(1.8f);
}

Vector forward, right;
Vector origin = bot->GetEyeOrigin();
bot->EyeVectors(&forward, &right, nullptr);
forward.NormalizeInPlace();
right.NormalizeInPlace();

switch (m_trydir)
{
case 0:
origin = origin + forward * 300.0f;
m_trydir++;
break;
case 1:
origin = origin + forward * -300.0f;
m_trydir++;
break;
case 2:
origin = origin + right * 300.0f;
m_trydir++;
break;
default:
origin = origin + right * -300.0f;
m_trydir = 0; // reset
break;
}

bot->GetControlInterface()->AimAt(origin, IPlayerController::LOOK_VERY_IMPORTANT, 0.2f, "Looking at build place.");
}

// crouch while placing
bot->GetControlInterface()->PressCrouchButton();

edict_t* weapon = bot->GetActiveWeapon();

if (weapon != nullptr)
{
auto classname = gamehelpers->GetEntityClassname(weapon);

if (classname != nullptr && classname[0] != '\0' && strcasecmp(classname, "tf_weapon_builder") == 0)
{
bot->GetControlInterface()->PressAttackButton();
}
else
{
switch (m_type)
{
case CTF2BotEngineerBuildObjectTask::OBJECT_SENTRYGUN:
bot->BeginBuilding(TeamFortress2::TFObject_Sentry, TeamFortress2::TFObjectMode_None);
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_DISPENSER:
bot->BeginBuilding(TeamFortress2::TFObject_Dispenser, TeamFortress2::TFObjectMode_None);
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_ENTRANCE:
bot->BeginBuilding(TeamFortress2::TFObject_Teleporter, TeamFortress2::TFObjectMode_Entrance);
break;
case CTF2BotEngineerBuildObjectTask::OBJECT_TELEPORTER_EXIT:
bot->BeginBuilding(TeamFortress2::TFObject_Teleporter, TeamFortress2::TFObjectMode_Exit);
break;
default:
break;
}
}
}
}
else
{
if (m_repathTimer.IsElapsed())
{
m_repathTimer.Start(2.5f);

CTF2BotPathCost cost(bot);
if (!m_nav.ComputePathToPosition(bot, m_goal, cost))
{
return Done("Failed to build path to build location.");
}
}

m_nav.Update(bot);
}


return Continue();
}

TaskEventResponseResult<CTF2Bot> CTF2BotEngineerBuildObjectTask::OnMoveToFailure(CTF2Bot* bot, CPath* path, IEventListener::MovementFailureType reason)
{
CTF2BotPathCost cost(bot);
if (!m_nav.ComputePathToPosition(bot, m_goal, cost))
{
return TryDone(PRIORITY_HIGH, "Failed to build path to build location.");
}

return TryContinue();
}

TaskEventResponseResult<CTF2Bot> CTF2BotEngineerBuildObjectTask::OnMoveToSuccess(CTF2Bot* bot, CPath* path)
{
m_reachedGoal = true;
m_giveupTimer.Start(15.0f);
m_strafeTimer.Start(2.0f);
return TryContinue();
}
47 changes: 47 additions & 0 deletions extension/bot/tf2/tasks/engineer/tf2bot_engineer_build_object.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef NAVBOT_TF2BOT_TASKS_ENGINEER_BUILD_OBJECT_H_
#define NAVBOT_TF2BOT_TASKS_ENGINEER_BUILD_OBJECT_H_

#include <string>

#include <sdkports/sdk_timers.h>
#include <bot/interfaces/path/meshnavigator.h>

class CTF2BotEngineerBuildObjectTask : public AITask<CTF2Bot>
{
public:
enum eObjectType
{
OBJECT_SENTRYGUN = 0,
OBJECT_DISPENSER,
OBJECT_TELEPORTER_ENTRANCE,
OBJECT_TELEPORTER_EXIT,

MAX_OBJECT_TYPES
};

CTF2BotEngineerBuildObjectTask(eObjectType type, const Vector& location);

TaskResult<CTF2Bot> OnTaskStart(CTF2Bot* bot, AITask<CTF2Bot>* pastTask) override;
TaskResult<CTF2Bot> OnTaskUpdate(CTF2Bot* bot) override;

TaskEventResponseResult<CTF2Bot> OnMoveToFailure(CTF2Bot* bot, CPath* path, IEventListener::MovementFailureType reason) override;
TaskEventResponseResult<CTF2Bot> OnMoveToSuccess(CTF2Bot* bot, CPath* path) override;

QueryAnswerType ShouldSeekAndDestroy(CBaseBot* me, const CKnownEntity* them) override { return ANSWER_NO; }

const char* GetName() const override { return m_taskname.c_str(); }

private:
Vector m_goal;
CountdownTimer m_repathTimer;
CountdownTimer m_giveupTimer;
CountdownTimer m_strafeTimer;
CMeshNavigator m_nav;
eObjectType m_type;
std::string m_taskname;
bool m_reachedGoal;
int m_trydir;
};


#endif // !NAVBOT_TF2BOT_TASKS_ENGINEER_BUILD_OBJECT_H_
Loading

0 comments on commit db24b3b

Please sign in to comment.