Releases: DarkMatter-Productions/MuffMode
MuffMode v0.22.10
Changelog
Scoreboard: captain indicator for TDM/CTF
- Show asterisk (*) next to team captains on the scoreboard. Server-side only; no client download required.
Tab menu: Ready Up option
- Added Ready Up / Not Ready option to the join menu (team and free modes), shown only during ready-up warmup when
g_dm_do_readyupis enabled. Toggles ready state on selection. Replaced a blank row and removed an extra blank for a cleaner layout.
Voting menu: Shuffle Teams and Ready All
- Added Shuffle Teams and Ready All options to the Call Vote menu.
- Shuffle Teams shows N/A for non-team gametypes; Ready All shows N/A when not in ready-up warmup.
- Added
readyallvote command (calls ReadyAll during MATCH_WARMUP_READYUP). Vote validation and execution include defensive checks for both votes.
Map vote / nextmap fix
- Fixed a bug where the same map could load again after a map vote when the voted map was not in
g_map_list.level.nextmap(set by the vote) was persisting across map loads because most maps don't define a worldspawnnextmapkey. The next match end would then use that stale value and reload the same map instead of advancing the rotation. - Now clears
level.nextmapwhen loading a map that has no worldspawnnextmapkey, so Match_End correctly falls through to map queue,g_map_list, or other fallbacks. - When the current map is not in
g_map_list(e.g. voted from pool), Match_End now rejoins the rotation at the first map in the list instead of falling through to target_changelevel or same map.
Eyecam spectator stutter fix
- Fixed stuttery view when spectating players with
g_eyecam1 enabled. Zerodelta_anglesfor eyecam spectators so the view is fully server-authoritative, avoiding jitter from spectatorcmd_anglesmismatch. Only apply the vanilla chase cam delta formula wheng_eyecamis off. - Aligned spectator entity origin with pmove (view position) for consistency.
MuffMode v0.22.0
- Added read-only admin
doctordiagnostics command that runs all checks. doctornow reports cvar misconfigurations and risky combinations with suggested fixes (no auto-apply).- Fixed single-player level transitions: prevent repeated
ExitLevel()calls from causingGot null changemap when trying to exit levelafter re-entering maps. - Refactored ruleset tuning in
p_weapon.cppinto centralized helper paths (pickup/drop, MG/CG, rocket/hyper, rail/BFG, plasma/ion) and aligned non-explicit overrides toward vanilla-default behavior. - Default ruleset changed to 1 to preserve vanilla behavior.
- Fixed gametype voting race condition: voting for duel from TDM could incorrectly load deathmatch due to GT_Changes() overriding the gametype after teamplay/ctf cvar changes.
- Adjusted chaingun damage to 4.5 for Balanced and QC rulesets.
- Added diagnostic logging to KillBox for telefrag lag investigation (enable with
g_muffmode_debug 1).
MuffMode v0.21.87
- Clan Arena/spectator: clear
eliminatedwhen switching to true spectator team so unteamed spectators can enter and use chasecam/follow normally. - Spectator/chasecam: allow eliminated players to receive and process queued follow targets (killer/leader auto-follow), reducing cases where they remain stuck in freecam after death.
- Clan Arena: reset per-player damage carryover counters on round reset (
dmg_scorer/dmg_team) so damage-based scoring does not leak across rounds. - Arena self-damage: clarified in-code behavior/docs that self-health damage is always blocked in arena modes, and
g_arena_dmg_armoronly controls self-hit armor absorption. - Clan Arena: fix round-timeout winner checks to use fresh live-player counts at timeout, preventing incorrect winner calls from stale team-living counters.
- Fix end-of-match team score HUD showing stale tied values in TDM/CTF; now displays the final score.
- g_ruleset 4 balance: reverted machinegun and chaingun spread overrides to defaults, reverted shotgun RS_VANILLA_PLUS override to default behavior, and increased rocket speed from 720 to 750.
- Fix crash:
P_Menu_Closenow clearsinmenuflag alongsidemenu = nullptr, preventingClientThinkfrom dereferencing a freed menu handle after menu close. - Fix sporadic end-of-map crash (seen on maps like
q64/dm4): screenshot filenames now sanitize map names/path separators beforescreenshotcommand enqueue, andExitLevellogs raw vs sanitized map names plus final screenshot command for diagnosis. - Harden end-of-map screenshot flow: validate duel sorted-client indices before entity access, require
follow_targetto beinusebefore name reads, cap screenshot filename length, and guard against empty screenshot command enqueue. - AutoDoc tech: fixed armor regeneration cadence for non-MM rulesets to match health regen timing (500ms), while preserving MM's 1s cadence.
- Fix crash: close any open player menu in
MoveClientToIntermissionto prevent stalesvc_layoutwrites after match end, which caused a renderer double-begin-frame assertion (g_bInValidFrame).
Muffmode v0.21.78
Voting Menu Improvements
- Enabled voting menu in GUI: Uncommented "Call a Vote" option in join menus (teams and free-for-all)
- Fixed duplicate "Admin" option: Removed static "Admin" entry that was duplicating the dynamic one
- Fixed "Admin" menu alignment: Changed from centered to left-aligned to match other menu options
- Simplified voting menu: Hid all voting options except "Map" (renamed from "change map") for focused testing
- Map names display in uppercase: Map names in the voting menu are now displayed in uppercase for better visibility while preserving original case for voting
- Fixed critical map name corruption bug: Resolved issue where map names were being corrupted when voting from the menu (e.g., "mm-mcoil" becoming "4UD" or "`MKD")
- Root cause: Memory corruption occurring when reading map names from menu entries
- Solution: Store original map names in
menu_t.text_arg1when populating menu, read directly from there instead of doing case-insensitive lookup - Additional safety: Use C string buffers until menu is closed, then convert to
std::stringto prevent corruption fromP_Menu_Close - Ensures map names are preserved correctly throughout the voting process
- Spectator voting restriction: Added checks to prevent spectators from calling votes via the menu system
- Menu-based voting now respects the
g_allow_spec_votecvar (defaults to 0, disabled) - Matches the behavior of command-based voting (
/callvote) - Checks added at menu entry point (
G_Menu_CallVote) and map selection (G_Menu_CallVote_Map_Selection)
- Menu-based voting now respects the
- Scorelimit voting menu: Fixed first-vote issue and improved reliability
- Fixed critical bug where scorelimit vote would show blank value on first vote from menu
- Root cause:
level.vote_argwas being set using plainstd::stringassignment which was getting corrupted - Solution: Use same
clear → reserve → assignpattern as map votes for consistent memory management - Menu option shows current scorelimit value
- Submenu allows selection of common limit values: 0, 5, 10, 20, 30, 40, 50, 100
- Includes spectator voting checks
- Timelimit voting menu: Added new timelimit voting option
- Menu option shows current timelimit value in minutes
- Submenu allows selection of: 0, 5, 10, 15, 20, 25, 30 minutes
- Mirrors scorelimit menu implementation for consistency
- Includes spectator voting checks
- Gametype voting menu: Added new gametype voting option
- Menu displays all available gametypes with their full names (e.g., "Deathmatch", "Team Deathmatch", "Capture the Flag")
- Respects
g_votable_gametypescvar: if set, only shows gametypes listed in the cvar - If
g_votable_gametypesis empty, shows all implemented gametypes (skips GT_NONE, GT_STRIKE, GT_RR, GT_LMS, GT_BALL) - Uses same reliable memory management pattern as other voting menus
- Includes spectator voting checks
- Gametype config execution fix: Fixed gametype-specific cfg files executing on every map load
- Problem:
gt-{gametype}.cfgfiles were executing on every map load, overriding player votes and map progression - Example: Players vote gametype to TDM (cfg sets map to q2dm1), vote scorelimit to 30, match ends, map advances to q2dm2, but then cfg executes again and resets map back to q2dm1
- Solution: Moved cfg execution from
InitGame()toChangeGametype()so it only runs when gametype actually changes - Cfg files now execute immediately when gametype changes (via vote or admin command), not on every map load
- Preserves player votes and natural map progression
- Problem:
- Powerups voting menu: Added powerups toggle vote with submenu
- Menu option shows current powerup state: "Powerups: ON" or "Powerups: OFF"
- Opens submenu with "ON" and "OFF" options for explicit selection
- When powerups vote passes, map automatically restarts so changes take effect immediately
- Uses same reliable memory management pattern as other voting menus
- Includes spectator voting checks
- Friendly Fire voting menu: Added friendly fire toggle vote with submenu
- Menu option shows current friendly fire state: "Friendly Fire: ON" or "Friendly Fire: OFF"
- Only available in TDM and CTF gametypes specifically
- In other gametypes, shows "Friendly Fire: N/A" and is not selectable
- Opens submenu with "ON" and "OFF" options for explicit selection
- When friendly fire vote passes, map automatically restarts so changes take effect immediately
- Uses same reliable memory management pattern as other voting menus
- Includes spectator voting checks
- Vote command validates that friendly fire can only be changed in TDM or CTF gametypes
- Main voting menu reorganization: Reordered main callvote menu options
- New order: Gametype, Map, (blank line), Scorelimit, Timelimit, (blank line), Powerups, Friendly Fire
- All submenus now return to the main callvote menu instead of the top-level main menu
- Consistent navigation experience across all voting submenus
Gametype System Enhancements
- Instagib as a gametype: Converted
g_instagibcvar functionality into a full gametype (GT_INSTAGIB)- Instagib can now be selected via the gametype voting menu
- When selected, executes
gt-INSTAGIB.cfgconfig file (ifg_gametype_cfgis enabled) - Maintains backward compatibility:
g_instagibcvar still works and syncs with gametype - When switching to Instagib gametype,
g_instagibcvar is automatically set to 1 - When switching away from Instagib gametype,
g_instagibcvar is automatically cleared - Both cvar and gametype methods can be used without conflict
- All existing code checks updated from
g_instagib->integerto(g_instagib->integer || GT(GT_INSTAGIB)) - Added to votable gametypes list
- Displays as "Instagib" in gametype menus and HUD
- NadeFest as a gametype: Converted
g_nadefestcvar functionality into a full gametype (GT_NADEFEST)- NadeFest can now be selected via the gametype voting menu
- When selected, executes
gt-NADEFEST.cfgconfig file (ifg_gametype_cfgis enabled) - Maintains backward compatibility:
g_nadefestcvar still works and syncs with gametype - When switching to NadeFest gametype,
g_nadefestcvar is automatically set to 1 - When switching away from NadeFest gametype,
g_nadefestcvar is automatically cleared - Both cvar and gametype methods can be used without conflict
- All existing code checks updated from
g_nadefest->integerto(g_nadefest->integer || GT(GT_NADEFEST)) - Added to votable gametypes list
- Displays as "NadeFest" in gametype menus and HUD
Team Captain System
- Added team captains for team modes: Teams now track captain ownership (
redandblue) and auto-assign captains when needed- First eligible player to join a team becomes captain when no captain is set
- If a captain leaves/switches teams/disconnects, captain status auto-transfers to the longest-tenured teammate
- Captain validity is rechecked on match start/reset to prevent stale captain pointers
- New
captaincommand:captainshows your current team captain, or claims captain if your team has nonecaptain <player>transfers captain status to a teammate (captain only)
- Captain permissions:
- Captains can lock/unlock their own team with
lockteam/unlockteam - Captains can ready their full team with
readyteam - Admins retain override control for all captain-gated actions
- Captains can lock/unlock their own team with
Ruleset Fixes
- Vanilla (Q2RE) powerup sound broadcasting: Fixed missing powerup sound broadcasting in vanilla ruleset
- Problem: Powerup pickup and activation sounds were only broadcast to all players in MM, Q3A, and Vanilla Plus rulesets, but not in vanilla (Q2RE) ruleset
- This was inconsistent behavior - vanilla should match other rulesets for competitive awareness
- Solution: Added
RS(RS_Q2RE)to powerup sound broadcasting checks - Powerup pickup sounds (when touching items) now broadcast to all players in deathmatch with vanilla ruleset
- Powerup activation sounds (when using Quad, Haste, Double Damage) now broadcast to all players in deathmatch with vanilla ruleset
- Matches behavior of MM, Q3A, and Vanilla Plus rulesets for consistency
- Quake Champions (QC) ruleset weapon tuning:
- Rocket launcher speed increased to
750 - Plasma Beam in deathmatch now matches Q2RE Balanced behavior: damage reduced to
10and maximum range limited to768 - Keeps QC ruleset pacing while aligning Plasma Beam balance with modern competitive settings
- Rocket launcher speed increased to
Voting System Stability
- Fixed vote counting in duel mode: Vote tallies are now recounted every frame in
UpdateActiveVote, fixing cases where votes wouldn't pass due to stale counts - Fixed crash when vote caller disconnects:
level.vote_state.calleris now cleared immediately when a vote transitions to FAILED, preventing dangling pointer access - Fixed potential crash during map vote execution: Added proper null/validity checks for entity pointers in
ExitLevelscreenshot logic, preventing access violations during mid-game map changes - Defensive null guard in vote menu: Added null check for
level.vote_state.callerinG_Menu_Vote_Updateto prevent crash if caller becomes invalid during menu rendering - Fixed duel vote eligibility: Duel-queued players are now counted as eligible voters. Previously, queued players were treated as spectators and excluded from vote counts when
g_allow_spec_votewas 0, causing votes to pass/fail immediately with only 1 eligible voter in 2-player duel matches - New
ClientCanVote()helper: Centralized vote eligibility logic — returns true for active players, duel-queued players, and spectators wheng_allow_spec_voteis enabled - Fixed crash on gametype change map load: `SV...
v0.21.29
Fixed
- Duel queue joining during match lock: Fixed issue where players were unable to join the duel queue when a match was locked. Queue joining is now allowed during match lock since it doesn't affect the active match - queued players are only pulled into matches during warmup periods. This allows players connecting mid-match to queue up for the next match without having to wait for warmup.
- Duel queue refilling during readyup: Fixed issue where the duel queue would not refill if a player disconnected during the readyup phase.
Duel_AddPlayer()now works duringMATCH_WARMUP_READYUPin addition toMATCH_WARMUP_DEFAULT, allowing queued players to be pulled in immediately if a slot opens during readyup. This ensures matches can start with a full roster even if players disconnect during the readyup phase. - Duel mode map change crash: Fixed crash error "Got null changemap when trying to exit level" that occurred when duel matches ended. Duel mode now automatically restarts on the same map if no changemap is configured, ensuring continuous duel matches without requiring map changelevel entities. This prevents server crashes when duel matches end and allows the queue system to continue functioning properly.
- Callvote map display: Fixed issue where
callvote maponly displayed maps from eitherg_map_poolorg_map_listdepending on which was populated. The callvote system now displays all maps from both lists combined, with case-insensitive deduplication and alphabetical sorting. This ensures players can see and vote for all available maps regardless of which cvar they're configured in. - Callvote map crash fix: Fixed access violation crash (0xc0000005) that occurred when executing
callvote map <mapname>. The crash was caused by insufficient validation of thelevel.changemappointer before dereferencing it inExitLevel(). Added comprehensive pointer validation and string length checks to prevent crashes from invalid or corrupted pointers. The fix also adds validation inVote_Pass_Map()to ensure the map name is properly copied to safe storage before use. - g_inactivity false positives: Fixed issue where
g_inactivitycould incorrectly trigger for actively playing players. The inactivity timer previously only checked for newly pressed buttons (latched_buttons), which meant players holding movement keys continuously or only moving the mouse could be flagged as inactive. The timer now checks for any button input, movement input (forwardmove/sidemove), view angle changes (mouse movement), and newly pressed buttons to accurately detect player activity. View angle changes are detected by comparing current and previous frame angles with a 1-degree threshold to avoid false positives from tiny movements. - [Special Colendro Fix] Eyecam spectator fall sound: Fixed the "donk" sound that played when spectating players in eyecam mode as they fell off ledges.
Added
- Automatic bot queueing in duel mode: Bots that are spectating in duel mode are now automatically added to the queue regardless of how many players are currently in the match. This allows bots to fill empty slots in duel matches and be ready for future matches, making it easier to test and play duel mode with bots. Bots are queued whenever they're spectating (except during intermission), and will be pulled into matches by
Duel_AddPlayer()during warmup periods.
Changed
- Team border display: Changed default value of
cl_teamBorderfrom 0 to 1, enabling team border display by default in team-based gamemodes. Players can still disable it by settingcl_teamBorder 0if desired.
v0.21.20
v0.21.20
Added
- Team border indicator: Added a configurable colored border at the bottom of the screen to clearly indicate team membership in team-based game modes (TDM, CTF, etc.). The border displays red for Red team and blue for Blue team. Configurable via cvars:
cl_teamBorder(enable/disable, default: 0),cl_teamBorderWidth(thickness in pixels, default: 4), andcl_teamBorderAlpha(transparency 0-255, default: 180). Fixed missingteam_idassignment inplayer_state_tthat was preventing the feature from working. - Configurable votable gametypes: Added
g_votable_gametypescvar to allow server admins to control which gametypes can be voted on by players. The cvar accepts a space-separated list of gametype short names (e.g., "ffa duel tdm ctf ca"). If empty (default), all gametypes are votable for backward compatibility. When set, only gametypes in the list can be voted on via callvote. Admingametypecommand still allows setting any gametype but shows a warning if the gametype is not in the votable list. Help text dynamically displays only the votable gametypes.
Fixed
- Spectator sound fixes: Fixed issue where positioned sounds for footsteps, fall damage, and ladder steps were being sent to all clients (including the player themselves), causing players to hear duplicate or changed sounds. Now positioned sounds are only sent when there are actual spectators viewing the player, so players hear normal entity event sounds while spectators can still hear the sounds properly.
- Callvote crash fixes: Fixed multiple null pointer dereference issues in the voting system that could cause server crashes when players used the
callvotecommand. Added null checks in vote menu updates, vote execution, and vote storage functions. Also fixed incomplete state cleanup when votes time out or fail, ensuringlevel.voteis properly cleared along withlevel.vote_time. Fixed vote state persistence across map changes -vote_execute_timeand other vote state variables are now properly cleared during level initialization. Fixed vote cancellation when the vote caller disconnects. Fixed incorrectvote_arginitialization inG_InitLevel()(was using= '\n'instead of.clear()for std::string). - Voting system improvements: Fixed duplicate vote vulnerability in menu voting functions (
G_Menu_Vote_Yes/No) that allowed players to vote multiple times. Added vote state validation inCheckVote()to detect and clear invalid vote state whenlevel.voteis null, preventing hanging votes. Added automatic vote count recalculation inCalculateRanks()when a vote is in progress, preventing race conditions when players join or leave during voting. Ensured complete state cleanup in all vote exit paths, includingvote_argclearing inCmd_ForceVote_f()andVote_Passed()error paths. - Division by zero fixes: Fixed potential division by zero in
P_CurrentKickFactor()whenkick.totalis zero or negative, which could cause crashes or NaN/infinity values to propagate through view angle calculations, resulting in corrupted camera views. Also fixed potential division by zero invec3_t operator/(const vec3_t &v)when any component is zero, preventing infinity/NaN values from propagating through vector calculations and causing physics or rendering issues. - Duel queue ordering fix: Fixed broken duel queue ordering where all queued players had
team_join_time = 0_sec, making queue order unpredictable. Now queued players correctly getteam_join_time = level.timewhen joining the queue, ensuring proper FIFO ordering based on when they entered the queue. Non-queued spectators still get0_secto maintain correct separation. - Gametype vote menu cleanup: Removed "ft" (Freeze Tag) and "horde" from the hardcoded available gametypes in vote command help text. Now replaced with configurable
g_votable_gametypescvar system that allows admins to control which gametypes are votable. The removed gametypes still function if set directly but are no longer in the default votable list. - Two-tier map validation system: Implemented proper validation hierarchy for map votes and commands using
g_map_poolandg_map_list. The system now validates maps againstg_map_poolfirst (all available maps), then falls back tog_map_list(maps in rotation) if not found in the pool. This allows players to vote for any map in the pool, not just those currently in rotation. Applied to callvote map validation, adminsetmapcommand, and map queue system. Error messages now display the appropriate map list (pool if available, otherwise rotation list).
v0.21.14
Fixed
-
Spectate functionality: Fixed issue where attempting to spectate would spam console with "You may not switch teams more than once per 5 seconds" message and prevent spectating. Players can now switch to spectator immediately without being blocked by the team switch rate limit. The rate limit still applies when switching between playing teams.
-
Spectator sound fixes: Fixed issue where spectators could not hear player footsteps, fall damage sounds, or ladder step sounds when spectating. These sounds used entity events (
EV_FOOTSTEP,EV_FALL_SHORT/MEDIUM/FAR,EV_LADDER_STEP) which weren't being transmitted to spectators. The fix adds positioned sound calls alongside the entity events to ensure spectators can hear these sounds. Item pickup sounds already worked correctly as they use direct sound calls rather than entity events. -
Spectator POV mode: Fixed issue where spectators were stuck in freecam mode and couldn't view from spectator POV (following other players). This was most noticeable in CA mode where eliminated players stay eliminated longer, but affected all gametypes. The issue was that
GetFollowTarget,FollowNext, andFollowPrevfunctions were setting the follow target but not updatingspectator_statetoSPECTATOR_FOLLOW. Now when spectators follow a player, they properly enter follow mode instead of remaining in freecam. -
Invisible player in CA mode: Fixed issue where a player could become invisible in Clan Arena mode. This occurred when
Entities_ResetsetSVF_NOCLIENTflag during round resets, but the flag wasn't properly cleared when a playing (non-eliminated) player spawned. NowSVF_NOCLIENTis explicitly cleared for playing players during spawn, ensuring they are always visible when they should be.
Restored
-
Map item layout switching: Restored functionality from v0.19.60 that allows maps to switch between different item layouts using entity keys and cvars. Maps can use
bfg_on/bfg_offandplasmabeam_on/plasmabeam_offentity keys to define alternative layouts, controlled byg_no_bfgandg_no_plasmabeamcvars. This fixes issues on maps like mm-kmach where multiple items were spawning at the same location - the map can now use these keys to have different layouts (e.g., BFG layout vs non-BFG layout) and toggle between them. -
Match cancellation delay: Added 300ms delay before match cancellation due to too few players. This allows
bot_minclients(or other bot systems) time to add bots before the match is cancelled, preventing premature cancellations when bots are being automatically added to maintain minimum player count.
v0.21.09
Fix elevators sometimes breaking after match start by resetting trains in Entities_Reset
Fix drop command: move special case checks before item lookup
Added new cvar g_frag_messages
Configure as below:
0: disable rampage messages across all game modes
1: disable rampage messages in TDM/CTF (default)
2: enable rampage messages in all game modes
v0.21.07
Disabled/removed banlist code as was causing issues.
Selectively implemented bugfixes from 0.21.0
Added new cvar: g_map_list_shuffle_once: when set to 1, shuffles the map list once at server startup, then cycles through maps in that order without re-shuffling. This differs from g_map_list_shuffle which re-shuffles on every map cycle. (default: 0)
v0.21.0
target_teleporterbug fix- numerous bug fixes and stability improvements
- plasmabeam knockback greatly reduced in muffmode ruleset
- banned player exploit fixed, more robust now