Files
garrysmod-coop/gamemode/maprotation.lua
T

109 lines
3.7 KiB
Lua

local changeDelay = CreateConVar(
"gc_mapchangedelay",
"8",
FCVAR_ARCHIVE,
"Seconds between map completion and loading the next coop map"
)
local maxMapTime = CreateConVar(
"gc_mapmaxtime",
"3600",
FCVAR_ARCHIVE,
"Maximum map time in seconds before rotating; 0 disables the time limit"
)
local changeQueued = false
local function MapExists(mapName)
if not mapName or mapName == "" then return false end
local wanted = string.lower(string.StripExtension(mapName))
for _, fileName in ipairs(file.Find("maps/*.bsp", "GAME")) do
if string.lower(string.StripExtension(fileName)) == wanted then
return true
end
end
return false
end
local function SetFreshNextLevel()
local nextLevel = GetConVar("nextlevel"):GetString()
if nextLevel == "" or not MapExists(nextLevel) or string.lower(nextLevel) == string.lower(game.GetMap()) then
nextLevel = NextRandomLevel()
end
return nextLevel
end
function QueueCoopMapChange(reason, requestedMap)
if changeQueued then return end
local destination = requestedMap and string.lower(requestedMap) or nil
if not MapExists(destination) or destination == string.lower(game.GetMap()) then
destination = SetFreshNextLevel()
end
if not destination then
ErrorNoHalt("[custom_coop] Map completed, but no installed destination map is available\n")
return
end
changeQueued = true
local delay = math.max(changeDelay:GetFloat(), 0)
PrintMessage(HUD_PRINTTALK, "Map complete! Loading " .. destination .. " in " .. math.ceil(delay) .. " seconds.")
print("[custom_coop] Map change queued by " .. (reason or "unknown") .. ": " .. destination)
timer.Create("CustomCoopChangeCompletedMap", delay, 1, function()
RunConsoleCommand("changelevel", destination)
end)
end
hook.Add("AcceptInput", "CustomCoopDetectMapCompletion", function(ent, inputName, _, _, value)
if not IsValid(ent) then return end
local className = string.lower(ent:GetClass())
local input = string.lower(inputName or "")
if className == "game_end" and input == "endgame" then
QueueCoopMapChange("game_end")
return true
end
if className ~= "point_servercommand" or input ~= "command" then return end
local command = string.lower(string.Trim(tostring(value or "")))
local requestedMap = string.match(command, "^changelevel%s+[%\"]?([%w_%-%[%]!]+)")
or string.match(command, "^map%s+[%\"]?([%w_%-%[%]!]+)")
if requestedMap and (not MapExists(requestedMap) or string.lower(requestedMap) == string.lower(game.GetMap())) then
QueueCoopMapChange("point_servercommand", requestedMap)
return true
end
end)
-- Repair old trigger_changelevel/point_changelevel entities that refer to a map
-- which is not mounted. Valid campaign destinations remain untouched.
hook.Add("EntityKeyValue", "CustomCoopRepairChangelevelTargets", function(ent, key, value)
local className = string.lower(ent:GetClass())
if className ~= "trigger_changelevel" and className ~= "point_changelevel" then return end
if string.lower(key or "") ~= "map" then return end
if MapExists(value) and string.lower(value) ~= string.lower(game.GetMap()) then return end
local replacement = GetRandomLevel()
if replacement then
print("[custom_coop] Replacing unavailable changelevel target '" .. tostring(value) .. "' with " .. replacement)
return replacement
end
end)
hook.Add("InitPostEntity", "CustomCoopStartMapTimeLimit", function()
SetFreshNextLevel()
local limit = maxMapTime:GetFloat()
if limit <= 0 then return end
timer.Create("CustomCoopMapTimeLimit", limit, 1, function()
QueueCoopMapChange("time limit")
end)
end)