2014-10-02 08:49:54 +08:00
|
|
|
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
|
|
|
|
|
2014-11-09 18:11:22 +08:00
|
|
|
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
|
|
|
|
|
2014-11-09 18:12:44 +08:00
|
|
|
return not util.TraceLine({start = posa, endpos = posb, mask = MASK_SHOT_OPAQUE, filter = filter}).Hit
|
2014-11-09 18:11:22 +08:00
|
|
|
end
|
|
|
|
|
2014-10-02 08:49:54 +08:00
|
|
|
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
|
2014-11-19 22:07:50 +08:00
|
|
|
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
|
2014-10-02 08:49:54 +08:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function util.BlastDamage2(inflictor, attacker, epicenter, radius, damage)
|
|
|
|
util.BlastDamageEx(inflictor, attacker, epicenter, radius, damage, DMG_BLAST)
|
|
|
|
end
|
|
|
|
|
2014-11-19 22:07:50 +08:00
|
|
|
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
|
|
|
|
|
2014-10-02 08:49:54 +08:00
|
|
|
function util.PoisonBlastDamage(inflictor, attacker, epicenter, radius, damage, noreduce)
|
|
|
|
local filter = inflictor
|
|
|
|
for _, ent in pairs(ents.FindInSphere(epicenter, radius)) do
|
2014-11-19 22:07:50 +08:00
|
|
|
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
|
2014-10-02 08:49:54 +08:00
|
|
|
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
|