109 lines
3.7 KiB
Lua
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)
|