Map rotation on a CS 1.6 server is driven by one plain-text file, mapcycle.txt, and one cvar, mapcyclefile. It is deliberately simple, which is exactly why it fails in ways that look mysterious: a map that is not on disk, a stray comment, or the wrong filename silently changes the rotation and you spend twenty minutes wondering why the server keeps looping de_dust2. This covers how the file is read, how the engine chooses the next map, and the per-map config hook most admins never wire up.
1. Where the file lives and what points at it
The rotation file is cstrike/mapcycle.txt. The engine locates it through the mapcyclefile cvar, which defaults to mapcycle.txt (a path relative to the game directory). Keeping several rotations and switching between them is a one-line change in server.cfg:
// server.cfg mapcyclefile "mapcycle.txt" // or a themed rotation you keep alongside it // mapcyclefile "cycle_gg.txt"
2. Write the file: one map per line
Each line is a map name with no .bsp extension and no path. Blank lines and // comments are ignored:
de_dust2 de_inferno de_nuke cs_office de_train // de_aztec <- disabled for now
Every listed map must exist as cstrike/maps/<name>.bsp. The engine does not fail loudly on a missing entry — it skips it and moves to the next valid line, so a typo just quietly drops a map from the rotation. If you host these maps for download, they must also be on your FastDL mirror; see the FastDL setup guide and installing custom maps.
3. Understand how the next map is chosen
When a map ends (see below for what ends it), the engine finds the current map in mapcycle.txt and advances to the line after it, wrapping to the top at the end. Two consequences trip people up:
- If the map you are on is not in the list at all, the engine cannot find its position and falls back to the first entry. A server that always jumps to the top of the cycle after a manual
changelevelis doing exactly this. - The engine tracks position by map name, not by an index it saves to disk. On a clean restart it begins from wherever the current map sits in the file.
The AMX Mod X nextmap plugin reads this same file to compute what say nextmap reports and to run end-of-map handling. If you also run a vote at map end, mapchooser or Rock The Vote overrides the plain cycle — see that guide, and the CSB Mapchooser plugin.
4. What actually ends a map
The rotation only advances when the map ends, and that is governed by cvars, not by mapcycle.txt:
mp_timelimit 30 // minutes; 0 disables the time-based change mp_maxrounds 0 // ReGameDLL: end after N rounds (0 = off) mp_winlimit 0 // ReGameDLL: end when a team reaches N wins
With mp_timelimit 0 and no round/win limit the map never ends on its own and the cycle appears frozen. These and the rest of the round cvars are covered in the mp_ cvars reference.
5. Per-map configs with mapchangecfgfile
Vanilla HLDS does not auto-execute a <mapname>.cfg for you, but it does expose mapchangecfgfile, a config it runs on every map change. Point it at a small script that re-applies per-rotation settings, or use it to exec a map-specific file yourself:
// server.cfg mapchangecfgfile "onchange.cfg"
Keep gameplay cvars in server.cfg (executed at start) and only put things that must re-apply after a map load in the change config. Per-map tuning by name is better handled by an AMXX plugin that reads the current map, but mapchangecfgfile is the stock hook and it is reliable.
Common errors
- Rotation ignores your edits — you edited the wrong file. Check what
mapcyclefileactually resolves to in the console; if you set it to a custom name inserver.cfg,mapcycle.txtis dead weight. - A map never appears — the
.bspis missing fromcstrike/maps/, or the line has a trailing extension (de_nuke.bsp) or a Windows carriage return from editing on the wrong OS. Save the file as plain LF text. - Server always returns to the first map — you are running maps that are not in the cycle (a vote map, a manual
changelevelto something unlisted). Add them, or accept that off-list maps reset the position. - Map never changes at all —
mp_timelimitis 0 with no round or win limit set. Nothing is telling the map to end.
Verification
From RCON or the server console, load the first map and query the plugin view:
changelevel de_dust2 // then in-game say nextmap
say nextmap should report the line that follows your current map in the file. Let mp_timelimit expire once (or lower it to 1 for a quick test) and confirm the server advances to that map rather than reloading the same one. Once the cycle behaves, layer voting on top with the RTV and nextmap guide.









