QueryResponse CTFBotPayloadGuard::ShouldRetreat(const INextBot *nextbot) const { CTFBot *actor = ToTFBot(nextbot->GetEntity()); CHandle<CTeamTrainWatcher> watcher = TFGameRules()->GetPayloadToBlock(actor->GetTeamNumber()); if (watcher != nullptr && watcher->IsTrainNearCheckpoint()) { return QueryResponse::NO; } return QueryResponse::DONTCARE; }
DETOUR_DECL_MEMBER(void, CTFPlayer_HandleCommand_JoinTeam, const char *team) { DETOUR_MEMBER_CALL(CTFPlayer_HandleCommand_JoinTeam)(team); auto player = reinterpret_cast<CTFPlayer *>(this); if (TFGameRules()->IsMannVsMachineMode() && player->GetTeamNumber() == TF_TEAM_RED) { CTFBot *bot = ToTFBot(player); if (bot != nullptr) { (void)bot->GetAutoTeam(5); } } }
/* make the targeted player known to all bots even if not in their ordinary * vision range; and if they're a spy, reveal their identity */ void NotifyBotsAboutTarget() { for (int i = 1; i <= gpGlobals->maxClients; ++i) { CTFPlayer *player = ToTFPlayer(UTIL_PlayerByIndex(i)); if (player == nullptr || !IsTheTarget(player)) continue; for (int j = 1; j <= gpGlobals->maxClients; ++j) { CTFBot *bot = ToTFBot(UTIL_PlayerByIndex(j)); if (bot == nullptr || bot->GetTeamNumber() != TF_TEAM_BLUE) continue; if (player->IsPlayerClass(TF_CLASS_SPY)) { bot->RealizeSpy(player); } bot->GetVisionInterface()->AddKnownEntity(player); } } }
/* ENHANCEMENT: make defender bots always aware of the bomb carrier(s) as * well as tanks */ void Enhancement_NotifyDefendersAboutBombs() { #if 0 std::set<CBaseEntity *> bombs; ForEachFlag([&](CCaptureFlag *flag, bool& done){ CBaseEntity *owner = flag->GetOwnerEntity(); if (owner == nullptr) return true; if (owner->GetTeamNumber() != TF_TEAM_BLUE) return true; CTFBot *carrier = ToTFBot(owner); if (carrier == nullptr) return true; bombs.insert(carrier); return true; }); ForEachTank([&](CTFTankBoss *tank, bool& done){ if (tank->GetTeamNumber() == TF_TEAM_BLUE) { bombs.insert(tank); } return true; }); if (bombs.empty()) return; ForEachDefenderBot([&](CTFBot *bot, bool& done){ if (!bot->IsAlive()) return true; IVision *vision = bot->GetVisionInterface(); for (auto bomb : bombs) { vision->AddKnownEntity(bomb); } return true; }); #endif }
bool IsPlayerMarkable(CTFBot *bot, CTFPlayer *victim) { /* must be alive */ if (!victim->IsAlive()) return false; /* must be an enemy */ if (bot->GetTeamNumber() == victim->GetTeamNumber()) return false; /* must be a giant */ if (!victim->IsMiniBoss()) return false; /* must not already be marked for death */ if (victim->m_Shared->InCond(TF_COND_MARKEDFORDEATH)) return false; /* must not be invulnerable */ if (victim->m_Shared->IsInvulnerable()) return false; /* must not be a sentry buster */ CTFBot *vbot = ToTFBot(victim); if (vbot != nullptr && vbot->GetMission() == CTFBot::MISSION_DESTROY_SENTRIES) return false; return true; }
//-------------------------------------------------------------------------------------------------------- // Return true if this cost applies to the given actor bool CFuncNavCost::IsApplicableTo( CBaseCombatCharacter *who ) const { if ( !who ) { return false; } if ( m_team > 0 ) { if ( who->GetTeamNumber() != m_team ) { return false; } } #ifdef TF_DLL // TODO: Make group comparison efficient and move to base combat character CTFBot *bot = ToTFBot( who ); if ( bot ) { if ( bot->HasTheFlag() ) { if ( HasTag( "bomb_carrier" ) ) { return true; } // check custom bomb_carrier tags for this bot for( int i=0; i<m_tags.Count(); ++i ) { const char* pszTag = m_tags[i]; if ( V_stristr( pszTag, "bomb_carrier" ) ) { if ( bot->HasTag( pszTag ) ) { return true; } } } // the bomb carrier only pays attention to bomb_carrier costs return false; } if ( bot->HasMission( CTFBot::MISSION_DESTROY_SENTRIES ) ) { if ( HasTag( "mission_sentry_buster" ) ) { return true; } } if ( bot->HasMission( CTFBot::MISSION_SNIPER ) ) { if ( HasTag( "mission_sniper" ) ) { return true; } } if ( bot->HasMission( CTFBot::MISSION_SPY ) ) { if ( HasTag( "mission_spy" ) ) { return true; } } if ( bot->HasMission( CTFBot::MISSION_REPROGRAMMED ) ) { return false; } if ( !bot->IsOnAnyMission() ) { if ( HasTag( "common" ) ) { return true; } } if ( HasTag( bot->GetPlayerClass()->GetName() ) ) { return true; } // check custom tags for this bot for( int i=0; i<m_tags.Count(); ++i ) { if ( bot->HasTag( m_tags[i] ) ) { return true; } } // this cost doesn't apply to me return false; } #endif return false; }
void DrawOverlay_Bots() { float duration = cvar_overlay_duration.GetFloat(); constexpr float base_x = 0.02f; constexpr float base_y = 0.02f; constexpr float col1_w = 0.04f; constexpr float col1_x = 0.00f; constexpr float col2_w = 0.04f; constexpr float col2_x = col1_x + col1_w; constexpr float col3_w = 0.04f; constexpr float col3_x = col2_x + col2_w; constexpr float col4_w = 0.10f; constexpr float col4_x = col3_x + col3_w; constexpr float col5_w = 0.12f; constexpr float col5_x = col4_x + col4_w; constexpr float col6_w = 0.00f; constexpr float col6_x = col5_x + col5_w; NDebugOverlay::ScreenText(base_x + col1_x, base_y, "ENTINDEX", 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col2_x, base_y, "TEAMNUM", 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col3_x, base_y, "ALIVE", 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col4_x, base_y, "ABSORIGIN", 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col5_x, base_y, "BOTNAME", 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col6_x, base_y, "BEHAVIOR", 0xff, 0xff, 0xff, 0xff, duration); float line_y = 0.0f; for (int i = 1; i <= gpGlobals->maxClients; ++i) { CTFBot *bot = ToTFBot(UTIL_PlayerByIndex(i)); if (bot == nullptr) continue; line_y += 0.0140f; bool is_alive = bot->IsAlive(); int teamnum = bot->GetTeamNumber(); NDebugOverlay::ScreenText(base_x + col1_x, base_y + line_y, CFmtStrN<64>("#%d", i), 0xff, 0xff, 0xff, 0xff, duration); if (teamnum == TF_TEAM_BLUE) { NDebugOverlay::ScreenText(base_x + col2_x, base_y + line_y, "BLU", 0x40, 0x40, 0xff, 0xff, duration); } else if (teamnum == TEAM_SPECTATOR) { NDebugOverlay::ScreenText(base_x + col2_x, base_y + line_y, "SPEC", 0x80, 0x80, 0x80, 0xff, duration); } else { NDebugOverlay::ScreenText(base_x + col2_x, base_y + line_y, CFmtStrN<64>("%d", teamnum), 0xff, 0xff, 0xff, 0xff, duration); } if (is_alive) { NDebugOverlay::ScreenText(base_x + col3_x, base_y + line_y, "ALIVE", 0x40, 0xff, 0x40, 0xff, duration); } else { NDebugOverlay::ScreenText(base_x + col3_x, base_y + line_y, "DEAD", 0xff, 0x40, 0x40, 0xff, duration); } const Vector& absorigin = bot->GetAbsOrigin(); NDebugOverlay::ScreenText(base_x + col4_x, base_y + line_y, CFmtStrN<256>("[ %+5.0f %+5.0f %+5.0f ]", absorigin.x, absorigin.y, absorigin.z), 0xff, 0xff, 0xff, 0xff, duration); NDebugOverlay::ScreenText(base_x + col5_x, base_y + line_y, bot->GetPlayerName(), 0xff, 0xff, 0xff, 0xff, duration); IIntention *intent = bot->GetIntentionInterface(); auto behavior = rtti_cast<Behavior<CTFBot> *>(intent->FirstContainedResponder()); if (behavior != nullptr) { auto action = rtti_cast<Action<CTFBot> *>(behavior->FirstContainedResponder()); if (action != nullptr) { NDebugOverlay::ScreenText(base_x + col6_x, base_y + line_y, PleaseRemoveThis::DebugString(action), 0xff, 0xff, 0xff, 0xff, duration); } else { NDebugOverlay::ScreenText(base_x + col6_x, base_y + line_y, "(action is nullptr)", 0x80, 0x80, 0x80, 0xff, duration); } } else { NDebugOverlay::ScreenText(base_x + col6_x, base_y + line_y, "(behavior is nullptr)", 0x80, 0x80, 0x80, 0xff, duration); } } }