MuffMode Configuration Reference

August 26, 2026 · View on GitHub

README | Player Guide | Server Host Guide | Gameplay Reference | Rulesets

This is the lookup document for MuffMode commands, cvars, vote options, and factory behavior. It is mainly for server hosts, admins, and competitive organizers who already know what setting they want to change. Players should start with the Player Guide; hosts should start with the Server Host Guide.

Admin Commands

Use commands in the form command [arg].

CommandPurpose
adminAuthenticate or use admin functionality, depending on server setup.
startmatchForce match start when warmup conditions apply. In MuffMode Arena it targets the admin's selected room and bypasses that room's ready wait.
endmatchForce an active match to end. In MuffMode Arena it aborts only the admin's selected room.
resetmatchReset the match to warmup. In MuffMode Arena it resets only the admin's selected room.
map_restartRestart the current level/session and apply latched cvar changes.
setmap <map>Change to a map in the configured map list.
nextmapForce level change to the next map.
gametype <gametype>Change gametype and reset the level.
`ruleset <q2remm
shuffleShuffle and balance teams, then reset the match.
balanceBalance teams without a shuffle.
setteam <player> [auto|red|blue|spectator]Inspect or force a player team change.
`lockteam <redblue>`
`unlockteam <redblue>`
readyallForce all players ready during ready-up warmup; in MuffMode Arena, target the admin's selected room.
unreadyallClear ready status during ready-up warmup; in MuffMode Arena, target the admin's selected room.
`vote <yesno>`
forcevoteForce the current vote result.
spawn <entity> [spawn_args]Spawn an entity without requiring cheats.
load_mappool / dedicated console sv load_mappoolReload the structured pool and validate its configured cycle.
load_mapcycle / dedicated console sv load_mapcycleReload only the configured structured cycle.
Dedicated console sv ghost_diag [reset]Report ghost capture eligibility/rejections, live reinstatement outcomes, deferred skin synchronization, and game-side reliable-message budget counters. The optional reset reports first, then clears the lifetime counters. Engine netchan backlog occupancy is not available through the game API.
Dedicated console sv graceful_shutdown [cancel]Mark the current map as the final one and notify connected players immediately, whenever another human joins, and once per minute. The server closes cleanly after the normal end-of-level scoreboard, map choice, and awards finish; with no human clients it closes immediately. The optional cancel keeps the server open if the final boundary has not been reached. Listen servers reject this command.
loadmotdReload the message of the day file.
doctorPrint diagnostics for risky or inconsistent cvar combinations.
boot <player>Remove a player, depending on server admin configuration.
`handicap <onoff>`
handicap_clearClear duel weapon restrictions.

Client Commands

The most useful player-facing commands are documented in the Player Guide. This quick list is provided for lookup:

AreaCommands
Displayannouncer, eskin, fm, help, id, infohud, kb, timer, tskin
Match stateready, notready, readyup, readyteam, forfeit, arena timeout, arena timein, time-out, time-in
Team selectionteam auto, team red, team blue, team free, team spectator
Votingcallvote, cv, vote yes, vote no
Server infomaplist, mapinfo, motd, players, stats
Spectatingfollow, follownext, followprev, followview, followkiller, followleader, followpowerup
Hookhook, unhook
Arena roomsarena list, arena go, arena leave, arena status, arena settings
Room teams and queuearena line, arena queue, arena create, arena join, arena teamleave, arena ready
Room chatsay_arena, say_world, arena say, arena say_team, arena say_world
Reconnect recoveryghost <code>
Captainscaptain, teamcaptain, teamname, teamlock, teamunlock, teamkick, teammute, teamunmute

Arena Room Commands

The arena dispatcher is available only while the Arena gametype is active on a validated Arena-compatible map. Tagged multi-room maps use positive room IDs and reserve arena 0 for the lobby; a classic one-room idmap uses the legacy profile described below. The normal Multiplayer menu exposes Browse Rooms or Change Room, Teams & Queue, and Return to Lobby without replacing its standard Follow, Player Config, Vote, Stats, Server, Match, and Admin entries. MuffMode's existing team, captain, lockteam, unlockteam, ready, notready, readyup, readyteam, vote, time-out, and time-in commands are room-aware and remain the native shortcuts. Convenience forms under arena use the same room-local state and shared command policies.

CommandPurpose
arenaShow the selected room's status/settings, or list rooms from the lobby.
arena listList every discovered room, its name/type, population, and state.
arena go <id>Enter or observe a playable room. Selector teleporters and the join menu provide the same navigation.
arena leaveLeave the current room and return to the lobby.
arena status / arena settingsShow the current room state or its effective settings.
arena line [on|off] / arena queueJoin or leave a Rocket Arena-type room's queue, or inspect that queue. line is retained as the historical command spelling.
arena create [name]Create a logical team in the current room.
arena join <team-id|player|red|blue> [password]Join a named/logical team or a fixed red/blue side in the current room.
arena teamleaveLeave the current logical team without leaving the room.
arena name <name> / arena captain [player]In competition mode, rename the team or inspect/transfer its captain role.
arena lock [password] / arena unlockIn competition mode, control entry to the logical team. Administrators may explicitly override this restriction outside competition mode. Passwords are a MuffMode extension.
arena kick [player]In competition mode, list team members or let the captain remove one.
arena teammute / arena teamunmuteIn competition mode, the captain can restrict noncaptains to team chat or restore their room/world chat. arena mute / arena unmute are aliases.
arena invite <player> / arena revoke <player>In competition mode, grant or revoke access to a locked logical team. This is a MuffMode extension.
arena specinvite <player> [coach] / arena specrevoke <player>In competition mode, let any non-coach team member grant or revoke same-room private spectating. Coaching is a MuffMode extension.
arena coach <team|player> / arena specwhoIn competition mode, choose a coached team or list the caller's team spectators/coaches and outstanding invitations.
arena ready [0|1]In competition mode, toggle ready state or set it explicitly.
arena propose <key> <value> / arena vote <yes|no>Start or answer a room-local settings ballot.
arena timeout / arena timeinPause using the active side's competition allowance, or resume a timeout called by that same side.
arena say <message> / arena say_team <message> / arena say_world <message>Send room, logical-team, or map-wide chat.
arena admin <arena> <setting|reset|start|abort> [value]Administer one room without changing the others.

The RA3-era commands teamlock, teamunlock, teamcaptain, teamname, teamkick, teammute, teamunmute, specinvite, specrevoke, specwho, timeout, and timein are registered conveniences for the corresponding room-local operations when the client and engine forward those tokens to the game DLL. MuffMode's older lockteam, unlockteam, captain, time-out, and time-in spellings remain available and are the portable forms. Q2RE owns some client-console tokens locally, notably timeout; use arena timeout or time-out in that case. These aliases preserve familiar input, but do not replace MuffMode's own team, room, and queue controls.

say_arena <message> is the portable direct arena-chat command, including on KEX clients where the engine owns ordinary say. It becomes world chat in the lobby. arena say_team <message> is the portable logical-team channel. KEX also owns bare say_team, so that form follows the projected engine red/blue team and cannot apply MuffMode's room-local logical-team filtering. say_world is always map-wide.

MuffMode stores each server-side version-2 player profile in baseq2/pcfg/profiles/sid-<encoded-social-id>.json, using a safe hex encoding of the engine-provided social ID and a directory that cannot collide with WORR's legacy filename scheme. Missing or unusually long social IDs keep session-only state instead of using fallback filenames. The versioned JSON schema records current, original, and up to 16 previous player-name aliases; first-seen, last-seen, and last-updated timestamps; display, audio, follow, and skin preferences; a custom weapon preference order; per-gametype skill ratings, latest rating changes, and match counts; and aggregate match totals for wins, losses, draws, abandons, play time, and best rating. Profile data never grants administrator or ban authority.

A new player's first 20 rated matches in a gametype use a higher Elo K-factor (48 instead of the usual 32), so their rating converges toward their true skill faster instead of taking dozens of matches to climb out of the 1500 default. This is tracked per gametype, so a veteran duelist starting Capture the Flag for the first time is still provisional there. Once a player passes 20 matches in a gametype, further rating changes there use the standard K-factor.

The JSON profile in baseq2/pcfg/profiles is the canonical file. When it is missing, MuffMode performs a one-time import from either the previous root-level baseq2/pcfg/sid-<encoded-social-id>.json location or a matching WORR profile that uses WORR's older sanitized-social-ID .json filename, then publishes the migrated version-2 profile in the canonical directory. A legacy document's full socialID must exactly match the authenticated identity, so sanitizer collisions are never trusted. When the canonical path is absent and no usable legacy JSON profile can migrate, MuffMode can seed the new profile from the older baseq2/pcfg/sid-<encoded-social-id>.cfg preference file; subsequent saves update JSON. Corrupt canonical JSON and canonical files whose stored identity does not match the authenticated social ID are quarantined before recovery without importing a stale .cfg over them. Profiles with a newer unsupported schema are left untouched rather than guessed at. Retained clients reload transactionally across map and gametype changes, so an unreadable profile cannot erase the live session state. A client whose current profile could not be loaded remains playable with session-only settings, but persistence stays disabled and any match containing that player is unranked until a later successful load.

Writes use unique temporary files, durable atomic replacement, and a bounded per-profile interprocess lock. Accepted preference changes are coalesced and debounced in bounded memory, then persisted by a fair frame pump. Each normal save merges only the changed preference fields into the latest profile document and preserves unknown extension keys, so delayed work from one connection cannot overwrite an unrelated setting written elsewhere; if the document must be recreated, the complete trusted pending preference snapshot is restored instead of defaulting untouched settings. Failed attempts retry with backoff, merge into later profile work, and use an exact-generation check so an older delayed writer cannot clear newer choices. Match-result failures retain the exact computed result in per-identity FIFO order and retry with bounded backoff and fair per-frame work instead of recalculating Elo. Settlement admission is also bounded: if the server cannot guarantee queue space for every required profile result, the match becomes sticky-unranked and no Elo update is applied. Non-Duel departures likewise make the whole match sticky-unranked so an early quitter can never receive Elo before a later bot, failed profile load, or persistence-capacity failure invalidates the remaining result; an exact two-player Duel forfeit still settles both sides atomically and ends immediately.

During reconnect recovery, the reserved gameplay snapshot remains authoritative for settling and exporting the match that was already in progress. Once that match closes, MuffMode reconciles the admitted result onto the reconnecting client's current profile state. A successfully loaded reconnect profile supplies the next match's preference base; if that load failed, the trusted reserved preferences and weapon order remain in place. Changes made during the reinstatement delay are layered over either base.

The in-game Player Config menu exposes the same saved preferences through separate Display & Audio, Spectator & Follow, and Skin Overrides pages. Inventory-menu controls remain available during intermission so Player Config and Player Stats can be reviewed after the match. The optional voice announcer defaults to off and can be enabled with announcer on or from Display & Audio; stock fallback cues remain available where defined. Free-form skin paths are still entered with eskin <model/skin> and tskin <model/skin>.

Match Statistics Exports

Completed singleton matches in the normal WORR-supported gametypes can produce a versioned structured record at baseq2/matches/<sanitized-match-id>.json, an optional companion HTML report at the same stem, and the atomic baseq2/matches/catalog.json artifact index. Every intermission path freezes one exact result before client state can change. The match record includes server and listen-host attribution, match and team totals, every participant including players who departed before the end, the settled win/loss/draw/abandon/no-contest result, rating results, weapon and damage statistics, deaths and spawns, item timing, medals, CTF actions, and bounded event and death logs with explicit truncation markers. Serialization and writes normally run in the background, report each success or failure, and fall back to a synchronous write if the bounded queue is full. JSON and catalog publication are the required pair; an HTML failure is reported but does not discard a valid JSON match. Catalog access is interprocess-locked, strictly size- and structure-bounded, quarantines malformed data, keeps latest chronological even when jobs complete out of order, and retains at most 4,096 artifact entries within a 16 MiB catalog; the oldest entries are pruned first without deleting their standalone match files.

Arena Rooms run multiple independent room series at once, so they remain unranked and are not exported; their live Player Stats menu continues to use room-local counters. Horde is co-op PvE rather than a contest between players, so it is unranked for the same reason — no Elo settlement, no awards reel, and match totals are not persisted to player profiles. For the same reason, MuffMode's MATCH_LOGGING_STATUS_API_V1 smoke status validates the singleton match schema and its real atomic catalog write path, but does not advertise WORR tournament-series fields.

These artifacts are controlled by the g_statex_* cvars below. They are independent of g_matchstats, which controls only the live in-game match-statistics menu.

Vote Commands

Use callvote <command> [arg] or cv <command> [arg].

CommandArgumentPurpose
map<mapname>Change to a specific map.
nextmapnoneMove to the next map in rotation.
restartnoneRestart the current match.
gametype<gametype>Change gametype.
timelimit<0..1440>Change match time limit in minutes; 0 disables.
scorelimit<0..>Change score limit; 0 disables.
fraglimit<0..>Alias for score limit.
shufflenoneShuffle teams.
balancenoneBalance teams without shuffling.
unlagged`<01>`
cointossnoneReturn heads or tails.
random<2-100>Return a random number from 2 to the provided value.
ruleset`<q2remm
powerups`<01>`
friendlyfire`<01>`
techs`<01>`
handicap` <onoff>`
readyallnoneReady all players during ready-up warmup.
factory<factory>Change the active factory preset. See Factories.

Vote Flags

g_vote_flags is a bitmask. Add values together to disable multiple vote commands.

ValueDisables
1map
2nextmap
4restart
8gametype
16timelimit
32scorelimit and fraglimit
64shuffle
128unlagged
256cointoss
512random
1024balance
2048ruleset
4096powerups
8192friendlyfire
16384handicap
32768readyall
65536techs
131072factory

Gametype Values

ValueShort nameGametype
1ffaDeathmatch
2duelDuel
3tdmTeam Deathmatch
4ctfCapture the Flag
5caClan Arena
6ftFreeze Tag
7strikeCapture Strike
8rrRed Rover
9lmsLast Man Standing
10hordeHorde Mode
14arenaArena Rooms (Rocket Arena)

Values 11 (ball), 12 (instagib) and 13 (nadefest) are not selectable in the current build; setting one falls back to Deathmatch with a console notice. Instagib and NadeFest are modifiers rather than gametypes -- they are g_instagib and g_nadefest, applied on top of whichever mode is running, and the shipped factories.cfg provides them (and their combinations with the team and round modes) as named presets. The ids are retained so arena keeps id 14 and existing configs do not renumber.

Factories

A factory is a named gameplay preset: one base gametype plus a set of cvar overrides and structured directives. Factories are how a MuffMode server is configured for play. They replaced the per-gametype gt-*.cfg presets the mod used to execute automatically, so nothing runs underneath a factory — a setting no factory states holds whatever server-base.cfg left in it.

Factories exist so one server can offer several flavours of the same gametype — classic CTF and Insta CTF, a competition Clan Arena and a casual one — selectable by name, by an admin, from the server console, or by vote.

Definitions live in baseq2/factories.cfg. The shipped catalogue provides 58 selectable presets — a classic and a competitive variant of each gametype, plus the Instagib, NadeFest, Vampiric, Frenzy and Quad Hog modifier presets for the modes where each makes sense (instagib, instactf, instaca, vampffa, vampca, frenzyctf, nadefest, and so on) — layered on eleven hidden _base_<mode> factories, one per gametype, that carry each mode's baseline, plus two hidden test entries. 71 definitions in all. Run factory list all to see every id and factory info <id> to see exactly what one changes. Set g_factory_file to load a different file, or several, separated by spaces.

Instagib and NadeFest used to be gametypes. They are modifiers now — applied on top of whichever mode is running — so they exist as factories rather than as g_gametype values. That is what makes Insta CTF and NadeFest Clan Arena expressible at all.

Writing a factory

factory ctf_classic {
    title    "Capture the Flag"
    desc     "Classic CTF with grapple and techs."
    base     ctf
    ruleset  q2re
    inherit  _base_ctf

    maps     q2ctf1 q2ctf2 q2ctf3 q2ctf4 q2ctf5
    mappool  q2ctf1 q2ctf2 q2ctf3
    rotation shuffle-per-gametype
    players  4 16

    set capturelimit 8
    set g_allow_grapple 1
}
KeyRequiredMeaning
factory <id>yes1–31 characters of a-z 0-9 _ -. An id beginning with _ is hidden from listings and from the vote menu, but can still be selected by name. The subcommand words (all, clear, cvars, diag, info, list, none, reload) are rejected, since a factory with one of those ids could never be selected.
titleyesDisplay name, published in serverinfo. Under 48 characters; no \, ; or ".
desc (or description)noOne line shown by factory info.
base (or basegt)yesBase gametype short name: ffa duel tdm ctf ca ft strike rr lms horde arena.
rulesetnoq2re, mm, q3a, q2reb, q or qc.
inheritnoAn earlier factory id with the same base gametype; its overrides and directives are the starting point.
mapsnoThe map rotation. Repeat the key to add more; a rotation is usually longer than one line allows.
mappoolnoThe maps offered to map votes and MyMap.
rotationnosequential, shuffle-on-wrap or shuffle-per-gametype.
playersno<min> <max> active players for this mode.
set <cvar> <value>noOverride an allowlisted cvar. Use "" to clear one.

maps, mappool, rotation and players are directives rather than plain set lines because they carry structure a bare string cannot: a map token is interpolated straight into a gamemap command, so it goes through the same validation the structured map system applies everywhere else, and the player limits are range-checked against each other. A rotation is also routinely longer than the value length a set line permits.

When a child factory names its own maps, it replaces the inherited rotation rather than extending it — otherwise an Insta CTF variant would inherit the deathmatch rotation it was trying to override. Directives the child does not name are inherited.

Layering

Each authority writes at a different moment, and that ordering is the precedence — there is no runtime arbiter to disagree with:

OrderAuthorityWhen it writes
1Compiled defaultscvar registration at level start
2server-base.cfg and your own autoexecserver start
3Factory overrides and directivesimmediately before the map load that follows a gametype or factory change
4Map worldspawn and Arena room configmap spawn / room setup
5Admin cvar write or a passed voteimmediately, and it stays until something writes the cvar again — a factory only re-asserts its own settings on a gametype or factory change

server-base.cfg keeps ownership of server scope — hostname, maxclients, admin and vote policy — and supplies the baseline a factory layers on top of. A factory can never reach those, deliberately: a vote must not be able to rename your server or resize its slab.

Restoring on a switch

Every cvar a factory writes is recorded with the value it had beforehand. Selecting a different factory restores every setting the outgoing factory changed and the incoming one does not re-assert, then applies the incoming overrides. Selecting no factory (factory none) restores all of them.

Restoration goes back to the value the server's own configuration produced — what server-base.cfg left behind — not to a compiled default, because that is the value the operator actually asked for. This is why server-base.cfg states the mutators explicitly even though they are off by default: stating a value is what establishes the value a mutator factory restores to.

Which cvars a factory may set

Factories may only set cvars on a fixed allowlist of 221 names. This is what makes the restore exact: the system can only give back settings it knows it owns. It also bounds the blast radius of an operator-authored file — server identity, the client slot allocation, authentication, and every sv_/cl_/fs_/net_/in_/bot_ cvar are unreachable, and a factory can never create a cvar.

CategoryCountCovers
Match limits and flow12fraglimit, timelimit, capturelimit, roundlimit, roundtimelimit, mercylimit, g_dm_overtime, g_match_lock, g_round_countdown, g_dm_do_warmup, g_warmup_countdown, g_warmup_ready_percentage
Mutators9g_instagib, g_instagib_splash, g_nadefest, g_quadhog, g_frenzy, and the four g_vampiric_*
Loadout, items, damage, movement, teams35g_start_items, g_starting_health_bonus, g_infinite_ammo, g_dm_weapons_stay, g_weapon_respawn_time, g_no_powerups, g_knockback_scale, g_damage_scale, g_dm_no_fall_damage, g_friendly_fire, g_teamplay_force_balance, g_lms_lives, and similar
CTF and techs4g_allow_grapple, g_allow_techs, g_grapple_damage, g_grapple_offhand
Arena rooms30every g_arena_*
Freeze Tag14every g_freezetag_*
Horde117every g_horde_*

Weapon damage, spread, pellet counts and projectile speeds are the ruleset's numbers and are deliberately absent. A factory selects a ruleset by name with ruleset <q2re|mm|q3a|q2reb|q|qc> and never overrides its numbers. See docs/rulesets.md. The map rotation and player limits are absent for the opposite reason: they are directives, with validation a set cannot do.

factory info <id> prints exactly which of these a factory sets; a set naming anything else is rejected by file, line and reason when the registry loads.

When an override takes effect

Selecting a factory always triggers a map change, and everything it carries is written before that map load — so every override lands at a clean boundary regardless of its kind. factory reload and sv gt_apply re-apply only the settings that can take effect mid-map, and report how many were deferred:

  • Immediate — read fresh at the point of use; applies at once.
  • Map load — captured during map spawn; applies at the next map load.
  • Latched (g_instagib, g_nadefest, g_quadhog, g_frenzy, g_infinite_ammo, g_quick_weapon_switch, and a few others) — these are CVAR_LATCH because the world they describe is built at map spawn. Writing one mid-map moves the cvar but not the item layout or loadout it governs, so a factory treats them as map-load settings and says so rather than reporting a change nobody can see.

factory diag <cvar> reports an allowlisted cvar's current value, who set it, what it will be restored to, and which of the three classes it falls into.

Failure handling

A factory file is parsed whole before any of it is used, and the new registry replaces the old one only if the file parsed — a bad edit leaves the working registry in place, so it cannot leave a server with no factories. A malformed definition is rejected on its own, named by file, line and reason, and the rest of the file still loads. An unknown g_factory selects nothing, clears itself, and lists what was available; it never guesses. A factory whose base does not match the configured gametype is discarded with a console notice rather than silently switching the mode out from under the operator. A factory file contains no console commands, so there is nothing to expand.

Host permissions

Everything a player can do to the mode is gated by cvars the operator sets in server-base.cfg, which no factory and no vote can reach:

CvarEffect
g_votable_factoriesSpace-separated ids players may vote for. Empty allows every non-hidden factory.
g_vote_flagsAdd 131072 to disable factory votes entirely.
g_votable_gametypesWhich gametypes may be voted directly.
g_allow_voting, g_allow_vote_midgameWhether votes run at all.
g_allow_adminWhether players may authenticate as admin and use factory <id>.
g_gametype_locked1 pins the gametype and factory: admin commands and passed votes are both refused with selection locked. The server console and rcon still get through, so an operator cannot lock themselves out.

Cvars

CvarDefaultPurpose
g_factory""Active factory id. Empty means no factory: the plain gametype runs on your server-base.cfg values. Carried across a map change.
g_factory_title""Read-only. The active factory's display title, published in serverinfo.
g_factory_filefactories.cfgSpace-separated leaf names under baseq2/ to load the registry from. Latched: a change takes effect at the next server start, or immediately on factory reload. Later files override earlier ones by id.
g_votable_factories""Space-separated ids players may vote for. Empty allows every non-hidden factory.
g_gametype_locked01 refuses every gametype and factory change from an admin command or a passed vote. The server console is exempt.

Commands

CommandAccessPurpose
factoryallShow the active factory and the ones available for the current gametype.
factory list [gametype|all]allList factory ids, optionally for one gametype.
factory info <id>allShow a factory's title, base gametype, source file and every setting it changes.
factory cvars [prefix]allList the cvars a factory may set, optionally filtered by prefix (factory cvars g_arena).
factory diag <cvar>allShow where an allowlisted setting's current value came from and what it restores to.
factory <id>adminSelect a factory. Triggers a map change.
factory noneadminClear the factory and restore everything it changed.
factory reloadadminRebuild the registry from disk and re-apply what can take effect now.
sv factory <id|none>consoleSelect or clear a factory from a dedicated server console. Exempt from g_gametype_locked.
callvote factory <id>allVote to change factory (vote flag 131072).
sv gt_applyconsoleServer-console equivalent of factory reload.

Ids beginning with _ are hidden from listings and from the vote menu, but can still be selected by name.

Ruleset Values

For player-facing differences between these options, see the Rulesets guide.

ValueShort nameRuleset
1q2reQuake II Rerelease
2mmMuff Mode
3q3aQuake III Arena style
4q2rebQ2RE Balanced
5qQuake style
6qcQuake Champions style

Cvar Changes

Deathmatch respawns use a WORR-style danger score instead of raw farthest-only modes. Spawn selection avoids blocked points, recent combat heat, direct enemy line of sight, nearby players, the player's previous spawn point, and nearby mines or traps. g_dm_spawn_farthest is retained for legacy config compatibility, while g_dm_respawn_point_min_dist controls hard spacing from the previous spawn and nearby players.

  • g_teamplay_force_join was renamed to g_dm_force_join.
  • Mod-based sv_* cvars were renamed to g_*.
  • g_teleporter_nofreeze was renamed to g_teleporter_freeze, with reversed meaning.
  • deathmatch defaults to 1.

Core Cvars

CvarDefaultPurpose
hostnameWelcome to Muff Mode!Server name shown in menus. Keep it short for display.
maxclientsengine defaultConnected client slots allocated by the engine and game. MuffMode clamps this to 1..128 during PreInit, before the engine sizes its client slab.
maxplayers16Maximum active players; capped to the allocated game.maxclients. Spectators may occupy the remaining connected slots.
minplayers2Minimum active players.
deathmatch1Enables deathmatch mode.
g_gametype1Current gametype index.
g_ruleset1Current ruleset index.
timelimit0Match time limit in minutes.
fraglimit0Frag limit where applicable.
capturelimit8Capture or objective limit where applicable; Capture Strike applies its own default.
roundlimit8Round wins needed in round-based gametypes. In Horde, this caps the number of waves; set to 0 for endless Horde (see Horde Late-Wave & Endless).
roundtimelimit2Round time limit in minutes.
mercylimit0Score gap to end match; 0 disables.
noplayerstime10Minutes with no players before forcing a map change; 0 disables.

The KEX lobby capacity is separate from maxclients. Packaged servers request the same value with kexmultiplayer maxplayers, because the stock game-module API does not expose the active lobby provider's limit. Keep the two configured values aligned, but expect a provider or engine build to enforce a lower service-specific ceiling. The shared Quake II protocol limit remains 256; MuffMode's supported connected-client ceiling is 128.

Bundled Lobby Presets

Execute one preset before creating a KEX lobby so its connected-client allocation and lobby-capacity request are both in place:

FileCapacityStartup and policy
lobby-casual.cfg16Unranked House Deathmatch; random structured rotation; curated classic factory voting; map votes and MyMap enabled.
lobby-competitive.cfg16Ranked Duel Competition; ordered structured rotation; competition factories; map votes and MyMap disabled.
lobby-party.cfg16Unranked Instagib Jump; random structured rotation; curated mutator factories; map votes and MyMap enabled.
lobby-horde.cfg8Unranked Classic Horde; random structured rotation; Horde factories only; map votes and MyMap disabled.

Each executes server-base.cfg, sets maxclients and kexmultiplayer maxplayers, enables the production pool/cycle, and selects a starting g_gametype/g_factory pair. The files are package-owned templates; for customization, copy the baseline, chosen lobby, pool, and cycle to operator-owned leaf filenames and update all three references in the copied lobby. Executing a preset after a lobby already exists cannot resize that existing provider lobby.

Access And Player Policy

CvarDefaultPurpose
g_allow_admin1Allows admin powers.
admin_passwordemptyExact, case-sensitive password accepted by admin <password>. Empty disables password authentication. Attempts share the client flood history and settings; flood_msgs <= 0 disables this throttle.
g_allow_custom_skins1Allows custom player models and skins.
g_allow_skin_overrides1Allows players to re-skin enemies/teammates on their own screen via the eskin/tskin commands (team games; in duel, eskin re-skins your opponent).
g_allow_forfeit1Allows Duel forfeits.
g_allow_grappleautoControls normal grapple availability. auto follows mode defaults; 0 disables; 1 enables.
g_allow_kill1Allows the kill suicide command.
g_allow_mymap1Allows MyMap queueing.
g_allow_spec_vote0Allows spectators to vote.
g_allow_techsautoControls tech pickups in FFA/TDM/CTF/Horde. auto enables techs by default in CTF and Horde (off in FFA/TDM); votes can force 0 or 1 in any of those modes.
g_allow_vote_midgame0Allows votes during active matches.
g_gametype_locked0Pins the gametype and factory. 1 refuses every gametype or factory change from an admin command or a passed vote; the server console and rcon are exempt so an operator cannot lock themselves out. See Factories.
g_allow_voting1Enables voting globally.
flood_msgs4Flood-controlled client actions (including chat, authentication attempts, gestures/pings, motd, and mymap) allowed within the shared window; values above the ten-entry history capacity are clamped to 10, and values at or below 0 disable this protection.
flood_persecond4Length of the shared client flood-detection window in seconds.
flood_waitdelay10Seconds a client must wait after triggering the shared client flood protection.
g_inactivity120Seconds before inactive players are moved to spectators.
g_match_lock0Adds automatic playing-team locks during countdown and active play. Full Duel challengers still join its spectator queue; disabling it releases only automatic locks and preserves captain/admin locks.
g_owner_auto_join1Auto-joins lobby owner on server start.
g_owner_push_scores0Shows scores to lobby owner on join.

Match Cvars

CvarDefaultPurpose
g_dm_allow_no_humans1Allows matches with only bots.
g_dm_death_scoreboard1Automatically opens the scoreboard when a player dies in deathmatch.
g_dm_auto_join0Automatically joins players into the active play pool when allowed by the current mode.
g_dm_do_warmup1Enables match warmup.
g_dm_do_readyup0Requires ready-up during warmup.
g_dm_force_join0Forces players to join instead of staying spectator, depending on mode.
g_dm_force_respawn1Forces respawn after death when the mode allows it.
g_dm_force_respawn_time3Seconds before forced respawn.
g_dm_intermission_shots0Allows players to continue firing during the brief intermission pre-delay.
g_dm_overtime120Overtime session length in seconds.
g_dm_tie_max_time1800Maximum total tied-overtime duration.
g_dm_respawn_delay_min1Minimum delay after death before respawn.
g_dm_respawn_point_min_dist256Minimum respawn distance from the previous spawn point and nearby players.
g_dm_respawn_point_min_dist_debug0Prints spawn avoidance debug information.
g_dm_spawn_farthest1Legacy spawn-mode compatibility cvar; respawns use combat-aware scoring.
g_dm_spawnpads1Controls deathmatch spawn pads.
g_auto_ghost_time120Seconds an auto-ghost reservation remains available, up to 3600; 0 disables auto-ghost capture.
g_auto_ghost_max3Maximum active auto-ghost reservations, capped by client capacity; 0 disables auto-ghost capture.
g_auto_ghost_timeout0Auto-pauses an active match for disconnected players, in seconds capped by g_auto_ghost_time; 0 disables.
g_dm_timeout_length120Timeout length in seconds; 0 disables timeouts.
g_dm_timeout_resume_countdown30Countdown announced before a paused match resumes, in seconds up to 120; 0 resumes immediately.
g_round_countdown10Round countdown time.
g_warmup_countdown10Warmup countdown time.
g_warmup_ready_percentage0.51fReady percentage required to start.

Team Cvars

CvarDefaultPurpose
g_friendly_fire0Enables friendly fire.
g_team_force_models0Forces team player models/skins when enabled.
g_team_red_modelmale/ctf_rModel/skin used when red team models are forced.
g_team_blue_modelfemale/ctf_bModel/skin used when blue team models are forced.
g_teamplay_allow_team_pick0Allows players to choose teams directly.
g_teamplay_armor_protect0Enables teamplay armor-protection behavior.
g_teamplay_auto_balance1Rebalances teams during matches.
g_teamplay_force_balance0Prevents joining over-stacked teams.
g_teamplay_item_drop_notice1Announces item drops to teammates.

Arena Room Cvars

Arena supports up to 31 independent playable rooms plus arena 0, the lobby, on a tagged map. These cvars form the global default layer; arena.cfg can override them by map and room.

CvarDefaultPurpose
g_arena_configarena.cfgLatched configuration file resolved beneath basedir/baseq2; missing files are harmless and reported before built-in/cvar defaults are used.
g_arena_legacy_idmap0Latched compatibility switch for an otherwise untagged classic RA2 idmap. Explicit worldspawn arena 0 uses the legacy profile without this switch; set 1 before the next map load only when importing untagged idmaps. In this one-room profile, any entity arena tags are treated as shared.
g_arena_default_typerocketDefault room type: rocket, clan, rover, or practice.
g_arena_players_per_team1Default team size, clamped from 1 through half of maxclients.
g_arena_rounds1Default room best-of length, normalized to an odd value from 1 through 99.
g_arena_start_health200 (100 in the shipped Arena factories)Shared arena-loadout starting-health default. The shipped Arena factories select the classic 100-health value without changing Freeze Tag's default.
g_arena_start_armor200 (100 in the shipped Arena factories)Shared arena-loadout armor; the shipped Arena factories select the traditional 100-armor value without changing Freeze Tag's default.
g_arena_health_protect1Health protection: 0 damages all, 1 protects self and teammates, 2 protects teammates but permits self damage.
g_arena_armor_protect2Armor protection using the same 0/1/2 modes. The default permits self-armor damage while protecting teammates.
g_arena_falling_damage1Default falling-damage behavior.
g_arena_weapon_mask255Default spawn-weapon mask; 255 enables the standard non-BFG set.
g_arena_ammo_shells100Starting shells.
g_arena_ammo_bullets200Starting bullets.
g_arena_ammo_grenades20Starting grenades.
g_arena_ammo_rockets50Starting rockets.
g_arena_ammo_cells150Starting cells.
g_arena_ammo_slugs50Starting slugs.
g_arena_fast_switch1Enables accelerated weapon switching.
g_arena_grapple0Grants the room-scoped selectable Grapple and enables the offhand +hook; it is independent of the global grapple cvars.
g_arena_excessive0Enables rapid fire, faster rockets, and infinite ammo with matching HUD reporting.
g_arena_rocket_speed900Default room rocket speed.
g_arena_competition0Requires the per-room ready/competition flow.
g_arena_warmup_readyup1Requires the per-room MuffMode warmup ready-up even when competition mode is off. With 0 a room starts as soon as two eligible sides pair up, and ready is rejected.
g_arena_unbalanced0Allows unequal team sizes.
g_arena_lock0Starts playable rooms locked to new entrants.
g_arena_lock_count6Minimum eligible population for the unanimous special lock-arena proposal. It does not lock entry by itself.
g_arena_max_players0Per-room player cap; 0 uses the available server capacity.
g_arena_vote_time30Seconds allowed for a room-local proposal.
g_arena_timeouts3Competition timeouts available to each side.

Each room runs its own warmup rather than sharing the level-wide match state, so several rooms can be waiting for players, balancing, or counting down at the same time. A room reports what it is waiting on through the HUD (WARMUP - NEED PLAYERS, WARMUP - UNBALANCED, WARMUP (n/m READY)), a centerprint every 30 seconds, and the scoreboard status line. Room warmup reuses the shared warmup cvars: minplayers for the player floor, g_warmup_ready_percentage for the ready threshold, g_dm_allow_no_humans to permit a bots-only room, and g_warmup_countdown for the first countdown of a series while g_round_countdown covers each later round. Both countdowns clamp to 1-30 seconds.

Arena bots choose their own room: they follow players into an occupied room, prefer one where somebody is waiting for an opponent, and take an opposing team, creating one when a lone player has nobody to fight. To populate rooms automatically, set bot_minClients in your own server config -- it is an engine-owned bot_ cvar, so a factory cannot set it.

Arena timeouts use the existing g_dm_timeout_length duration and g_dm_timeout_resume_countdown time-in countdown. g_arena_timeouts remains separate because its per-side allowance is unique to room competition. The shipped arena_ra2 factory selects 60 seconds and a five-second time-in.

g_arena_weapon_mask is the sum of the enabled weapon bits:

BitWeapon
1Chainfist (RA3 Gauntlet role)
2Machinegun
4Shotgun
8Grenade Launcher
16Rocket Launcher
32Plasma Beam (RA3 Lightning Gun role)
64Railgun
128HyperBlaster (RA3 Plasma Gun role)
256BFG10K

The mask is MuffMode's native explicit loadout setting. An empty mask receives a Chainfist as a safety fallback; otherwise each bit is authoritative. Unsupported bits are discarded. The compact weapons input remains available for compatibility; its native and imported-RA2 number rows are documented below. Each ammo value is clamped from 0 through 999.

Arena map profiles

Tagged multi-room is the preferred MuffMode map profile. Set worldspawn's explicit arena key to the number of playable rooms (1 through 31). Arena 0 is the lobby and needs a finite usable start or destination. Each declared positive room needs at least two finite tagged info_player_deathmatch starts so both active sides can spawn without sharing a point. Room-local spawns, observer positions, teleporters, and triggers carry the same positive arena key. A tagged info_player_intermission can supply a room name and observer view, but it is not required merely to activate a room. A positive tagged misc_teleporter acts as a room selector. Negative legacy values are shared/reserved markers, not lobby aliases.

Classic RA2 idmaps use a one-room compatibility profile. An explicit worldspawn arena value of 0 selects that profile and uses the map's shared deathmatch-start pool as one room; in this profile arena 0 is a profile marker, not a lobby. A map with no worldspawn arena key is accepted as the same legacy profile only when g_arena_legacy_idmap 1 is latched before the next map load. The cvar defaults to 0, so ordinary untagged maps do not quietly become Arena maps. In either legacy route, entity arena tags are treated as shared inside the one virtual room; they do not create isolated subrooms.

Classic RA2 observer views prefer a matching misc_teleporter_dest and fall back to a matching deathmatch start when no destination exists; tagged maps can instead use an intermission view and its mangle/angles.

As in the original RA2/RA3 map contract, playable rooms must occupy BSP-separated visibility/hearing regions. Room tags isolate server gameplay, but the Quake II protocol still distributes generic snapshots and temporary effects by PVS/PHS, so arbitrary arenas overlaid at the same coordinates are not a supported mapping pattern.

Validation runs against the final entity lump before any entity is spawned and is checked again against the live entity set. If preflight validation fails, Arena remains inactive and the requested mode is treated as effective FFA; no room, loadout, isolation, spawn-filter, command, HUD, or room-menu hooks are enabled. A disagreement after entities have spawned hard-rejects the map instead of running a partially modified level. The shipped preset leaves g_map_list empty: install your own Arena-compatible maps and configure an Arena rotation. It leaves the untagged-idmap compatibility switch at 0; set g_arena_legacy_idmap 1 only for a known rotation of untagged classic RA2 idmaps.

arena.cfg layers

Settings resolve in this order: built-in defaults, global cvars and top-level file settings, matching map block, then matching numeric room block. For example:

// baseq2/arena.cfg
health 100
armor 100
type rocket

map mm_arena_hub {
    rounds 3

    room 1 {
        type practice
        grapple 1
    }

    room 2 {
        type clan
        playersperteam 3
        competitionmode 1
    }
}

# and // comments and quoted values are supported. Colons and semicolons from original RA2 files (health: 100;) are optional. Native MuffMode configs make scopes explicit with map <name> and room <id>; arena <id> remains an accepted compatibility alias. Bare RA2-style ra2map1 { 1 { ... } } blocks and maploop are accepted as imported legacy syntax and are detected automatically. A top-level-only arena.cfg defaults to the legacy RA2 weapon row so unmodified old configs work; add format: native; (or format: ra3;) at its top when a global-only MuffMode config needs the RA3 shorthand row. format: ra2; makes that legacy intent explicit. Native map/room scopes are already unambiguous. Map rotation remains owned by MuffMode's existing g_map_list, g_map_pool, and g_map_list_shuffle settings; arena.cfg only resolves room rules.

Recognized aliases include type/gametype, weapons/weaponmask, and playersperteam/ppt. The full setting set is type, pickup, weapons, armor, health, playersperteam, rounds, shells, bullets, slugs, grenades, rockets, cells, plasma, bfgammo, fastswitch, fallingdamage, grapple, rocketspeed, excessive, damagescoring, lockarena, competitionmode, unbalanced, lockcount, maxplayers, maxteams/max_teams, minping, maxping, votetries, armorprotect, and healthprotect. Zero disables a player, team, or ping bound. votetries defaults to two unsuccessful proposal attempts per player per room match; a successful room vote restores every player's allowance, while 0 disables player proposals. Stock RA3 gametype: pickup rooms resolve through the latest layered defpickup value (clanarena by default, with redrover supported), and practicearena is accepted as the original Practice spelling. The RA2-style boolean pickup 1/pickup 0 switch remains available; enabled fixed-team pickup rooms can fill the server capacity and use two teams.

Prefer weaponmask for new MuffMode configs. In explicit native config syntax (or a global file marked format: native;), the weapons: shorthand retains the RA3 compatibility row: 1 Chainfist (Gauntlet), 2 Machinegun, 3 Shotgun, 4 Grenade Launcher, 5 Rocket Launcher, 6 Plasma Beam (Lightning Gun), 7 Railgun, 8 HyperBlaster (Plasma Gun), 9 BFG10K, and 0 grapple. Automatically imported legacy RA2 syntax instead uses the Quake II row: 2/3 select the compact Shotgun role (SG/SSG), 4/5 the Machinegun role (MG/Chaingun), 6 Grenade Launcher, 7 Rocket Launcher, 8 HyperBlaster, 9 Railgun, and 0 BFG10K. In that imported RA2 form, 1 is ignored and 0 is BFG10K, not grapple. allow_voting_* switches can independently permit or deny ballots for type, health/armor, team size, rounds, protection, weapons, falling damage, excessive, locking, competition mode, ping limits, and maximum logical teams. Original unseparated allowvoting* spellings are accepted as compatibility aliases. The shipped policy disables excessive and grapple ballots by default; enable them explicitly when appropriate. Starting-ammo values are server configuration only and cannot be changed by a player ballot.

Quake II uses one cell pool for the HyperBlaster/RA3 plasma role and BFG10K. When those weapons are enabled, the spawn reserve is therefore the largest of cells, plasma, and bfgammo.

The optional roundtimelimit caps a round. Each room evaluates that timer and its outcome independently; the shipped Arena factories leave it at 0, so room rounds are uncapped by default.

Map And Rotation Cvars

CvarDefaultPurpose
g_maps_pool_fileemptyOpt-in MuffMode structured map-pool JSON leaf filename under baseq2; empty keeps legacy map sources active. Never set this to the KEX mapdb.json.
g_maps_cycle_fileemptyOptional structured cycle leaf filename under baseq2; requires a valid structured pool.
g_maps_random11 selects randomly from eligible cycle maps, with popular maps weighted twice; 0 follows cycle order.
g_maps_repeat_delay1800Preferred seconds before a structured-cycle map repeats; clamped to 0–86400 and relaxed if necessary to keep rotation moving.
g_maps_avoid_custom0When enabled, structured-pool entries marked custom are unavailable while the server has no human players or Q2REX reports a console player in the lobby. The restriction covers automatic rotation, post-match picks, map votes, and MyMap, and immediately returns a custom level to a standard map if the server becomes empty or a console player arrives. Other compatible engines still enforce the empty-server half of the rule.
g_map_listemptySpace-separated map rotation.
g_map_list_shuffle10 disables shuffle, 1 shuffles on wrap, 2 shuffles once per gametype session.
g_map_pick15Seconds the post-scoreboard next-map pick stays open; 0 disables it. Clamped to 5–60. See Next-Map Pick.
g_match_awards10Seconds the post-match awards reel stays up unattended before handing on to the next-map pick; 0 disables it. Clamped to 3–30, and skippable with any key after the first three seconds. Ranked matches only. See Post-Match Awards.
g_map_poolemptyAdditional voting map pool.
g_dm_exec_level_cfg0Executes level-specific configs when enabled.
g_loc1Enables location-backed teammate callouts, including the loc command and Freeze Tag frozen help markers.
g_loc_items1Allows location callouts to derive a fallback location from visible weapons, powerups, or mega health when no map .loc file exists.
g_motd_filenamemotd.txtMessage of the day file (maximum 256 KiB). Client output uses UTF-8-safe 900-byte chunks: motd is capped at eight messages and the automatic join preview at one, with a truncation notice for longer text.
g_entity_override_dirmapsDirectory for entity override .ent files.
g_entity_override_load1Loads entity override files on map load.
g_entity_override_save0Saves entity override files when none exist.

Next-Map Pick

When the end-of-match scoreboard — and the awards reel after it, where one runs — is done, the level normally changes straight to whatever the rotation picked. With g_map_pick set, the intermission camera instead holds and everyone chooses the next map from up to three candidates:

set g_map_pick "15"

Candidates come from the same eligibility rules the automatic rotation uses, so the pick can only ever offer a map the rotation would have been willing to load next. The current map is always excluded. With a structured pool the candidates carry their title; on the legacy g_map_pool/g_map_list sources they show the BSP name.

Players choose with the movement keys and attack/jump, or with mappick <1-3> from the console. Live tallies are shown beside each map and a vote can be changed until the window closes. Once a map holds more than half of the eligible voters the pick ends early. Ties are broken at random, and a pick that nobody voted in still resolves to one of the offered maps.

Eligibility follows g_allow_spec_vote, exactly as regular votes do. Bots never vote and are not counted toward the majority.

The pick stands down and the level changes as usual when:

  • g_map_pick is 0, or the gametype is Rocket Arena;
  • the next map was already chosen deliberately — a mymap queue entry, g_dm_same_level, or a forced map;
  • fewer than two eligible candidates exist;
  • no human players remain to ask.

Post-Match Awards

The end of a ranked match is three screens in a row, each handing on to the next the same way: a minimum hold so nobody presses straight through it, then any key, with a timeout so an unattended server still moves.

scoreboard  ->  awards reel  ->  next-map pick  ->  level changes

The awards reel replaces the scoreboard with a title in green and the player who earned it in white underneath.

set g_match_awards "10"

g_match_awards is how long the reel stays up unattended; 0 disables it. Any key advances it early, but not for the first three seconds — otherwise the press that dismissed the scoreboard would carry straight through the reel before anybody had seen it. Once the reel is done the next-map pick opens under its own rules, and the level changes after that.

At most 12 awards are shown, ordered so that the honours come first and the wooden spoons are what get dropped when more than 12 qualify. A single player takes at most 3 titles before the remainder are offered to everyone else, and any slots still unused after that are back-filled from what the cap skipped.

Every award needs a strict winner, so a tie awards nobody, and every award has a floor to clear — "most rail kills" with four kills is not a marksman. Awards range from the earned (SHOTGUN SHERIFF, RAIL SLUT, QUAD GOD, AIMBOT ALLEGATIONS, UNTOUCHABLE) through the observed (SPAWN FRAGGER, DIRTY ROTTEN CAMPER, KLEPTOMANIAC) to the deserved (QUAD DUMMY for hoarding the Quad and doing nothing with it, STORMTROOPER, THE PUNCHING BAG, BUTTERFINGERS). Capture the Flag and team modes add their own.

Awards are a ranked-match feature and are only offered when:

  • g_ranked is on and the gametype is not Rocket Arena;
  • no bot took part, and at least two humans did;
  • the match ran for at least a minute.

Whatever a player earned is repeated in their end-of-match summary, is available from the console with awards, and is written into the match export (matchAwards per match and per player) and into their career profile under stats.awards.

Two of the awards need counters the mod did not previously keep, both collected only while a match is being recorded: kills landed while the attacker's Quad was still running, and a once-a-second sample of where each living player is standing, bucketed into 512-unit cells. The camping award is a share of those samples in one cell, and it explicitly disqualifies anyone the inactivity timer had flagged, so an idle body cannot out-camp a player who was actually playing.

Structured Map Pools (Optional)

The package installs three production map assets with separate jobs:

FileConsumer and schema
mapdb.jsonKEX engine/UI metadata. This is a full stock-derived database, retaining the stock episodes and maps arrays and appending the nine bundled MuffMode maps with KEX dm/tdm/ctf/bot metadata. It preserves stock menus and is not a server rotation policy file.
muffmode-map-pool.jsonMuffMode's strict multiplayer catalog. Its root contains only maps; it adds mode preferences, active-human bounds, popularity, and custom-resource policy.
muffmode-map-cycle.txtMuffMode's ordered or random automatic-selection subset, referring to entries in the strict pool. Catalog-only specialist maps need not appear.

Never point g_maps_pool_file at mapdb.json. The engine database's root and key set do not satisfy MuffMode's strict pool schema, so the load fails closed. The production lobby presets already select the MuffMode pool and cycle. For a different server config, enable them with:

set g_maps_pool_file "muffmode-map-pool.json"
set g_maps_cycle_file "muffmode-map-cycle.txt"
set g_maps_random "1"
set g_maps_repeat_delay "1800"

All three files and the lobby presets are package-owned. Leave mapdb.json as shipped. Before changing pool membership, bounds, weights, or cycle order, copy the pool and cycle to operator-owned leaf filenames and update a copied lobby or server config to name them.

Only safe leaf filenames are accepted for these two cvars; paths and traversal segments are rejected. Pool identifiers are portable lowercase ASCII BSP stems with forward slashes, so safe subdirectories such as q64/dm1 work on both case-sensitive and Windows hosts. Do not add maps/, .bsp, cinematic/demo suffixes, Windows device names, or engine map-command markers such as + and $.

The JSON root must contain a maps array. Each usable entry requires a safe bsp string and at least one true mode flag:

{
  "maps": [
    {
      "bsp": "q2dm1",
      "title": "The Edge",
      "episode": "baseq2",
      "dm": true,
      "duel": true,
      "min": 2,
      "max": 8,
      "popular": true
    }
  ]
}

Supported fields are:

FieldRequiredMeaning
bspyesCanonical lowercase ASCII map identifier with forward slashes and without maps/ or .bsp. Player lookups remain case/slash-insensitive; duplicate identifiers keep the first valid entry.
dm, tdm, ctf, duel, arenaone or moreBoolean mode-suitability flags. CTF and Arena always require their matching flags. Duel/TDM tags are preferred when present, with generic dm maps used as fallback at every eligibility tier.
titlenoDisplay title; defaults to bsp.
episodenoDisplay/filter grouping such as baseq2, rogue, or muffmode.
min, maxnoInclusive active-human-player bounds; 0 or omission means no bound. Bots, spectators, and spare connected slots do not count.
popularnoGives the map weight 2 instead of 1 when g_maps_random is enabled.
custom, custom_textures, custom_soundsnoCatalog metadata. Either asset flag also marks the entry as custom.

g_maps_avoid_custom 1 treats this metadata as an availability rule rather than a display-only tag. The custom restriction is never relaxed to keep a rotation moving. If the configured cycle has no standard candidate, MuffMode uses a standard entry from the structured pool, repeating the current standard map if necessary, instead of escaping through a custom legacy fallback.

The cycle is an ordered whitespace-separated list of bsp identifiers from the pool. It accepts an optional UTF-8 BOM, // line comments, and /* ... */ block comments, removes case/slash-insensitive duplicates, and ignores safe names not found in the pool. Stray or unterminated block-comment delimiters fail the cycle instead of being guessed. With g_maps_random 0, the order determines the next eligible map. With g_maps_random 1, the cycle is the eligible set and popular supplies the only extra weighting.

With a valid pool and cycle, structured selection supersedes the active factory's maps directive for normal automatic transitions and for the map chosen by a factory or gametype change. The factory's g_map_list remains the legacy safety fallback when structured selection is disabled, invalid, or has no compatible candidate.

Selection uses the requested raw gametype, so a transition into Arena can choose an arena-tagged map before that mode becomes effective. It first honors active-human bounds and the repeat delay; Duel/TDM tries its specialized tag before generic dm fallback at each tier. If needed, selection relaxes the repeat delay and then player bounds. Normal next-map selection always excludes the current map. If no other compatible cycle entry remains, legacy g_map_list transition handling continues. When a factory change selects its first map, the load is clamped to the incoming factory's minplayers/maxplayers range rather than using an empty boot server or the outgoing match's population.

The post-match next-map pick uses the same mode, active-human bounds, repeat, and current-map eligibility as automatic rotation. It relaxes cooldown first; if even one player-count-valid map remains, it never adds out-of-range maps just to fill a ballot, and a one-map pick is suppressed. It drops player bounds only when no bounded candidate exists. Direct map votes and MyMap requests intentionally do less: they validate that the requested BSP is a safe member of the active catalog, but do not enforce that entry's mode tags or min/max. This permits an explicit host/player override on Casual and Party lobbies. Competitive and Horde disable map votes and MyMap so those paths cannot bypass their automatic-selection policy.

mm-rail101 is a specialist Railgun/Instagib practice map with no weapon pickups. The schema has no ruleset-or-factory requirement, so the production cycle deliberately leaves it catalog-only for explicit use with an appropriate factory. No bundled map is Arena-compatible: the production pool contains no arena: true entry, the cycle cannot satisfy Arena, and every bundled lobby preset excludes Arena. Install licensed compatible maps and add them to custom pool/cycle and factory policy before enabling that gametype.

An explicit factory or gametype change is the exception to next-map ordering: ordered selection begins at the first compatible cycle entry, matching the legacy "first map after the new gametype config" behavior. That path may reload the current map when it is the first compatible entry; random selection still chooses from the eligible set.

The structured and legacy systems interoperate as follows:

Structured stateVoting and MyMap sourceAutomatic rotation
No valid structured poolLegacy g_map_pool plus g_map_listLegacy g_map_list
Valid pool, but no valid cycleStructured poolLegacy g_map_list
Valid pool and cycleStructured poolStructured cycle, then legacy g_map_list if no eligible map can be selected

Legacy fallback entries use the same safe BSP-stem identity rules as cycle entries, while retaining case-insensitive and slash-insensitive matching. Unsafe or non-map tokens are ignored instead of being sent to the engine.

Malformed roots, unsupported root properties, and oversized inputs fail closed. Unsupported entry properties invalidate that entry so misspelled settings cannot silently change policy. Invalid individual pool entries and unusable cycle tokens are skipped with bounded diagnostics; a pool with no usable multiplayer entries or a cycle with no recognized entries fails. Titles and episodes must be well-formed UTF-8 without terminal, line-breaking, or bidirectional display controls. Once a structured snapshot is active, a failed live reload keeps that complete last-known-good snapshot. If a full pool-and-cycle transaction fails, a later cycle change or load_mapcycle retries the full transaction rather than combining the old pool with a new cycle. On the first load, a valid pool is still published if its configured cycle is invalid, so structured voting/MyMap works while legacy g_map_list handles rotation; if the pool itself is invalid, both uses remain legacy. Clearing g_maps_cycle_file disables only the structured cycle. Clearing g_maps_pool_file disables the structured system immediately and returns both voting and rotation to legacy sources, including during a match timeout.

Players can inspect the active catalog with mappool [filter] and the active cycle with mapcycle [filter]. Filters match map identifiers, titles, and episodes; the exact filters dm, tdm, ctf, duel, arena, popular, and custom select metadata. Each listing prints at most the first 32 matches and asks for a narrower filter when more remain. maplist summarizes both structured status and any active legacy fallback. An authenticated admin can run load_mappool after changing the pool (this transaction also validates the configured cycle), or load_mapcycle after changing only the cycle. A dedicated console can use sv load_mappool and sv load_mapcycle.

Item And Gameplay Cvars

CvarDefaultPurpose
g_arena_start_armor200Global MuffMode Arena starting-armor default; also used by Freeze Tag when g_freezetag_arena_loadout is enabled.
g_arena_start_health200Shared arena-loadout starting-health default; also used by Freeze Tag when g_freezetag_arena_loadout is enabled. The shipped Arena factories override it to 100.
g_arena_dmg_armor0Legacy arena-loadout self-armor switch used outside multi-room MuffMode Arena; GT_ARENA uses each room's independent armorprotect setting.
g_adrenaline_legacy_sound0Plays Adrenaline's original n_health.wav pickup sound instead of the current default (m_health.wav, shared with Mega Health).
g_coop_health_scaling0Scales co-op health by player count.
g_corpse_sink_time15Seconds before corpses sink and disappear.
g_damage_scale1Global damage scale.
g_gib_enhanced1Enhanced gib and debris presentation, built entirely from stock rerelease assets. Gibs take map lighting instead of rendering fullbright, vary in scale, fly nose-first along their velocity, keep the direction of the killing blow instead of having each axis clamped separately, drift and drag in water rather than falling through it, settle flat on floors, and fade out as they sink. Player deaths also mix in the limb, bone and torso gib models the base game precaches for monsters but never gives to players. 0 restores id's original behaviour exactly.
g_gib_impact_effects2Feedback when a gib hits something. 0 disables it, 1 emits the blood or spark burst only, 2 also plays the stock player/gibimp* impact sounds. Effects are rate-limited per gib and server-wide, and gibs that reach a sky brush are removed instead of bouncing off it.
g_gib_max192Ceiling on live gibs across the server. Once reached, the oldest gib is retired so the newest death always looks right. 0 removes the cap; the tracking ring bounds it to 1024 either way. A single deepest-overkill death costs at most 58 entities.
g_dm_explosive_respawn_time60Seconds before a destroyed misc_explobox or func_explosive returns in deathmatch; 0 disables prop respawning entirely. Values are clamped to 1-3600. A prop only returns once no player can see its spot, nothing is standing in it, and no player is within 128 units, so the wait can exceed this time on a busy map.
g_dm_holdable_adrenaline0Allows holdable Adrenaline in deathmatch.
g_dm_instant_items1Makes holdable items activate instantly in deathmatch.
g_dm_item_respawn_rate1.0Global multiplier on every item's respawn time (weapons included).
g_dm_no_fall_damage0Disables deathmatch fall damage.
g_dm_no_quad_drop0Prevents Quad Damage from dropping on death.
g_dm_no_self_damage0Disables self damage after knockback calculation.
g_dm_no_stack_double0Prevents double-stacking behavior for configured deathmatch items.
g_dm_powerup_drop1Drops carried powerups on death.
g_dm_powerups_minplayers0Minimum players required for powerup pickup; 0 disables.
g_dm_random_items0Enables random item replacement behavior.
g_dm_strong_mines0Enables stronger deathmatch mine behavior.
g_dm_weapons_stay0Controls weapons-stay behavior in deathmatch.
g_drop_cmds7Bitflag for dropping flags, powerups, weapons, and ammo.
g_fast_doors1Doubles standard and rotating door speed.
g_freezetag_arena_loadout0Freeze Tag only: set 1 to give players the arena-style spawn/thaw kit using g_arena_start_health, g_arena_start_armor, full weapons, and stocked ammo. The default 0 preserves map/item-control loadouts.
g_freezetag_auto_thaw_time0Freeze Tag only: seconds before a frozen player is thawed automatically; 0 disables auto-thaw.
g_freezetag_bot_rescue1Freeze Tag only: lets bots path toward frozen teammates and hold near them to thaw.
g_freezetag_frozen_hazard_release_time10Freeze Tag only: seconds a frozen body may sit in lava or slime before it is destroyed and its owner respawns, with no thaw credit or score awarded to anyone. A safety valve for bodies shoved somewhere no teammate can reach, so the default is deliberately far slower than g_freezetag_thaw_time — dying in lava must not be a cheaper escape than a rescue. The timer holds while a teammate is actively thawing, and restarts if that attempt is abandoned. Bodies that leave the map are released immediately. Set 0 to disable the watchdog, at the risk of stranding a player for the rest of the round.
g_freezetag_frozen_knockback_scale1.0Freeze Tag only: multiplier for knockback applied to frozen players. Frozen bodies are shovable, and weapons that carry no weapon kick of their own fall back on knockback derived from damage (capped at 200) before this multiplier applies. Set 0 to make bodies immovable.
g_freezetag_frozen_shove_lift24Freeze Tag only: upward speed, in units per second, added to a shove so the body clears the floor and starts sliding. Lower values keep bodies grounded; higher values make them pop into the air.
g_freezetag_frozen_shove_max_speed700Freeze Tag only: speed cap, in units per second, applied to a frozen body after each hit. Prevents several pellets or a sustained grapple pull from stacking into a single map-crossing launch.
g_freezetag_frozen_slide_friction0.9Freeze Tag only: fraction of velocity a sliding frozen body retains on each floor contact, against 0.75 for gibs and dropped items; clamped from 0.1 to 0.99. This alone sets how far a shove carries — at the default a rocket moves a body roughly two body-widths on flat ground, and much further downhill or off a ledge. Lower values stop bodies sooner; values near 0.99 make them slide like ice and creep down ramps.
g_freezetag_multi_thaw_scale0.5Freeze Tag only: extra thaw speed contributed by each additional live teammate near the frozen player; values are clamped from 0 to 4, and total thaw rate is capped.
g_freezetag_round_respawn_all1Freeze Tag only: respawns every round participant for the next round when 1; set 0 to respawn only frozen, dead, or waiting players while live survivors stay in place.
g_freezetag_round_reset_alive_inventory1Freeze Tag only: when full round respawns are enabled, resets live survivor inventory/loadout on the next-round respawn. Set 0 to preserve survivor inventory through that respawn.
g_freezetag_thaw_radius96Freeze Tag only: teammate proximity radius, in units, required to thaw a frozen player.
g_freezetag_thaw_respawn_at_location0Freeze Tag only: when 0, thawed players respawn normally at player spawn points. Set 1 to restore them at the safe thaw location instead.
g_freezetag_thaw_time3Freeze Tag only: seconds a live teammate must remain near a frozen player to thaw them.
g_frenzy0Enables Weapons Frenzy: faster fire rates, faster rockets, regenerating ammo, and faster weapon switching.
g_grapple_offhand0Enables offhand hook commands.
g_grapple_damage10Grapple impact damage.
g_grapple_fly_speed650Grapple projectile speed.
g_grapple_pull_speed650Grapple pull speed.
g_infinite_ammo0Enables infinite ammo when latched before map load.
g_instagib0Enables Instagib as a game modification or through the Instagib gametype.
g_instagib_splash0Adds non-damaging instagib rail explosions for movement and knockback.
g_knockback_scale1.0Scales knockback from damage.
g_ladder_steps1Ladder step sounds: 1 campaigns only, 2 always.
g_lag_compensation1Enables lag compensation.
g_lag_compensation_enhanced1Enables richer lag compensation with historical hitboxes, lag-aware aim projection, frame-based snapshot selection, interpolation, and stale/discontinuous-history cleanup.
g_mover_speed_scale1.0fScales mover speed for doors, rotators, lifts, and similar entities.
g_no_bfg0Prevents BFG spawning in maps.
g_no_armor0Prevents armor spawning in maps.
g_no_health0Prevents health spawning in maps.
g_no_items0Prevents normal item spawning in maps.
g_no_mines0Prevents mine spawning in maps.
g_no_nukes0Prevents nuke spawning in maps.
g_no_plasmabeam0Prevents Plasma Beam spawning in maps.
g_no_powerups0Disables powerup pickups.
g_no_spheres0Prevents sphere powerups spawning in maps.
g_nadefest0Enables grenade-only NadeFest behavior.
g_quadhog0Enables Quad Hog behavior.
g_starting_armor0Starting armor on spawn.
g_starting_health100Starting health on spawn.
g_starting_health_bonus0Bonus health granted on spawn, except where a ruleset overrides it.
g_start_itemsemptySpace-separated extra item classnames or item names granted on spawn.
g_vampiric_exp_min0Minimum health value for vampiric expiration.
g_vampiric_damage0Enables Vampiric Damage healing from damage dealt.
g_vampiric_health_max9999Maximum health cap from vampiric damage.
g_vampiric_percentile0.67fHealth percentile bonus for vampiric damage.
g_weapon_projection0Weapon projection offset mode.
g_weapon_respawn_time30Weapon respawn time in seconds. This is the literal time even in Horde — weapons are not affected by g_horde_item_respawn_scale. Effective time is g_weapon_respawn_time × g_dm_item_respawn_rate.

Interface And Debug Cvars

CvarDefaultPurpose
bot_name_prefix`B`
g_dm_crosshair_id1Enables crosshair player identification by default.
g_frag_messages1Enables frag message drawing.
g_frames_per_frame1Game frames run per server frame, clamped to 0..64; 0 intentionally pauses game simulation. Useful for controlled testing and performance tuning.
g_huntercam1Enables huntercam spectator behavior.
g_item_bobbing1Enables item bobbing.
g_matchstats0Enables the live in-game match-statistics menu. It does not control completed-match artifact exports.
g_muffmode_debug0Enables muffmode_debug.log output.
g_ranked1Master switch for ranking. Set to 0 to run a purely casual server: skill ratings never move, sr reports the server as unranked, the join centerprint omits the rating line, and no match statistics are collected or exported (g_statex_* has nothing to write). Player preference profiles still load and save. Advertised in serverinfo.
g_select_empty0Allows selecting weapons without ammo.
g_showhelp1Prints quick explanations for game modifications.
g_showmotd1Shows message of the day behavior when enabled.
g_statex_enabled1Writes completed singleton-match JSON artifacts and maintains baseq2/matches/catalog.json; concurrent Arena room series are excluded. Requires g_ranked 1.
g_statex_export_html1Writes a companion HTML report for each exported match. JSON and the catalog remain enabled when this is 0.
g_statex_humans_present1Exports only matches with at least one human participant; set to 0 to include bot-only matches.
g_verbose0Enables extra console diagnostics.

Drop Command Flags

g_drop_cmds is a bitflag:

ValueAllows
1Dropping CTF flags.
2Dropping powerups.
4Dropping weapons and ammo.

The default 7 enables all three.

Per-Level Config Files

When g_dm_exec_level_cfg is enabled, MuffMode executes a config named for the loaded map (exec <mapname>) at level start. It is off by default.

Functional per-gametype config files (gt-FFA.cfg and friends) are retired and no longer auto-execute. Everything they carried — the mode's ruleset, limits, map rotation, player limits and gameplay settings — now lives in a factory. A transition ZIP may contain inert filenames solely for old-updater compatibility; see Factories and the migration notes in baseq2/CONFIGS_README.md.

To run endless Horde, select a factory with roundlimit 0 — the shipped horde_endless does exactly that. See Horde Late-Wave & Endless.

Horde Wave And Scaling Cvars

These cvars tune Horde pacing, wave budget, player scaling, and map-size scaling.

CvarDefaultPurpose
g_horde_starting_wave1First wave number after map load; latched before the level starts.
g_horde_points_base15Base monster point budget.
g_horde_points_per_wave5Additional point budget per wave before late-wave tapering.
g_horde_points_min0Optional minimum point budget; 0 disables.
g_horde_points_max0Optional maximum point budget; 0 disables.
g_horde_spawn_interval_min0.3Minimum time between monster spawns, in seconds.
g_horde_spawn_interval_max0.5Maximum time between monster spawns, in seconds.
g_horde_spawn_burst_count6Number of successful spawns in a pressure burst before adding a short rest. 0 disables burst rests and restores a steady stream.
g_horde_spawn_burst_rest2.0Seconds added after each completed spawn burst.
g_horde_warmup_cap30Maximum warmup monsters alive.
g_horde_max_alive60Maximum live monsters during active waves; 0 disables the cap.
g_horde_wave_spawn_delay_ms500Delay before a new wave starts spawning monsters.
g_horde_player_scale1Scales wave budget by active fighter count.
g_horde_player_scale_factor0.4Additional budget factor per extra fighter.
g_horde_player_scale_max8Maximum fighter count considered by player scaling.
g_horde_lives1Lives granted to each fighter per wave. Values above 1 allow real mid-wave respawns until the counter reaches zero.
g_horde_featured_spawns3Successful early-wave spawns reserved for monster types newly unlocked on that wave. 0 leaves every unlock to weighted chance.
g_horde_wave_type_ramp3Adds one to the effective non-themed minimum roster breadth every N waves. 0 disables the ramp and uses g_horde_wave_min_types unchanged.
g_horde_mark_monsters_threshold3Starts marking remaining monsters when the living count is at or below this value.
g_horde_mark_monsters_max8Maximum monster marker slots.
g_horde_map_scale1Enables map-size-based budget scaling.
g_horde_map_scale_ref4000Reference map span for map-size scaling.
g_horde_map_scale_factor0.5Strength of map-size scaling.
g_horde_start_chainsaw1Gives Horde players Chainfist/Chainsaw-style starting melee support when applicable.

Horde Champions And Themes

Champions are stronger monster variants. Themes bias a wave toward a monster category when enough matching monsters are available. A killed champion rolls a strong reward at g_horde_champion_drop_chance (100% by default) -- a random tech when techs are enabled (no other Horde monster drops techs), otherwise a pick from the champion strong-item pool. Summon or resurrection kills cannot be farmed for repeat score, rally progress, or drops.

CvarDefaultPurpose
g_horde_champions1Enables champion monster rolls.
g_horde_champion_max_per_run2Target champion budget across the tuned run before late-wave steady-rate logic.
g_horde_champion_chance0.6Chance factor used when allocating champions.
g_horde_champion_min_wave3Earliest wave that can spawn champions.
g_horde_champion_health_mult3.0Champion health multiplier.
g_horde_champion_health_floor400Minimum champion health floor before per-wave scaling.
g_horde_champion_health_per_wave25Additional champion health floor per wave.
g_horde_champion_damage_mult2.0Champion outgoing-damage multiplier.
g_horde_champion_speed_mult1.25Champion movement-speed multiplier.
g_horde_champion_strong_ratio4.0Ratio used to taper champion strength on already-strong monsters.
g_horde_champion_force0Debug/test switch that forces a champion every wave. Leave off for public servers.
g_horde_themed_waves1Enables occasional themed waves.
g_horde_theme_chance0.20Chance for a themed wave.
g_horde_theme_min_wave4Earliest wave that can use themes.
g_horde_wave_variety1Enables roster variety limits for non-themed waves.
g_horde_wave_min_types3Minimum monster type count when wave variety can be satisfied.

Horde Wildcard Waves And Edge Drops

Wildcard Waves are an opt-in set of unusual wave modifiers suggested by playtester HonkHonk. They are disabled as a group by default: individual weights only affect selection after g_horde_preset_chance is set above 0. A Wildcard replaces the normal theme, roster, featured-spawn, and champion choices for that wave, preventing modifier stacking. Boss units never receive Wildcard scaling or combat modifiers; setting g_horde_preset_allow_boss_waves 1 only permits the boss wave's ordinary escorts to use one.

Model and collision scaling always stay synchronized and are clamped to 0.5-1.5. Scaled monsters use the same pre-spawn and post-spawn world validation as every other Horde threat. Clone Army excludes medics so a single-type wave cannot recursively grow through revivals. Tiny Shamblers is ineligible before the Shambler's wave-10 unlock. Weights are clamped to 0-12; a weight of 0 disables that preset.

CvarDefaultPurpose
g_horde_monster_edge_drops1Lets a living ground monster walk off an edge only while actively chasing a living fighter and only when a non-hazardous, sufficiently flat BSP landing exists within 256 units and remains in the target's PHS. Bosses, flyers, swimmers, stand-ground monsters, voids, lava, slime, and deep water are excluded.
g_horde_preset_chance0Chance that an eligible wave becomes a Wildcard Wave; clamped to 0-1. 0 disables every Wildcard regardless of its weight.
g_horde_preset_allow_boss_waves0Allows a Wildcard on scheduled boss waves. It applies only to ordinary escorts, never to boss units.
g_horde_preset_weight_clone_army7One eligible non-medic director monster type fills the ordinary wave.
g_horde_preset_weight_funhouse_horde5Each director monster is either 0.6x or 1.45x model/hull scale, with bounded health, damage, and movement compensation.
g_horde_preset_weight_get_over_here4Ordinary monster hits deal 85% damage and add a capped pull toward the attacker.
g_horde_preset_weight_giant_horde4Director monsters use 1.35x model/hull scale, 1.6x health, 1.1x damage, and 0.75x movement.
g_horde_preset_weight_glass_cannon8Director monsters use 0.4x health and 1.8x damage.
g_horde_preset_weight_low_gravity3Uses 55% gravity for fighters and director monsters for this wave without changing the server's global gravity cvar.
g_horde_preset_weight_tiny_shamblers4From wave 10 onward, fills the ordinary wave with 0.55x Shamblers using reduced health/damage and faster movement.
g_horde_preset_weight_tiny_terror10Director monsters use 0.6x model/hull scale, 0.35x health, 0.7x damage, and 1.5x movement.
g_horde_preset_weight_pinball_night4Uses 65% fighter/director-monster gravity, 500% knockback against fighters, and 85% ordinary-monster damage.
g_horde_preset_weight_sawstorm5Quadruples player Chainfist damage against non-boss monsters for the wave.

The proposed route-time hull shrinking, visual-only scaling, Hyper Wave, Jackpot Wave, Kill Medic instant revival, Mini Me spawn multiplication, and Boss Duel are intentionally not implemented. Route-time shrinking can restore a hull while overlapping geometry; visual-only scaling creates misleading collision; the Hyper proposal cannot safely accelerate every monster attack animation as one uniform rule; loot/revival/copy mechanics can multiply live entities or drops; and making hostile boss AI duel reliably would require new faction, target, summon, completion, and reposition semantics rather than a safe director modifier.

Horde Bosses, Water Ambushes, And Reinforcements

Scheduled boss waves replace the champion roll for that wave, reduce the normal escort budget, spawn the boss first, and pause briefly before escorts arrive. Bosses use their real hull for spawn validation and stay marked for the team and drive the native named boss health bars. The 25-profile catalog combines the core Quake II Supertank, Guardian, Hornet, Carrier, Black Widow, Makron, and Black Widow II with every named Call of the Machine boss encounter and its explicit Arachnid mini-boss. Children of Makron and Masters of the Machine deploy two bosses and use both native health bars; the defeat announcement and boss-kill rally occur only after the complete encounter is gone.

Selection follows unlock tiers, avoids the configured number of recent profiles when the current tier has enough alternatives, and gives a compatible authored horde_boss anchor priority over the global roll. Boss health gains 20% per additional active fighter, then applies profile, pair, global, and post-unlock wave multipliers. Damage uses the equivalent profile/global/endless growth path. Power armor can be scaled separately. The default model scale limit keeps Modir and other unusually large campaign variants usable on multiplayer maps; setting it to 0 disables that configurable limit while retaining an absolute safety ceiling of 16.

Carrier and Medic Commander reinforcements remain pressure-only, but Widow-spawned monsters and successful medic revivals become counted threats that must be killed before the wave can end. All summoned or revived monsters remain ineligible for repeat score, rally progress, or drops, and transition cleanup removes any pressure-only survivors. At level load, Horde tests every boss profile's scaled hull against authored boss anchors and player spawns, records only the player points suitable for that profile, and excludes profiles without enough placements (including two distinct placements for enabled pair encounters). A map with no compatible profile does not schedule boss waves. Runtime blockage can still cancel a deployment after bounded retries, but never forces a different boss that was not validated for the map.

Aquatic attempts can use authored monster_flipper placements, underwater monster_gekk placements, or explicit water anchors, choosing either a Flipper or swimming Gekk. If no authored water location is usable, the director falls back to a fully submerged ambush near waist-deep fighters. Maps without suitable water simply continue with the normal roster.

Eliminated fighters can be rallied back by team kills. A boss kill immediately earns the pending rally; otherwise the configured kill threshold is required. Rallying grants one life, uses normal Horde spawn/loadout handling, and applies short spawn protection. The per-wave cap prevents an endless death loop.

CvarDefaultPurpose
g_horde_boss_waves1Enables scheduled boss waves.
g_horde_boss_min_wave6First wave eligible for the boss schedule.
g_horde_boss_interval6Waves between scheduled bosses after the first; 0 disables the schedule.
g_horde_boss_budget_mult0.8Multiplies the normal wave budget on boss waves before the boss cost is deducted. Values below 0.1 are treated as 0.1.
g_horde_boss_health_mult1.0Multiplies boss health after automatic active-fighter scaling. Values below 0.1 are treated as 0.1.
g_horde_boss_damage_mult1.15Boss outgoing-damage multiplier. Values below 0.1 are treated as 0.1.
g_horde_boss_tier_window3Carries forward bosses whose unlock wave is within this many waves of the newest unlocked boss. Profiles unlocked since the previous scheduled boss wave are always admitted once, so cadence cannot skip a tier; 0 otherwise keeps only the newest tier.
g_horde_boss_powerup_chance0.35Chance that a killed boss's guaranteed strong reward is a timed powerup; clamped to 0-1.
g_horde_boss_machinegames1Includes the Call of the Machine named profiles in progression rolls. Explicit g_horde_boss_force still permits one while this is 0.
g_horde_boss_pairs1Enables the two-unit children_of_makron and masters_of_the_machine profiles.
g_horde_boss_repeat_window2Avoids this many most-recent boss profiles when the active tier has enough alternatives; exclusions relax oldest-first if necessary.
g_horde_boss_forceemptyForces one profile ID on every scheduled boss wave, bypassing unlock and MachineGames filters. Pair profiles still require g_horde_boss_pairs 1, and the forced profile is skipped if its level-load placement catalog has no suitable authored/player points.
g_horde_boss_scale_limit2.5Maximum applied boss model/hull scale. 0 disables this configurable cap; an absolute safety ceiling of 16 still protects collision and trace math.
g_horde_boss_health_per_wave0.05Adds this fraction of health for each wave after the selected profile's unlock wave. Negative values behave as 0.
g_horde_boss_damage_per_wave0.01Adds this fraction of outgoing damage for each wave after the selected profile's unlock wave. Negative values behave as 0.
g_horde_boss_pair_health_mult1.0Per-unit health multiplier for paired encounters. Values below 0.05 are treated as 0.05.
g_horde_boss_armor_mult1.0Multiplies any power-screen or power-shield capacity produced by the boss class/profile/anchor. 0 removes its capacity.
g_horde_water_spawns1Enables authored or dynamic aquatic Flipper/Gekk attempts.
g_horde_water_spawn_chance0.30Chance per normal spawn opportunity to attempt an aquatic spawn; clamped to 0-1.
g_horde_water_max_alive4Maximum simultaneous aquatic Horde monsters. 0 removes this separate cap.
g_horde_reinforcement_kills12Monster kills required to rally one eliminated fighter; values below 1 are treated as 1.
g_horde_reinforcements_per_wave1Maximum mid-wave rallies. 0 disables rallies, including the boss-kill rally.
g_horde_reinforcement_protection2.0Seconds of Protection granted to a rallied fighter.

Call Of The Machine Boss Catalog

The shipped baseq2/pak0.pak contains 20 target_healthbar entities representing 18 named encounters. The table below records their English rerelease names and entity-lump tuning. Difficulty-split 0.75/1.25 encounters use 1.25 as the portable profile, while Horde on the original map keeps the active difficulty variant's exact anchor value. Carrier base health remains the rerelease class's skill-dependent 2000-4000 before multipliers.

Profile IDShipped encounterMapClassAuthored tuning
gate_wardenGate Wardenmgu1m3monster_boss22x health, 1.25 scale; the active map variant retains its Hornet attack flag.
makronMakronmgu1m5monster_makron1.25 scale.
children_of_makronChildren of Makronmgu1m5monster_makronTwo units, each 0.8 scale.
bloodstarved_mutantBloodstarved Mutantmgu2m2monster_mutant6x health, 1.5 scale.
strogg_supertankStrogg Supertankmgu3m4monster_supertank0.75x/1.25x health by difficulty.
strogg_carrierStrogg Carriermgu3m4monster_carrier0.75x/1.25x health by difficulty.
strogg_megatankStrogg Megatankmgu3m4monster_boss50.75x/1.25x health; shielded Supertank class with its heat-seeking rockets and default 400 shield.
ancient_carrierAncient Carriermgu3secretmonster_carrier0.75x/1.25x health by difficulty.
commanderCommandermgu4m1monster_tank_commander2x health, 1.3 scale, 250-point shield, heat-seeking rockets.
garbage_carrierGarbage Carriermgu4m3monster_carrier1x/1.25x health, four summon slots, Stalker reinforcements.
arachnidArachnid mini-bossmgu5m2monster_arachnid1.5x health; this encounter has no campaign health-bar name.
system_administratorThe System Administratormgu5m3monster_makron0.75x health.
janitorThe Janitormgu5m3monster_supertank0.2 scale with full Supertank health and attacks.
overburdenOverburdenmgu6m1monster_supertankPower-screen type authored without extra capacity.
underminerThe Underminermgu6m2monster_supertank2x health.
modirModirmgu6m3monster_shambler40x health, 5.5 authored scale; geometry is capped by g_horde_boss_scale_limit by default.
servitor_of_creationServitor of Creationmgubossmonster_boss21.25x health, 1.125 scale, alternate Hornet attack set.
servitors_of_creationServitors of Creationmgubossmonster_supertank1.25x health.
masters_of_the_machineMasters of the Machinemgubossmonster_shamblerTwo units, each 3x health and 1.125 scale, with the authored precision-lightning flag.

The remaining forceable profile IDs are supertank, guardian, hornet, carrier, black_widow, and black_widow_ii. tank_commander is the automatic compact fallback profile and may also be forced explicitly.

Horde Authored Spawn Sources

With authored spawn sources enabled, Horde converts usable campaign monster_* placements into inert typed anchors instead of spawning the campaign monsters. monster_flipper and underwater monster_gekk become water anchors; campaign boss classes become boss anchors; flying classes become aerial anchors; other combat monsters become ground anchors. Canonical mgu* bosses are recognized by map, targetname, and class, so their boss profile and active-difficulty health/scale/armor/summon tuning survive conversion. Normal entity inhibition runs before the inert anchor is finalized, preventing easy/medium/hard duplicate placements from appearing together. Exact source-class matches receive a strong preference, then the director uses other compatible monster anchors, and finally ordinary deathmatch/team/player starts. Every location must still fit the requested hull, share a PHS with a living fighter, and satisfy the minimum distance. Decorative stands, commander bodies, and fixed monster turrets are ignored.

Custom maps and .ent overrides can use the explicit info_horde_* entities documented in Level Design Guide.

CvarDefaultPurpose
g_horde_map_monster_spawns1Enables converted campaign monster placements and explicit info_horde_* anchors.
g_horde_map_spawn_chance0.75Chance for a non-water, non-boss spawn to prefer an authored compatible anchor before player spawns; clamped to 0-1. Bosses always try authored anchors, while water uses g_horde_water_spawn_chance.
g_horde_map_spawn_cooldown3.0Default seconds before the same authored anchor can be reused. An anchor's positive horde_cooldown overrides it.
g_horde_map_spawn_min_dist192Minimum distance from every living fighter for an authored anchor.

Horde Rewards And Momentum

Monster loot is decided when the monster dies. Ordinary kills can yield nothing; when they do yield an item, the monster's weapon or combat role heavily biases the result (for example Infantry favors bullets, Gunner favors bullets/grenades, Chick favors rockets, and Gladiator favors slugs). The profile bias still leaves room for the general wave-appropriate loot curve. Champions have a higher but non-guaranteed strong-drop chance. Bosses always drop a strong reward and may upgrade it to Quad, Double, Protection, Haste, Regeneration, or Invisibility.

Consecutive credited kills build personal momentum tiers. Each tier adds kill score, improves drop chance, and can upgrade small ammo/health/armor into a more valuable version. Death resets the streak. A fighter who contributes at least one kill and finishes the wave without dying receives the configured survival score bonus.

CvarDefaultPurpose
g_horde_drop_chance0.35Base chance for a regular credited monster kill to drop an item.
g_horde_drop_profile_bias0.85Chance that a successful regular drop uses the monster-specific profile instead of the general wave loot pool.
g_horde_champion_drop_chance1.0Base chance for a killed champion to drop a strong reward (or tech, when techs are enabled).
g_horde_streak_step5Consecutive credited kills required per momentum tier; values below 1 behave as 1.
g_horde_streak_max_tier3Maximum momentum tier. 0 disables momentum bonuses.
g_horde_streak_score_bonus1Additional score per credited kill for each active momentum tier.
g_horde_streak_drop_bonus0.08Added regular/champion drop chance per momentum tier.
g_horde_streak_upgrade_chance0.20Per-tier chance to upgrade a successful regular/champion drop to its next value class.
g_horde_momentum_messages0Print momentum-tier notifications to the player. Off by default; the score and drop bonuses still apply when disabled.
g_horde_wave_survival_bonus2Score awarded after a contributed, deathless wave. 0 disables it.
g_horde_wave_flawless_message1Centerprint the flawless-wave notice to qualifying players. 0 hides it; the score bonus still applies either way.

Horde Item Respawn

In Horde, non-weapon items (health, ammo, armor, powerups) respawn slower than in other modes. The effective respawn time is base × g_dm_item_respawn_rate × g_horde_item_respawn_scale, where base is the item's built-in respawn time. Weapons are exempt from g_horde_item_respawn_scale — they respawn at exactly g_weapon_respawn_time (× g_dm_item_respawn_rate), so the configured value is the real in-game time. The shipped Horde factories set g_weapon_respawn_time 60 and g_horde_item_respawn_scale 4. Active held powerup and timed-tech deadlines pause from wave end until the next wave starts; Regeneration and AutoDoc ticks pause too, so inter-round preparation neither consumes nor exploits their duration.

CvarDefaultPurpose
g_horde_item_respawn_scale4Multiplies non-weapon item respawn time in Horde. 1 disables the slowdown; values below 1 are treated as 1. Weapons are unaffected.
g_horde_tech_reset_each_wave1When techs are enabled in Horde, 1 clears all techs (world and held) at the countdown to the next wave and spawns a fresh set at wave start. 0 makes techs persist across waves for the whole match (spawned once at map load).
g_horde_tech_relocate00 = Horde techs stay where they spawn or are dropped. 1 = unpicked techs relocate to a new spot every 60s (the behavior in other modes).
g_horde_tech_count0Number of techs to spawn per Horde wave. 0 = adaptive ceil(players / 2); 1–4 = fixed. Clamped to the four tech types.
g_horde_tech_unique00 = each wave's techs are picked independently, so duplicates can appear (e.g. three AutoDocs). 1 = pick a distinct, no-repeat random subset.
g_horde_tech_drop_on_death11 = a killed player drops their held tech. 0 = they keep it.
g_horde_tech_spawn_anywhere11 = scatter techs at random validated floor spots across the play area. 0 = spawn them at deathmatch spawn points (as in other modes).
g_horde_tech_duration30Seconds a tech lasts after pickup before it expires and vanishes (like Quad). 0 = techs are held until dropped/lost. The remaining time shows in the powerup timer slot.

Horde Late-Wave & Endless

Horde waves 1-12 are tuned content by default. Past wave 12, reached either by setting roundlimit 0 for endless or by a high finite roundlimit such as 20 or 25, late-wave systems engage so themes stay truthful and budgets stay playable: a theme banner only shows when the theme can field on-category bodies, every spawn in a themed wave stays on-category, and the per-wave point budget tapers instead of growing linearly forever. Waves up to the peak are unchanged.

With g_horde_late_escalation 1 (default), post-peak waves also use a stronger budget growth factor and ramp the concurrent alive cap (g_horde_max_alive base + bonus per wave, clamped). Set to 0 for legacy post-peak behaviour (flat cap 60, g_horde_late_wave_factor 0.35 budget taper only). The alive cap exists to prevent client network-buffer overflow from large homing swarms (SZ_GetSpace); raise g_horde_late_max_alive_cap only after stress-testing on your hardware.

Champions also keep coming: up to the peak they spend the per-run budget (g_horde_champion_max_per_run × g_horde_champion_chance) as usual, and past the peak they switch to a steady per-wave rate derived from those same two cvars — so an endless run never runs out of champions. Raise either cvar to make champions more frequent (early and late alike).

CvarDefaultPurpose
g_horde_content_peak_wave12Wave where the tuned curve ends; late-wave logic fires above it.
g_horde_late_escalation11 = post-peak budget + alive-cap ramp (defaults below). 0 = legacy flat cap and 0.35 budget factor.
g_horde_late_wave_factor0.35Post-peak budget growth when g_horde_late_escalation is 0.
g_horde_late_budget_factor0.6Post-peak budget growth when g_horde_late_escalation is 1.
g_horde_late_max_alive_per_wave2Added to g_horde_max_alive per wave past peak when escalation is on.
g_horde_late_max_alive_cap70Ceiling for the ramped alive cap (~+17% over 60); tune after homing-swarm stress test.
g_horde_weight_floor0.12Minimum monster spawn weight past the peak; keeps cheap chaff spendable.
g_horde_theme_min_monsters2Minimum on-theme monsters required at a wave for that theme to roll.

Endless example (escalation is on by default; only roundlimit is required):

set roundlimit 0

To disable post-peak escalation: set g_horde_late_escalation 0.

Horde Enhanced AI

Master switch for experimental horde AI (Tier 0 orchestration in mm_horde plus Tier 1 vanilla hooks). Defaults to 1 (enabled); set to 0 to restore legacy horde monster targeting and pacing.

CvarDefaultPurpose
g_horde_enhanced_ai1Target spread, tactical hull-aware placement, adaptive pacing, per-spawn roles, periodic retargeting, extended aggro, relentless pursuit, attack stagger, and medic corpse-resurrect priority.
g_horde_target_spread_weight512How strongly monsters avoid piling onto one fighter. Under the strategy model (g_horde_target_model 1) this scales the target-load weight, where 512 is the reference (1024 doubles it, 0 ignores target load entirely). Under g_horde_target_model 0 it keeps its legacy meaning: a raw score penalty per monster already assigned, with hunters using half this value to prefer isolated fighters and heavies 37.5% to prefer healthier ones.
g_horde_target_model1Strategy-driven target selection. Monsters weigh proximity, target load, how dangerous a fighter is right now, how finishable they are, and how isolated they are, then multiply by a reachability gate covering area connectivity, climbable height, habitat, PHS, and remembered failed routes. Large monsters weigh reachability far more heavily and stop chasing stragglers into geometry they cannot follow through. 0 restores the previous role-based scorer exactly. Requires g_horde_enhanced_ai 1.
g_horde_target_aggression1.0Multiplier (0-2) on how much monsters prefer the most dangerous fighter. 0 ignores threat entirely; 2 produces a pronounced "hunt the carry" feel.
g_horde_target_opportunism1.0Multiplier (0-2) on how much monsters prefer a finishable fighter (hurt, unarmoured, out of ammo, helpless). 0 never prefers a weakened target.
g_horde_reach_probe_budget512Maximum PHS reachability probes per server frame, claimed all-or-nothing per monster so a shortfall can never reorder that monster's candidates. 0 disables PHS probing; reachability still uses area connectivity, climbable height, habitat, and remembered failed routes.
g_horde_retarget_interval8.0Seconds between per-monster target-load rebalance checks. Close engagements and special AI goals remain sticky. 0 disables periodic retargeting.
g_horde_pursuit1Relentless pursuit. A threat that loses sight of its fighter keeps chasing the fighter's live position instead of a player trail that has gone cold, never times out of its search, drops hold orders, and clears its movement penalties when it stops covering ground. Scripted goals, escorts, medics, noise chases, and immobile monsters are untouched. 0 restores vanilla trail pursuit.
g_horde_pursuit_repath_time2.0Maximum seconds a pursuing threat will sit out a navigation failure before retrying, replacing vanilla's 5-10 second lockout. Higher values trade responsiveness for fewer path queries; 0 retries on the next frame. Ignored when g_horde_pursuit is 0.
g_horde_stall_timeout90Seconds with no damage to a counted Horde monster after all spawns are committed before recovery runs. The first timeout retargets every threat; another timeout relocates one stranded threat to a validated in-PHS combat spawn. Invalid or escaped world-space positions are recovered immediately regardless of this value. 0 disables only the timed recovery.

Debug-Only Weapon Balance Cvars

These cvars are available only in debug builds:

CvarPurpose
g_weapon_balance_devEnables weapon balance development mode.
g_chaingun_max_shotsSets maximum shots for Chaingun.
g_chaingun_damageSets Chaingun damage.
g_chaingun_hspreadSets Chaingun horizontal spread.
g_chaingun_vspreadSets Chaingun vertical spread.
g_chaingun_spread_offsetSets Chaingun spread offset.
g_machinegun_damageSets Machinegun damage.
g_machinegun_hspreadSets Machinegun horizontal spread.
g_machinegun_vspreadSets Machinegun vertical spread.
g_hyperblaster_speedSets Hyperblaster projectile speed.
g_railgun_damageSets Railgun damage.
g_rocketlauncher_damageSets Rocket Launcher damage.
g_rocketlauncher_speedSets Rocket Launcher projectile speed.