A small Go command-line tool that generates a botprofile.db for Counter-Strike: Source, so every match is full of bots with fresh, human-looking names and slightly different skill levels. Names are built from word lists you control, and a seed makes any result reproducible.
  • Go 98.9%
  • Makefile 1.1%
Find a file
joshdevelopsIRL 9cb68dbd2e
Some checks failed
ci / check (push) Has been cancelled
docs: rewrite README with usage, config reference and development notes
2026-10-12 13:33:28 -05:00
.github/workflows ci: run gofmt, vet and tests on push and pull request 2026-10-12 13:33:28 -05:00
pkg test: replace log-only tests with real assertions 2026-10-12 13:33:28 -05:00
release chore: regenerate release/botprofile.db with the fixed generator 2026-10-12 13:33:28 -05:00
.gitignore build: add check, test, vet, fmt and release targets 2026-10-12 13:33:28 -05:00
config.go refactor: run() returns errors instead of panicking, no package-level state 2026-10-12 13:33:28 -05:00
config_test.go refactor: run() returns errors instead of panicking, no package-level state 2026-10-12 13:33:28 -05:00
cs-source-dynamic-bots-office-29-1.png add screenshot to top 2025-02-02 17:26:57 -06:00
example.AppConfig.json fix(config): keep defaults for settings missing from AppConfig.json 2026-10-12 13:33:28 -05:00
go.mod initial push 2024-03-17 16:55:40 -05:00
LICENSE docs: use full name in LICENSE 2026-10-12 13:33:28 -05:00
main.go feat: add a -seed flag for reproducible output 2026-10-12 13:33:28 -05:00
mainlists.csv add more random, make new release file 2026-01-10 15:59:56 -06:00
Makefile build: add check, test, vet, fmt and release targets 2026-10-12 13:33:28 -05:00
names.go fix: running out of bot names is an error, not a stack overflow 2026-10-12 13:33:28 -05:00
names_test.go fix: running out of bot names is an error, not a stack overflow 2026-10-12 13:33:28 -05:00
README.md docs: rewrite README with usage, config reference and development notes 2026-10-12 13:33:28 -05:00
run_test.go feat: add a -seed flag for reproducible output 2026-10-12 13:33:28 -05:00

Counter-Strike: Source Bot Profile Generator

A small Go command-line tool that generates a botprofile.db for Counter-Strike: Source, so every match is full of bots with fresh, human-looking names and slightly different skill levels. Names are built from word lists you control, and a seed makes any result reproducible.

Counter-Strike Source custom bots

Features

  • Generates bots for all four difficulties (Easy, Normal, Hard, Expert) and all six weapon groups (Rifles, Autos, SMGs, Scoped, Shotguns, Snipers)
  • Random but sane stats per bot (skill, aggression, reaction time, attack delay), kept in range and ordered by difficulty
  • Names built from a CSV of words, nouns, adjectives and optional clan tags, with random numbers and casing
  • Every name is unique (case-insensitive) and fits the Source engine's name limit, clan tag included
  • Reproducible output with -seed
  • JSON config that rejects typos and clamps out-of-range values, with a note about each change
  • Unit tests, end-to-end tests, and CI on every push

Quick start

You need Go 1.22 or newer. make is optional.

git clone https://github.com/joshdevelopsIRL/botprofiles-cs-source.git
cd botprofiles-cs-source
cp example.AppConfig.json AppConfig.json
make run

Without make:

go run .

The tool prints where it wrote the file and which seed it used:

wrote 288 bot profiles to ./release/botprofile.db (seed 20241)

A ready-made release/botprofile.db is also included if you just want to try it.

Install into the game

Copy botprofile.db to the custom/cstrike/ folder inside your Counter-Strike: Source install. Create the cstrike folder inside custom if it does not exist.

  • Linux: ~/.steam/steam/steamapps/common/Counter-Strike Source/cstrike/custom/cstrike/
  • Windows: C:\Program Files (x86)\Steam\steamapps\common\Counter-Strike Source\cstrike\custom\cstrike\

Restart the game or load a new map for the bots to pick up the file.

Usage

css-botprofiles [-config PATH] [-seed N] [-version]
Flag Description Default
-config Path to the JSON config file ./AppConfig.json
-seed Random seed. The same seed and config give the same bots. 0 picks a new one each run 0
-version Print the version and exit

If the default config file is missing, the built-in defaults are used. If you pass -config explicitly and the file is missing, the tool exits with an error.

To recreate a profile you liked, run again with the seed it printed:

go run . -seed 20241

Only the timestamp in the file header differs between runs with the same seed.

Configuration

Copy example.AppConfig.json to AppConfig.json and edit it. Unknown keys are an error, so a misspelled option never silently does nothing. Values outside the allowed range are clamped and the tool tells you what it changed.

Key Meaning Default Allowed
csv_namelist_path Word list CSV ./mainlists.csv
db_output_path Where to write the profile (folders are created) ./release/botprofile.db
use_words, use_nouns, use_adjectives Which word lists to draw from true
use_clans Prefix some bots with a clan tag (better bots are more likely to have one) false
use_numbers Sometimes append a number true
use_uppercase, use_lowercase Sometimes force upper or lower case true
max_name_length Longest name, clan tag included. The engine cuts names near 31 31 3 to 60
max_words_in_name Most words in one name 3 1 to 9
max_list_length Candidate words drawn per name 10 1 to 49
rand_pool_size Each extra (number, upper, lower) happens about 1 in N times 20 1 to 99
max_rifles, max_autos, max_smgs, max_scoped, max_shotguns, max_snipers Bots of that weapon group, per difficulty 9, 3, 3, 6, 1, 6 0 to 99

At least one bot must be requested overall, and there must be enough distinct words to produce that many unique names, otherwise the tool stops with a clear error instead of looping forever.

Word lists

mainlists.csv has one column per list, and the header row picks the list. Recognised headers are Words, Nouns, Adjectives and Clans. Column order does not matter, extra columns are ignored, and empty cells or short rows are fine. Add your own words and tags there.

Output

The file starts with a header, then a template per difficulty and per weapon group, then every bot in shuffled order:

// BotProfiles - CS:Source - v1.1.0
...
Template Default
	Skill = 50
	...
HardMode+Rifles "3th0 POET King LEAD"
EasyMode+Autos "well-to-do lab"

Development

make check     # gofmt check, go vet, go test
make test      # tests only
make fmt       # format the code
make release   # cross-compile to dist/ (linux, macOS, windows)
make clean

Layout:

  • main.go, config.go, names.go: the command, config loading and validation, and unique name generation
  • pkg/bots: bot stats, difficulties, weapon groups and the profile file format
  • pkg/namegen: word list loading and name building
  • pkg/rng: a small seeded random number helper, passed around so output is reproducible

The tests cover the stat ranges, name length limits (including multi-byte characters), CSV edge cases, config validation, and full runs that check the generated file end to end. CI runs formatting, vet and go test -race on every push.

License

MIT, see LICENSE.