GM.Name = "Feedc0de's coop Mode" GM.Author = "0xFEEDC0DE64" GM.Email = "daniel@brunner.ninja" GM.Website = "brunner.ninja" DeriveGamemode("sandbox") include( "levels.lua" ) include( "progression_shared.lua" ) if (SERVER) then function ChangeRandomLevel() local randomLevel = GetRandomLevel() if not randomLevel then ErrorNoHalt("[custom_coop] No other installed coop map was found in levels.lua\n") return false end print("[custom_coop] Changing to random level " .. randomLevel) RunConsoleCommand("changelevel", randomLevel) return true end function NextRandomLevel() local randomLevel = GetRandomLevel() if not randomLevel then ErrorNoHalt("[custom_coop] Cannot set nextlevel: no other installed coop map was found\n") return nil end print("[custom_coop] Setting nextlevel to " .. randomLevel) RunConsoleCommand("nextlevel", randomLevel) return randomLevel end concommand.Add("randomlevel", ChangeRandomLevel) concommand.Add("randomnextlevel", NextRandomLevel) hook.Add("Initialize", "SetupRandomLevels", function() timer.Simple(0, NextRandomLevel) end) end -- timer.Simple( -- 1, -- function() -- function HideThings(name) -- if (name == "CHudDamageIndicator" or name == "CHudHintDisplay") then -- return false -- end -- end -- hook.Add("HUDShouldDraw", "HideThings", HideThings) -- end -- ) function GM:IsSpawnpointSuitable(ply, spawnpointent, bMakeSuitable) local Pos = spawnpointent:GetPos() -- Note that we're searching the default hull size here for a player in the way of our spawning. -- This seems pretty rough, seeing as our player's hull could be different.. but it should do the job -- ( HL2DM kills everything within a 128 unit radius ) local Ents = ents.FindInBox(Pos + Vector(-16, -16, 0), Pos + Vector(16, 16, 72)) if (ply:Team() == TEAM_SPECTATOR or ply:Team() == TEAM_UNASSIGNED) then return true end local Blockers = 0 for k, v in pairs(Ents) do if (IsValid(v) and v:GetClass() == "player" and v:Alive()) then Blockers = Blockers + 1 if (bMakeSuitable) then v:SetVelocity(v:GetPos() + Vector(100, 100, 0)) end end end if (bMakeSuitable) then return true end if (Blockers > 0) then return false end return true end if SERVER then -- Preserve the inherited selector across script auto-refreshes so the -- emergency fallback does not build a chain of older wrappers. local DefaultPlayerSelectSpawn = GM.CustomCoopDefaultPlayerSelectSpawn or GM.PlayerSelectSpawn GM.CustomCoopDefaultPlayerSelectSpawn = DefaultPlayerSelectSpawn local spawnPriorities = { info_player_deathmatch = 1, info_player_coop = 1, info_coop_spawn = 1, gmod_player_start = 1, info_player_rebel = 2, info_player_start = 3, info_player_combine = 4 } -- Include the additional spawn classes registered by Garry's Mod, while -- retaining a preference for the spawn types used by HL2DM coop maps. for _, className in ipairs(scripted_ents.GetMember("gmod_player_start", "SpawnPointClasses") or {}) do spawnPriorities[className] = spawnPriorities[className] or 2 end local playerHullMins = Vector(-16, -16, 0) local playerHullMaxs = Vector(16, 16, 72) local function BoxesIntersect(minsA, maxsA, minsB, maxsB) return minsA.x <= maxsB.x and maxsA.x >= minsB.x and minsA.y <= maxsB.y and maxsA.y >= minsB.y and minsA.z <= maxsB.z and maxsA.z >= minsB.z end local function IsSpawnInsideActiveHurt(spawnpoint) local position = spawnpoint:GetPos() local spawnMins = position + playerHullMins local spawnMaxs = position + playerHullMaxs for _, hurt in ipairs(ents.FindByClass("trigger_hurt")) do local disabled = hurt:GetInternalVariable("m_bDisabled") local damage = tonumber(hurt:GetInternalVariable("damage") or hurt:GetKeyValues().damage) or 0 if disabled ~= true and disabled ~= 1 and damage > 0 then local hurtMins, hurtMaxs = hurt:WorldSpaceAABB() if BoxesIntersect(spawnMins, spawnMaxs, hurtMins, hurtMaxs) then return true end end end return false end function GM:PlayerSelectSpawn(ply, transition) if transition then return end local bestPriority local candidates = {} for _, spawnpoint in ipairs(ents.GetAll()) do local priority = spawnPriorities[spawnpoint:GetClass()] if priority and spawnpoint:IsInWorld() and not IsSpawnInsideActiveHurt(spawnpoint) then if spawnpoint:HasSpawnFlags(1) then priority = 0 end if not bestPriority or priority < bestPriority then bestPriority = priority candidates = { spawnpoint } elseif priority == bestPriority then candidates[#candidates + 1] = spawnpoint end end end if #candidates == 0 then return DefaultPlayerSelectSpawn(self, ply, transition) end local lastSpawnpoint = ply:GetVar("LastSpawnpoint") if #candidates > 1 and IsValid(lastSpawnpoint) then table.RemoveByValue(candidates, lastSpawnpoint) end local chosen = candidates[math.random(#candidates)] self.LastSpawnPoint = chosen ply:SetVar("LastSpawnpoint", chosen) return chosen end end local hl2dmLoadout local automaticLoadout local BuildAutomaticLoadout local ammoWeaponPairs = { { weapon = "weapon_pistol", ammo = { "item_ammo_pistol", "item_ammo_pistol_large" } }, { weapon = "weapon_smg1", ammo = { "item_ammo_smg1", "item_ammo_smg1_large", "item_ammo_smg1_grenade" } }, { weapon = "weapon_357", ammo = { "item_ammo_357", "item_ammo_357_large" } }, { weapon = "weapon_ar2", ammo = { "item_ammo_ar2", "item_ammo_ar2_large", "item_ammo_ar2_altfire" } }, { weapon = "weapon_shotgun", ammo = { "item_box_buckshot" } }, { weapon = "weapon_crossbow", ammo = { "item_ammo_crossbow" } }, { weapon = "weapon_rpg", ammo = { "item_rpg_round" } } } if SERVER then hl2dmLoadout = CreateConVar( "gc_hl2dmloadout", "1", FCVAR_ARCHIVE, "Legacy map loadout: 0 off, 1 supply weapons missing for placed ammo, 2 full HL2DM loadout" ) local function MapProvidesWeapon(className) if #ents.FindByClass(className) > 0 then return true end for _, equip in ipairs(ents.FindByClass("game_player_equip")) do local weaponNames = equip:GetSaveTable().m_weaponNames or {} for _, equippedClass in pairs(weaponNames) do if string.lower(tostring(equippedClass)) == className then return true end end end return false end BuildAutomaticLoadout = function() automaticLoadout = {} for _, pair in ipairs(ammoWeaponPairs) do local hasAmmoPickup = false for _, ammoClass in ipairs(pair.ammo) do if #ents.FindByClass(ammoClass) > 0 then hasAmmoPickup = true break end end if hasAmmoPickup and not MapProvidesWeapon(pair.weapon) then automaticLoadout[#automaticLoadout + 1] = pair.weapon end end end hook.Add("InitPostEntity", "CustomCoopDetectMissingAmmoWeapons", BuildAutomaticLoadout) end function GM:PlayerLoadout(ply) if striponspawn then return end ply:Give("weapon_fists") local loadoutMode = hl2dmLoadout and hl2dmLoadout:GetInt() or 0 if loadoutMode <= 0 then return end if loadoutMode == 1 then -- InitPostEntity normally prepares this before anybody spawns. The -- fallback also covers script auto-refresh during a running map. if not automaticLoadout and BuildAutomaticLoadout then BuildAutomaticLoadout() end for _, weaponClass in ipairs(automaticLoadout or {}) do ply:Give(weaponClass) end return end -- Forced compatibility mode mirrors CHL2MP_Player::GiveDefaultItems. ply:Give("weapon_crowbar") ply:Give("weapon_pistol") ply:Give("weapon_smg1") ply:Give("weapon_frag") ply:Give("weapon_physcannon") ply:GiveAmmo(255, "Pistol", true) ply:GiveAmmo(45, "SMG1", true) ply:GiveAmmo(1, "Grenade", true) ply:GiveAmmo(6, "Buckshot", true) ply:GiveAmmo(6, "357", true) end hook.Add( "SpawnMenuOpen", "DisallowSpawnMenu", function () return LocalPlayer():IsAdmin() end) hook.Add( "ContextMenuOpen", "DisallowSpawnMenu", function () return LocalPlayer():IsAdmin() end) function GM:PlayerNoClip(ply, desiredState) if desiredState then return ply:IsAdmin() else return true end end function GM:PlayerDeathSound() return true end function GM:DrawDeathNotice(x, y) return false end function GM:PlayerSpawnVehicle(ply, model, name, table) return ply:IsAdmin() end function GM:PlayerSpawnSWEP(ply, weapon, info) return ply:IsAdmin() end function GM:PlayerSpawnSENT(ply, class) return ply:IsAdmin() end function GM:PlayerSpawnRagdoll(ply, model) return ply:IsAdmin() end function GM:PlayerSpawnProp(ply, model) return ply:IsAdmin() end function GM:PlayerSpawnObject(ply, model, skin) return ply:IsAdmin() end function GM:PlayerSpawnNPC(ply, npc_type, weapon) return ply:IsAdmin() end function GM:PlayerSpawnEffect(ply, model) return ply:IsAdmin() end function GM:PlayerGiveSWEP(ply, weapon, swep) return ply:IsAdmin() end --function GM:HUDAmmoPickedUp( item, amount ) -- return false; --end