Skip to content

Commit

Permalink
Big TF2 Update
Browse files Browse the repository at this point in the history
Implemented FindHealth task (missed this one for too long lol).
Fixed some crashes caused by the TF2 bot.
Improvements to the TF2 bot behavior (on CTF maps)
Medic bot still dumb. Needs major overhaul.
  • Loading branch information
caxanga334 committed Dec 8, 2024
1 parent 0e2a8c5 commit a90b599
Show file tree
Hide file tree
Showing 37 changed files with 827 additions and 89 deletions.
5 changes: 5 additions & 0 deletions extension/bot/basebot.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,11 @@ bool CBaseBot::IsAbleToBreak(edict_t* entity)
return false;
}

bool CBaseBot::IsAlive() const
{
return UtilHelpers::IsEntityAlive(this->GetIndex());
}

void CBaseBot::RegisterInterface(IBotInterface* iface)
{
m_interfaces.push_back(iface);
Expand Down
3 changes: 2 additions & 1 deletion extension/bot/basebot.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class CBaseBot : public CBaseExtPlayer, public IEventListener
virtual bool IsRangeLessThan(edict_t* edict, const float range) const;

virtual bool IsAbleToBreak(edict_t* entity);
virtual bool IsAlive() const;

IBotController* GetController() const { return m_controller; }

Expand Down Expand Up @@ -182,7 +183,7 @@ class CBaseBot : public CBaseExtPlayer, public IEventListener

// makes the bot hold their fire for the given time in seconds
inline void DontAttackEnemies(const float time) { m_holdfire_time.Start(time); }
bool IsLineOfFireClear(const Vector& to) const;
virtual bool IsLineOfFireClear(const Vector& to) const;

inline const Vector& GetHomePos() const { return m_homepos; }
void SetHomePos(const Vector& home) { m_homepos = home; }
Expand Down
12 changes: 6 additions & 6 deletions extension/bot/interfaces/event_listener.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ class IEventListener
virtual void OnLostSight(edict_t* subject); // when the bot loses sight of an entity
virtual void OnSound(edict_t* source, const Vector& position, SoundType type, const int volume); // when the bot hears an entity
virtual void OnRoundStateChanged(); // When the round state changes (IE: round start,end, freeze time end, setup time end, etc...)
virtual void OnFlagTaken(CBaseEntity* flag); // CTF: Flag was stolen
virtual void OnFlagDropped(CBaseEntity* flag); // CTF: Flag was dropped
virtual void OnFlagTaken(CBaseEntity* player); // CTF: Flag was stolen
virtual void OnFlagDropped(CBaseEntity* player); // CTF: Flag was dropped
virtual void OnControlPointCaptured(CBaseEntity* point); // When a control point is captured
virtual void OnControlPointLost(CBaseEntity* point); // When a control point is lost
virtual void OnControlPointContested(CBaseEntity* point); // When a control point is under siege
Expand Down Expand Up @@ -241,28 +241,28 @@ inline void IEventListener::OnRoundStateChanged()
}
}

inline void IEventListener::OnFlagTaken(CBaseEntity* flag)
inline void IEventListener::OnFlagTaken(CBaseEntity* player)
{
auto vec = GetListenerVector();

if (vec)
{
for (auto listener : *vec)
{
listener->OnFlagTaken(flag);
listener->OnFlagTaken(player);
}
}
}

inline void IEventListener::OnFlagDropped(CBaseEntity* flag)
inline void IEventListener::OnFlagDropped(CBaseEntity* player)
{
auto vec = GetListenerVector();

if (vec)
{
for (auto listener : *vec)
{
listener->OnFlagDropped(flag);
listener->OnFlagDropped(player);
}
}
}
Expand Down
50 changes: 35 additions & 15 deletions extension/bot/interfaces/inventory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ void IInventory::Reset()
m_weapons.clear();
m_weaponSwitchCooldown.Invalidate();
m_updateWeaponsTimer.Start(UPDATE_WEAPONS_INTERVAL_AFTER_RESET);

edict_t* weapon = GetBot()->GetActiveWeapon();

if (weapon != nullptr)
{
m_cachedActiveWeapon = std::make_shared<CBotWeapon>(weapon);
}
}

void IInventory::Update()
Expand All @@ -38,6 +45,13 @@ void IInventory::Update()
m_updateWeaponsTimer.Start(UPDATE_WEAPONS_INTERVAL);
BuildInventory();
}

edict_t* weapon = GetBot()->GetActiveWeapon();

if (weapon != nullptr && m_cachedActiveWeapon->GetEdict() != weapon)
{
m_cachedActiveWeapon = std::make_shared<CBotWeapon>(weapon);
}
}

void IInventory::Frame()
Expand All @@ -48,10 +62,10 @@ bool IInventory::HasWeapon(std::string classname)
{
for (auto& weapon : m_weapons)
{
if (!weapon.IsValid())
if (!weapon->IsValid())
continue;

const char* clname = weapon.GetBaseCombatWeapon().GetClassname();
const char* clname = weapon->GetBaseCombatWeapon().GetClassname();

if (clname != nullptr)
{
Expand Down Expand Up @@ -84,7 +98,7 @@ void IInventory::BuildInventory()
if (!weapon || weapon->IsFree() || weapon->GetIServerEntity() == nullptr)
continue;

m_weapons.emplace_back(weapon);
m_weapons.emplace_back(new CBotWeapon(weapon));
}
}

Expand All @@ -107,34 +121,34 @@ void IInventory::SelectBestWeaponForThreat(const CKnownEntity* threat)
const CBotWeapon* best = nullptr;
int priority = std::numeric_limits<int>::min();

ForEveryWeapon([&bot, &priority, &rangeToThreat, &best](const CBotWeapon& weapon) {
ForEveryWeapon([&bot, &priority, &rangeToThreat, &best](const CBotWeapon* weapon) {

// weapon must be usable against enemies
if (!weapon.GetWeaponInfo()->IsCombatWeapon())
if (!weapon->GetWeaponInfo()->IsCombatWeapon())
{
return;
}

// Must have ammo
if (weapon.GetBaseCombatWeapon().GetClip1() == 0 && bot->GetAmmoOfIndex(weapon.GetBaseCombatWeapon().GetPrimaryAmmoType()) == 0)
if (weapon->GetBaseCombatWeapon().GetClip1() == 0 && bot->GetAmmoOfIndex(weapon->GetBaseCombatWeapon().GetPrimaryAmmoType()) == 0)
{
return;
}

if (rangeToThreat > weapon.GetWeaponInfo()->GetAttackInfo(WeaponInfo::PRIMARY_ATTACK).GetMaxRange())
if (rangeToThreat > weapon->GetWeaponInfo()->GetAttackInfo(WeaponInfo::PRIMARY_ATTACK).GetMaxRange())
{
return; // outside max range
}
else if (rangeToThreat < weapon.GetWeaponInfo()->GetAttackInfo(WeaponInfo::PRIMARY_ATTACK).GetMinRange())
else if (rangeToThreat < weapon->GetWeaponInfo()->GetAttackInfo(WeaponInfo::PRIMARY_ATTACK).GetMinRange())
{
return; // too close
}

int currentprio = weapon.GetWeaponInfo()->GetPriority();
int currentprio = weapon->GetWeaponInfo()->GetPriority();

if (currentprio > priority)
{
best = &weapon;
best = weapon;
priority = currentprio;
}
});
Expand All @@ -150,7 +164,7 @@ void IInventory::SelectBestWeaponForThreat(const CKnownEntity* threat)
}
}

const CBotWeapon* IInventory::GetActiveBotWeapon()
std::shared_ptr<CBotWeapon> IInventory::GetActiveBotWeapon()
{
edict_t* weapon = GetBot()->GetActiveWeapon();

Expand All @@ -159,13 +173,19 @@ const CBotWeapon* IInventory::GetActiveBotWeapon()
return nullptr;
}

int index = gamehelpers->IndexOfEdict(weapon);
if (m_cachedActiveWeapon)
{
if (m_cachedActiveWeapon->GetEdict() == weapon)
{
return m_cachedActiveWeapon;
}
}

for (auto& weapon : m_weapons)
for (auto& weaponptr : m_weapons)
{
if (weapon.GetIndex() == index)
if (weaponptr->GetEdict() == weapon)
{
return &weapon;
return weaponptr;
}
}

Expand Down
13 changes: 7 additions & 6 deletions extension/bot/interfaces/inventory.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,20 @@ class IInventory : public IBotInterface

/**
* @brief Runs a function on every valid bot weapon
* @tparam T a class with operator() overload with 1 parameter: (const CBotWeapon& weapon)
* @tparam T a class with operator() overload with 1 parameter: (const CBotWeapon* weapon)
* @param functor function to run on every valid weapon
*/
template <typename T>
inline void ForEveryWeapon(T functor) const
{
for (const CBotWeapon& weapon : m_weapons)
for (auto& weapon : m_weapons)
{
if (!weapon.IsValid())
if (!weapon->IsValid())
{
continue;
}

functor(weapon);
functor(weapon.get());
}
}

Expand All @@ -62,10 +62,11 @@ class IInventory : public IBotInterface

virtual void SelectBestWeaponForThreat(const CKnownEntity* threat);

virtual const CBotWeapon* GetActiveBotWeapon();
virtual std::shared_ptr<CBotWeapon> GetActiveBotWeapon();

private:
std::vector<CBotWeapon> m_weapons;
std::vector<std::shared_ptr<CBotWeapon>> m_weapons;
std::shared_ptr<CBotWeapon> m_cachedActiveWeapon;

protected:
CountdownTimer m_updateWeaponsTimer;
Expand Down
1 change: 1 addition & 0 deletions extension/bot/interfaces/movement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,7 @@ bool IMovement::IsGap(const Vector& pos, const Vector& forward)
* @param fraction trace result fraction
* @param now When true, check if the bot is able to move right now. Otherwise check if the bot is able to move in the future
* (ie: blocked by an entity that can be destroyed)
* @param obstacle The obstacle entity will be stored here.
* @return true if the bot can walk, false otherwise
*/
bool IMovement::IsPotentiallyTraversable(const Vector& from, const Vector& to, float* fraction, const bool now, CBaseEntity** obstacle)
Expand Down
17 changes: 16 additions & 1 deletion extension/bot/interfaces/path/basepath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,8 @@ bool CPath::ProcessGroundPath(CBaseBot* bot, const Vector& start, std::shared_pt

// Sometimes there is a railing between the drop and the ground


#if PROBLEMATIC
trace::CTraceFilterNoNPCsOrPlayers filter(bot->GetEntity(), COLLISION_GROUP_NONE);
trace_t result;
Vector mins(-halfWidth, -halfWidth, mover->GetStepHeight());
Expand All @@ -547,9 +549,22 @@ bool CPath::ProcessGroundPath(CBaseBot* bot, const Vector& start, std::shared_pt
seg2->CopySegment(to.get());
seg2->goal = startDrop + Vector(0.0f, 0.0f, mover->GetStepHeight());
seg2->type = AIPath::SegmentType::SEGMENT_CLIMB_UP;
pathinsert.emplace(newSegment, std::move(seg2), false);

std::shared_ptr<CBasePathSegment> jumpRunSegment = CreateNewSegment();
jumpRunSegment->CopySegment(from.get());
jumpRunSegment->type = AIPath::SegmentType::SEGMENT_GROUND;

Vector runDir = (jumpRunSegment->goal - result.endpos);
runDir.z = 0.0f;
runDir.NormalizeInPlace();
jumpRunSegment->goal = result.endpos + (runDir * (mover->GetHullWidth() * 1.2f));

pathinsert.emplace(seg2, jumpRunSegment, false);
pathinsert.emplace(newSegment, seg2, false);
}

#endif

pathinsert.emplace(to, newSegment, true);
}
}
Expand Down
Loading

0 comments on commit a90b599

Please sign in to comment.