zombiesurvival-evolved/gamemodes/zombiesurvival/gamemode/sh_util.lua
JetBoom bd937c290e Large backend update
Players are no longer implicitly zombies if they're not humans. Players
are no longer implicitly humans if they're not zombies. This is
preparation for a third, optional spectator team.
A few small optimizations and fixes.
2015-03-09 13:45:47 -04:00

295 lines
6.6 KiB
Lua

function player.GetAllActive()
local t = {}
for _, pl in pairs(player.GetAll()) do
if not pl:IsSpectator() then
t[#t + 1] = pl
end
end
return t
end
function player.GetAllSpectators()
local t = {}
for _, pl in pairs(player.GetAll()) do
if pl:IsSpectator() then
t[#t + 1] = pl
end
end
return t
end
function FindStartingItem(id)
if not id then return end
local t
local num = tonumber(id)
if num then
t = GAMEMODE.Items[num]
else
for i, tab in pairs(GAMEMODE.Items) do
if tab.Signature == id then
t = tab
break
end
end
end
if t and t.WorthShop then return t end
end
function FindItem(id)
if not id then return end
local t
local num = tonumber(id)
if num then
t = GAMEMODE.Items[num]
else
for i, tab in pairs(GAMEMODE.Items) do
if tab.Signature == id then
t = tab
break
end
end
end
return t
end
function TrueVisible(posa, posb, filter)
local filt = ents.FindByClass("projectile_*")
filt = table.Add(filt, player.GetAll())
if filter then
filt[#filt + 1] = filter
end
return not util.TraceLine({start = posa, endpos = posb, filter = filt, mask = MASK_SHOT}).Hit
end
function TrueVisibleFilters(posa, posb, ...)
local filt = ents.FindByClass("projectile_*")
filt = table.Add(filt, player.GetAll())
if ... ~= nil then
for k, v in pairs({...}) do
filt[#filt + 1] = v
end
end
return not util.TraceLine({start = posa, endpos = posb, filter = filt, mask = MASK_SHOT}).Hit
end
MASK_SHOT_OPAQUE = bit.bor(MASK_SHOT, CONTENTS_OPAQUE)
-- Literally if photon particles can reach point b from point a.
function LightVisible(posa, posb, ...)
local filter = {}
if ... ~= nil then
for k, v in pairs({...}) do
filter[#filter + 1] = v
end
end
return not util.TraceLine({start = posa, endpos = posb, mask = MASK_SHOT_OPAQUE, filter = filter}).Hit
end
function WorldVisible(posa, posb)
return not util.TraceLine({start = posa, endpos = posb, mask = MASK_SOLID_BRUSHONLY}).Hit
end
function ValidFunction(ent, funcname, ...)
if ent and ent:IsValid() and ent[funcname] then
return ent[funcname](ent, ...)
end
end
function CosineInterpolation(y1, y2, mu)
local mu2 = (1 - math.cos(mu * math.pi)) / 2
return y1 * (1 - mu2) + y2 * mu2
end
function string.AndSeparate(list)
local length = #list
if length <= 0 then return "" end
if length == 1 then return list[1] end
if length == 2 then return list[1].." and "..list[2] end
return table.concat(list, ", ", 1, length - 1)..", and "..list[length]
end
function util.SkewedDistance(a, b, skew)
if a.z > b.z then
return math.sqrt((b.x - a.x) ^ 2 + (b.y - a.y) ^ 2 + ((a.z - b.z) * skew) ^ 2)
end
return a:Distance(b)
end
function util.Blood(pos, amount, dir, force, noprediction)
local effectdata = EffectData()
effectdata:SetOrigin(pos)
effectdata:SetMagnitude(amount)
effectdata:SetNormal(dir)
effectdata:SetScale(math.max(128, force))
util.Effect("bloodstream", effectdata, nil, noprediction)
end
-- I had to make this since the default function checks visibility vs. the entitiy's center and not the nearest position.
function util.BlastDamageEx(inflictor, attacker, epicenter, radius, damage, damagetype)
local filter = inflictor
for _, ent in pairs(ents.FindInSphere(epicenter, radius)) do
if ent and ent:IsValid() then
local nearest = ent:NearestPoint(epicenter)
if TrueVisibleFilters(epicenter, nearest, inflictor, ent) then
ent:TakeSpecialDamage(((radius - nearest:Distance(epicenter)) / radius) * damage, damagetype, attacker, inflictor, nearest)
end
end
end
end
function util.BlastDamage2(inflictor, attacker, epicenter, radius, damage)
util.BlastDamageEx(inflictor, attacker, epicenter, radius, damage, DMG_BLAST)
end
function util.FindValidInSphere(pos, radius)
local ret = {}
for _, ent in pairs(util.FindInSphere(pos, radius)) do
if ent and ent:IsValid() then
ret[#ret + 1] = ent
end
end
return ret
end
function util.PoisonBlastDamage(inflictor, attacker, epicenter, radius, damage, noreduce)
local filter = inflictor
for _, ent in pairs(ents.FindInSphere(epicenter, radius)) do
if ent and ent:IsValid() then
local nearest = ent:NearestPoint(epicenter)
if TrueVisibleFilters(epicenter, nearest, inflictor, ent) then
ent:PoisonDamage(((radius - nearest:Distance(epicenter)) / radius) * damage, attacker, inflictor, nil, noreduce)
end
end
end
end
function util.ToMinutesSeconds(seconds)
local minutes = math.floor(seconds / 60)
seconds = seconds - minutes * 60
return string.format("%02d:%02d", minutes, math.floor(seconds))
end
function util.ToMinutesSecondsMilliseconds(seconds)
local minutes = math.floor(seconds / 60)
seconds = seconds - minutes * 60
local milliseconds = math.floor(seconds % 1 * 100)
return string.format("%02d:%02d.%02d", minutes, math.floor(seconds), milliseconds)
end
function util.RemoveAll(class)
for _, ent in pairs(ents.FindByClass(class)) do
ent:Remove()
end
end
local function TooNear(spawn, tab, dist)
local spawnpos = spawn:GetPos()
for _, ent in pairs(tab) do
if ent:GetPos():Distance(spawnpos) <= dist then
return true
end
end
return false
end
function team.GetSpawnPointGrouped(teamid, dist)
dist = dist or 200
local tab = {}
local spawns = team.GetSpawnPoint(teamid)
for _, spawn in pairs(spawns) do
if not TooNear(spawn, tab, dist) then
table.insert(tab, spawn)
end
end
return tab
end
function AccessorFuncDT(tab, membername, type, id)
local emeta = FindMetaTable("Entity")
local setter = emeta["SetDT"..type]
local getter = emeta["GetDT"..type]
tab["Set"..membername] = function(me, val)
setter(me, id, val)
end
tab["Get"..membername] = function(me)
return getter(me, id)
end
end
function team.GetValidSpawnPoint(teamid)
local t = {}
local spawns = team.GetSpawnPoint(teamid)
if spawns then
for _, ent in pairs(spawns) do
if ent:IsValid() then
t[#t + 1] = ent
end
end
end
return t
end
function timer.SimpleEx(delay, action, ...)
if ... == nil then
timer.Simple(delay, action)
else
local a, b, c, d, e, f, g, h, i, j, k = ...
timer.Simple(delay, function() action(a, b, c, d, e, f, g, h, i, j, k) end)
end
end
function timer.CreateEx(timername, delay, repeats, action, ...)
if ... == nil then
timer.Create(timername, delay, repeats, action)
else
local a, b, c, d, e, f, g, h, i, j, k = ...
timer.Create(timername, delay, repeats, function() action(a, b, c, d, e, f, g, h, i, j, k) end)
end
end
function ents.CreateLimited(class, limit)
if #ents.FindByClass(class) >= (limit or 200) then return NULL end
return ents.Create(class)
end
function tonumbersafe(a)
local n = tonumber(a)
if n then
if n == 0 or n < 0 or n > 0 then
return n
end
-- NaN!
return 0
end
return nil
end