Recharge coop wall chargers

This commit is contained in:
2026-09-06 16:36:58 +02:00
parent 0b94cbb081
commit 062c358c23
3 changed files with 119 additions and 2 deletions
+103
View File
@@ -0,0 +1,103 @@
local healthRechargeTime = CreateConVar(
"gc_healthchargerrechargetime",
"60",
FCVAR_ARCHIVE,
"Seconds before an emptied wall health charger refills; 0 disables automatic refills"
)
local suitRechargeTime = CreateConVar(
"gc_suitchargerrechargetime",
"30",
FCVAR_ARCHIVE,
"Seconds before an emptied wall suit charger refills; 0 disables automatic refills"
)
local chargerClasses = {
item_healthcharger = healthRechargeTime,
item_suitcharger = suitRechargeTime
}
local chargerStates = {}
local function GetChargerJuice(charger)
local juice = charger:GetInternalVariable("m_iJuice")
return tonumber(juice)
end
local function GetChargerCapacity(charger, juice)
local maxJuice = charger:GetInternalVariable("m_iMaxJuice")
local displayedJuice = charger:GetInternalVariable("m_flJuice")
return math.max(
juice or 0,
tonumber(maxJuice) or 0,
tonumber(displayedJuice) or 0
)
end
local function RefillCharger(charger, state)
charger:Fire("Recharge")
-- GMod's suit charger implements Recharge, but item_healthcharger does not
-- on all engine branches. Give the native input a frame to run, then use
-- its internal Source charge fields as a compatibility fallback.
timer.Simple(0.1, function()
if not IsValid(charger) or (GetChargerJuice(charger) or 0) > 0 then return end
if not state.capacity or state.capacity <= 0 then return end
charger:SetSaveValue("m_iJuice", state.capacity)
if charger:GetInternalVariable("m_flJuice") ~= nil then
charger:SetSaveValue("m_flJuice", state.capacity)
end
charger:SetCycle(0)
charger:EmitSound("items/medshot4.wav", 60, 100, 0.5)
end)
end
timer.Create("CustomCoopRechargeWallChargers", 1, 0, function()
local now = CurTime()
local seen = {}
for className, rechargeTime in pairs(chargerClasses) do
local delay = math.max(rechargeTime:GetFloat(), 0)
for _, charger in ipairs(ents.FindByClass(className)) do
seen[charger] = true
local juice = GetChargerJuice(charger)
if juice == nil then continue end
local state = chargerStates[charger]
if not state then
-- A mapper may deliberately place a charger with zero charge.
-- Only chargers observed being drained during play are refilled.
state = {
lastJuice = juice,
capacity = GetChargerCapacity(charger, juice)
}
chargerStates[charger] = state
elseif juice > 0 or delay == 0 then
state.refillAt = nil
elseif state.lastJuice > 0 and juice <= 0 then
state.refillAt = now + delay
elseif state.refillAt and now >= state.refillAt then
-- Use the native Source input rather than replacing the entity,
-- preserving its name, Hammer I/O, animation and sounds.
RefillCharger(charger, state)
state.refillAt = nil
end
state.lastJuice = juice
end
end
for charger in pairs(chargerStates) do
if not seen[charger] or not IsValid(charger) then
chargerStates[charger] = nil
end
end
end)
hook.Add("PostCleanupMap", "CustomCoopResetWallChargerTracking", function()
chargerStates = {}
end)
+3 -2
View File
@@ -2,8 +2,9 @@ AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
AddCSLuaFile( "levels.lua" )
include( "spawninit.lua" )
include( "weaponsystem.lua" )
include( "allplayersdied.lua" )
include( "weaponsystem.lua" )
include( "chargersystem.lua" )
include( "allplayersdied.lua" )
include( "deathspectate.lua" )
include( "headcrabs.lua" )
include( "zombies.lua" )
+13
View File
@@ -15,10 +15,23 @@ local respawnDelay = CreateConVar(
local trackedItems = {}
local suppressRespawns = false
-- These use the item_ prefix but are map machinery or containers rather than
-- touch pickups. Ammo crates are already infinite; the others may be removed
-- deliberately by Hammer I/O and must not be recreated as loose supplies.
local persistentItemClasses = {
item_ammo_crate = true,
item_dynamic_resupply = true,
item_healthcharger = true,
item_item_crate = true,
item_suitcharger = true
}
local function IsRespawnable(ent)
if not IsValid(ent) then return false end
local className = ent:GetClass()
if persistentItemClasses[className] then return false end
return string.StartWith(className, "item_") or string.StartWith(className, "weapon_")
end