Skip to content

Improve bot stability and teammate support - #37

Open
Angry-Bishop wants to merge 2 commits into
APGRoboCop:masterfrom
Angry-Bishop:stability-and-team-support-improvements
Open

Angry-Bishop wants to merge 2 commits into
APGRoboCop:masterfrom
Angry-Bishop:stability-and-team-support-improvements

Conversation

@Angry-Bishop

@Angry-Bishop Angry-Bishop commented Sep 20, 2026 •

Copy link
Copy Markdown

Summary

This pull request combines a broad stability and memory-safety review with improvements to flag handling, Medic healing, Engineer armor repair, and Metamod engine hooks.

The changes were transplanted onto the current upstream beta 3 source and reconciled with overlapping upstream work. Existing 1.0-beta3 version identifiers are retained.

Major changes

Stability and memory safety

  • Reduced unnecessary per-frame polling and mutation of the bot command cvar.
  • Added bounds validation for team, weapon, ammunition, waypoint, area, route, and persistent-file data.
  • Corrected several out-of-bounds, unterminated-string, malformed-input, allocation, and format-string hazards.
  • Hardened behavior-script, bot-command, chat-command, configuration, waypoint, area, compressed-file, neural-network, and genetic-algorithm parsing.
  • Corrected linked-list removal and several file/resource handling issues.
  • Preserved current upstream waypoint-count validation while avoiding duplicate checks.

Flag tracking and human handoff

  • Corrected the assumption that a bot-array index always equals client slot - 1.
  • Added validation that the resolved bot record owns the corresponding client entity.
  • Added configurable bot-to-human flag handoff behavior.
  • Bot flag carriers select a nearby visible human teammate, face the recipient, and use TFC's normal dropitems command.
  • Successful transfers are confirmed before announcing them in team chat.
  • Failed throws are retried after 1.5 seconds with fresh recipient validation.

Configuration:

bot_flag_toss 1
bot_flag_toss_distance 200

Medic healing bug fixes and teammate support

FoXBot already contained a JOB_BUFF_ALLY healing implementation, but several discovery, scheduling, navigation, and combat interactions could prevent it from running reliably.

Corrected problems include:

  • Patient discovery was nested inside enemy-search control flow that could return before the patient scan executed.
  • The inherited healing priority was lower than several ordinary navigation and item jobs, allowing a valid healing job to remain buffered without being selected.
  • Patient discovery depended on the Medic's forward view instead of searching all directions.
  • The first eligible client slot could be selected instead of the nearest patient.
  • A nearby patient could be rejected when the Medic lacked a current waypoint, even when no route was needed to begin treatment.
  • Seeing any enemy canceled healing, including distant enemies that posed no immediate threat.
  • The combat pass could leave IN_ATTACK set or reselect a firearm after urgent healing had been selected.
  • The Medic could attack before the medikit became the active weapon, potentially firing the previously selected weapon.
  • Responder selection could be affected by players outside the caller's actual team.
  • The urgent-healing commitment test could index the fixed job arrays without first validating currentJob.

The corrected behavior:

  • Searches all directions and selects the nearest visible same-team patient.
  • Treats any injured or infected teammate within 400 units as urgent.
  • Allows an accepted support job to continue to 600 units.
  • Permits close-range healing without requiring a waypoint or route.
  • Retains urgent healing when an enemy is visible at more than 250 units.
  • Interrupts healing when an enemy is within 250 units or the Medic has taken non-ignored damage during the preceding second.
  • Gives nearby saveme requests increased priority for five seconds.
  • Uses a short commitment window to prevent minor movement from repeatedly interrupting treatment.
  • Confirms that the medikit is active before pressing attack.
  • Suppresses conflicting combat attack/weapon state while urgent healing owns the frame.
  • Validates the current job index before accessing fixed job arrays.

Engineer teammate support

  • Corrected armor-percentage calculation that previously reduced most partial armor values to zero.
  • Engineers locate nearby visible teammates needing armor and select the nearest eligible patient.
  • Routine and urgent armor-repair priorities are bounded by distance and immediate combat conditions.
  • Engineers wait for the spanner to become active before attacking.
  • Existing construction, sentry maintenance, metal acquisition, flag objectives, and danger avoidance retain higher priority where appropriate.

Metamod engine hooks

  • Corrected ClientCommand paths that could return without setting meta_result.
  • Human clients now return MRES_IGNORED; fake or invalid client destinations retain the intended suppression behavior.
  • Client classification now uses GoldSrc's FL_FAKECLIENT flag.
  • Removed duplicate ClientCommand and ClientPrintf hook assignments.
  • Added null and format-string safety to client/server print paths.

Follow-up: Prevent bots from holding primed grenades after combat

Observed problem

Bots could prime a grenade while fighting, eliminate or lose their opponent, and then continue holding the live grenade until it exploded in their hand. This caused avoidable self-damage and occasional bot suicides after an otherwise successful fight.

Problems discovered

The investigation found several related control-flow gaps:

  • Management of an already-primed grenade depended too heavily on the normal combat and grenade-processing path.
  • When the enemy died or otherwise became invalid, normal combat processing could stop before the grenade reached its release condition.
  • The existing no-target disposal check was located inside that combat-dependent path and waited until approximately the last two seconds of the fuse before requesting JOB_BIN_GRENADE.
  • Blinded bots, deliberately stationary bots, and other early-return conditions could bypass the code responsible for maintaining the live grenade.
  • JOB_BIN_GRENADE could be rejected when the bot temporarily had no current waypoint, even though safely releasing a live grenade should not require valid route data.
  • Grenade release commands and the associated nadePrimed and nadeType state resets were duplicated across multiple paths, increasing the possibility of the engine command and internal bot state becoming inconsistent.
  • A frame-level emergency release could occur while the disposal job was still trying to aim, requiring the job to recognize that it no longer owned a live grenade.

Changes made

  • Added BotCheckPrimedGrenade() to maintain an already-live grenade independently of ordinary combat processing.

  • Calls the safety check before early stationary/blinded exits and again after environment sensing, where an enemy pointer may be cleared immediately following a kill.

  • Submits JOB_BIN_GRENADE as soon as a primed bot no longer has a valid enemy, allowing the bot more time to select and face a safe throw direction.

  • Preserves the existing grenade-type and health-dependent release deadline:

    • MIRV grenades are released earlier.
    • Injured bots release earlier to reduce the risk of lethal splash damage.
  • Ensures that the final release deadline remains active even if normal combat processing stops or grenade use is disabled after the grenade has already been primed.

  • Added BotReleasePrimedGrenade() to centralize:

    • Release of both grenade buttons.
    • Clearing nadePrimed.
    • Clearing nadeType.
  • Allows JOB_BIN_GRENADE to run without a current waypoint.

  • Updates the disposal job so that, if the frame-level safety check releases the grenade while the bot is still turning, the job stops aiming and enters its normal retreat phase.

  • Reuses the centralized release helper for normal timed throws, untimed throws, underwater release, and the disposal job’s emergency fallback.

Existing beta3 behavior preserved

The change was ported into the current beta3 source rather than copying the older beta2 files over it. The following newer beta3 behavior remains intact:

  • When no suitable disposal waypoint exists, the bot creates a forward throw target rather than immediately abandoning the disposal attempt.
  • The disposal job retains its existing 1.2-second release threshold while aiming.
  • The existing 0.5-second emergency release remains as the final defensive fallback.
  • The bot continues into the existing retreat phase after throwing the grenade.

Gameplay scope

This does not give bots extraordinary awareness or abilities. The bot only responds to its own known primed-grenade state, the existing enemy state, and the existing disposal job. It does not locate unseen opponents or obtain information unavailable through normal bot processing.

Normal grenade selection, targeting, cooking, and close-range emergency behavior remain unchanged.

Concussion-jump behavior is also unaffected because the dedicated concussion-jump job does not use the ordinary nadePrimed state monitored by this safety path.

Validation

  • The original correction was tested extensively on the deployed beta2-based server build.

  • The change was separately ported onto the beta3 source used by PR Improve bot stability and teammate support #37.

  • Only the five relevant source files were changed:

    • bot.cpp
    • bot_combat.cpp
    • bot_func.h
    • bot_job_functions.cpp
    • bot_job_think.cpp
  • All C++ translation units passed syntax validation.

  • The Win32 DLL compiled successfully and loaded through Metamod as:

    FoXBot v1.0-beta3, Sep 26 2026

  • Runtime testing of the beta3 build is continuing, with particular attention to opponent loss, missing waypoints, interrupted disposal jobs, and normal grenade and concussion-jump behavior.

Files and principal functions changed

File Principal functions or data
bot.cpp BotCreate, BotFindItem, PlayerArmorPercent, BotAttackerCheck, BotSoundSense, BotRoleCheck, BotComms, BotThink, BotSenseEnvironment, BotFight, BotCombatThink; per-frame primed-grenade safety checks
bot.h Bot support/flag-handoff state, job-buffer declarations, helper prototypes
bot_client.cpp Weapon, ammunition, pickup, and TFC score message parsers
bot_combat.cpp Enemy/team validation, flag-carrier tracking, infection handling, combat interaction with urgent support; BotNadeHandler, BotCheckPrimedGrenade, BotReleasePrimedGrenade, and grenade-release timing
bot_func.h Primed-grenade safety and centralized release helper declarations
bot_compress.h Compressed read/write size and allocation validation
bot_ga.cpp Genetic-algorithm and trained-network loading validation
bot_job_assessors.cpp assess_JobBuffAlly support priorities, range limits, and threat handling
bot_job_functions.cpp JobBuffAlly healing/repair execution and weapon confirmation; JobBinGrenade disposal, emergency release, and retreat handling
bot_job_think.cpp SubmitNewJob, Engineer support discovery, and support for grenade-disposal jobs without a current waypoint
bot_neuralnet.cpp Neural-network loading and allocation validation
dll.cpp Chat/config parsing, ClientCommand, StartFrame, FakeClientCommand, bot-cfg processing, server-command polling
engine.cpp pfnClientCommand, pfnClientPrintf, pfnServerPrint, hook registration, name/message validation
list.h Safe end-of-list iterator removal
util.cpp UTIL_GetTeamColor, UTIL_GetClass, filename construction, line reading
waypoint.cpp Waypoint/area loading and saving, route allocation, auto-build/merge, commander-list handling

Validation

  • Transplanted onto current upstream beta 3 rather than copying beta 2 files directly.

  • Tested changes using current V1 Beta 2 and the working Beta 3 exetensively

  • git diff --check completes without errors.

  • Visual Studio Release | Win32 rebuild completed successfully.

  • Verified required DLL exports, including:

    • GiveFnptrsToDll
    • Meta_Query
    • Meta_Attach
    • GetEntityAPI
    • GetEntityAPI_Post
  • Runtime smoke-tested over two rounds on a Windows TFC dedicated server.

  • Bot creation, ordinary bot behavior, and server bot commands operated as expected.

  • The cumulative flag-handoff and teammate-support behavior was also exercised using the beta 2 development builds.

  • Generated DLL is not included in this pull request but can be provided on request.

Test-build SHA-256:

229b7f20329c28ea33bebdec96032e7988f48d5391572eb614f9717c2b2fd502

@Angry-Bishop

Copy link
Copy Markdown
Author

Added a follow-up commit addressing bots that retained primed grenades after combat ended.

The investigation identified several paths where grenade maintenance could stop after the enemy became invalid, during early bot-think exits, or when the grenade-disposal job was rejected because no current waypoint existed. The update adds an independent safety check, centralizes grenade release and state cleanup, permits emergency disposal without a waypoint, and coordinates the frame-level release deadline with the existing disposal job.

The full problem description, implementation details, preserved beta3 behavior, and validation status have been added to the PR description.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant