mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
Upload
This commit is contained in:
505
lua/includes/circles/circles.lua
Normal file
505
lua/includes/circles/circles.lua
Normal file
@@ -0,0 +1,505 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
if SERVER then return false end
|
||||
|
||||
local _R = debug.getregistry()
|
||||
if _R.Circles then return _R.Circles end
|
||||
|
||||
local CIRCLE = {}
|
||||
CIRCLE.__index = CIRCLE
|
||||
|
||||
CIRCLE_FILLED = 0
|
||||
CIRCLE_OUTLINED = 1
|
||||
CIRCLE_BLURRED = 2
|
||||
|
||||
local New do
|
||||
local err_number = "bad argument #%i to 'New' (number expected, got %s)"
|
||||
|
||||
function New(t, r, x, y, ...)
|
||||
assert(isnumber(t), string.format(err_number, 1, type(t)))
|
||||
assert(isnumber(r), string.format(err_number, 2, type(r)))
|
||||
assert(isnumber(x), string.format(err_number, 3, type(x)))
|
||||
assert(isnumber(y), string.format(err_number, 4, type(y)))
|
||||
|
||||
local circle = setmetatable({}, CIRCLE)
|
||||
|
||||
circle:SetType(t)
|
||||
circle:SetRadius(r)
|
||||
circle:SetX(x)
|
||||
circle:SetY(y)
|
||||
|
||||
circle:SetVertices({Count = 0})
|
||||
|
||||
if t == CIRCLE_OUTLINED then
|
||||
local outline_width = ...
|
||||
assert(outline_width == nil or isnumber(outline_width), string.format(err_number, 5, type(outline_width)))
|
||||
|
||||
circle:SetOutlineWidth(outline_width)
|
||||
elseif t == CIRCLE_BLURRED then
|
||||
local blur_layers, blur_density = ...
|
||||
assert(blur_layers == nil or isnumber(blur_layers), string.format(err_number, 5, type(blur_layers)))
|
||||
assert(blur_density == nil or isnumber(blur_density), string.format(err_number, 6, type(blur_density)))
|
||||
|
||||
circle:SetBlurLayers(blur_layers)
|
||||
circle:SetBlurDensity(blur_density)
|
||||
end
|
||||
|
||||
return circle
|
||||
end
|
||||
end
|
||||
|
||||
local RotateVertices do
|
||||
local err_table = "bad argument #1 to 'RotateVertices' (table expected, got %s)"
|
||||
local err_number = "bad argument #%i to 'RotateVertices' (number expected, got %s)"
|
||||
|
||||
function RotateVertices(vertices, ox, oy, rotation, rotate_uv)
|
||||
assert(istable(vertices), string.format(err_table, type(vertices)))
|
||||
assert(isnumber(ox), string.format(err_number, 2, type(ox)))
|
||||
assert(isnumber(oy), string.format(err_number, 3, type(oy)))
|
||||
assert(isnumber(rotation), string.format(err_number, 4, type(rotation)))
|
||||
|
||||
local rotation = math.rad(rotation)
|
||||
local c = math.cos(rotation)
|
||||
local s = math.sin(rotation)
|
||||
|
||||
for i = 1, vertices.Count or #vertices do
|
||||
local vertex = vertices[i]
|
||||
local vx, vy = vertex.x, vertex.y
|
||||
|
||||
vx = vx - ox
|
||||
vy = vy - oy
|
||||
|
||||
vertex.x = ox + (vx * c - vy * s)
|
||||
vertex.y = oy + (vx * s + vy * c)
|
||||
|
||||
if rotate_uv == false then
|
||||
local u, v = vertex.u, vertex.v
|
||||
u, v = u - 0.5, v - 0.5
|
||||
|
||||
vertex.u = 0.5 + (u * c - v * s)
|
||||
vertex.v = 0.5 + (u * s + v * c)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local CalculateVertices do
|
||||
local err_number = "bad argument #%i to 'CalculateVertices' (number expected, got %s)"
|
||||
|
||||
function CalculateVertices(x, y, radius, rotation, start_angle, end_angle, distance, rotate_uv)
|
||||
assert(isnumber(x), string.format(err_number, 1, type(x)))
|
||||
assert(isnumber(y), string.format(err_number, 2, type(y)))
|
||||
assert(isnumber(radius), string.format(err_number, 3, type(radius)))
|
||||
assert(isnumber(rotation), string.format(err_number, 4, type(rotation)))
|
||||
assert(isnumber(start_angle), string.format(err_number, 5, type(start_angle)))
|
||||
assert(isnumber(end_angle), string.format(err_number, 6, type(end_angle)))
|
||||
assert(isnumber(distance), string.format(err_number, 7, type(distance)))
|
||||
|
||||
local vertices = {Count = 0}
|
||||
local step = distance / radius
|
||||
|
||||
local rad_start_angle = math.rad(start_angle)
|
||||
local rad_end_angle = math.rad(end_angle)
|
||||
local rad_rotation = math.rad(rotation)
|
||||
|
||||
for a = rad_start_angle, rad_end_angle + step, step do
|
||||
a = math.min(a, rad_end_angle)
|
||||
|
||||
local c = math.cos(a + rad_rotation)
|
||||
local s = math.sin(a + rad_rotation)
|
||||
|
||||
local vertex = {
|
||||
x = x + c * radius,
|
||||
y = y + s * radius,
|
||||
}
|
||||
|
||||
if rotate_uv == false then
|
||||
vertex.u = 0.5 + math.cos(a) / 2
|
||||
vertex.v = 0.5 + math.sin(a) / 2
|
||||
else
|
||||
vertex.u = 0.5 + c / 2
|
||||
vertex.v = 0.5 + s / 2
|
||||
end
|
||||
|
||||
vertices.Count = vertices.Count + 1
|
||||
vertices[vertices.Count] = vertex
|
||||
end
|
||||
|
||||
if end_angle - start_angle ~= 360 then
|
||||
table.insert(vertices, 1, {
|
||||
x = x, y = y,
|
||||
u = 0.5, v = 0.5,
|
||||
})
|
||||
|
||||
vertices.Count = vertices.Count + 1
|
||||
else
|
||||
table.remove(vertices)
|
||||
vertices.Count = vertices.Count - 1
|
||||
end
|
||||
|
||||
return vertices
|
||||
end
|
||||
end
|
||||
|
||||
function CIRCLE:__tostring()
|
||||
return string.format("Circle: %p", self)
|
||||
end
|
||||
|
||||
function CIRCLE:Copy()
|
||||
return table.Copy(self)
|
||||
end
|
||||
|
||||
function CIRCLE:IsValid()
|
||||
return (
|
||||
not self.m_Dirty and
|
||||
self.m_Vertices.Count >= 3 and
|
||||
self.m_Radius >= 1 and
|
||||
self.m_Distance >= 1
|
||||
)
|
||||
end
|
||||
|
||||
function CIRCLE:Calculate()
|
||||
local rotate_uv = self.m_RotateMaterial
|
||||
|
||||
local radius = self.m_Radius
|
||||
local x, y = self.m_X, self.m_Y
|
||||
|
||||
local rotation = self.m_Rotation
|
||||
local start_angle = self.m_StartAngle
|
||||
local end_angle = self.m_EndAngle
|
||||
|
||||
local distance = self.m_Distance
|
||||
|
||||
assert(radius >= 1, string.format("circle radius should be >= 1 (%.4f)", radius))
|
||||
assert(distance >= 1, string.format("circle distance should be >= 1 (%.4f)", distance))
|
||||
|
||||
self:SetVertices(CalculateVertices(x, y, radius, rotation, start_angle, end_angle, distance, rotate_uv))
|
||||
|
||||
if self.m_Type == CIRCLE_OUTLINED then
|
||||
local inner = self.m_ChildCircle or self:Copy()
|
||||
local inner_r = radius - self.m_OutlineWidth
|
||||
|
||||
inner:SetType(CIRCLE_FILLED)
|
||||
|
||||
inner:SetPos(x, y)
|
||||
inner:SetRadius(inner_r)
|
||||
inner:SetRotation(rotation)
|
||||
inner:SetAngles(start_angle, end_angle)
|
||||
inner:SetDistance(distance)
|
||||
|
||||
inner:SetColor(false)
|
||||
inner:SetMaterial(false)
|
||||
|
||||
inner:SetShouldRender(inner_r >= 1)
|
||||
inner:SetDirty(inner.m_ShouldRender)
|
||||
|
||||
self:SetShouldRender(inner_r < radius)
|
||||
self:SetChildCircle(inner)
|
||||
elseif self.m_ChildCircle then
|
||||
self.m_ChildCircle = nil
|
||||
end
|
||||
|
||||
self:SetDirty(false)
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
do
|
||||
local blur = Material("pp/blurscreen")
|
||||
|
||||
function CIRCLE:__call()
|
||||
if self.m_Dirty then self:Calculate() end
|
||||
|
||||
if not self:IsValid() then return false end
|
||||
if not self.m_ShouldRender then return false end
|
||||
|
||||
do
|
||||
local col, mat = self.m_Color, self.m_Material
|
||||
|
||||
if IsColor(col) then
|
||||
if col.a <= 0 then return end
|
||||
surface.SetDrawColor(col.r, col.g, col.b, col.a)
|
||||
end
|
||||
|
||||
if mat == true then
|
||||
draw.NoTexture()
|
||||
elseif TypeID(mat) == TYPE_MATERIAL then
|
||||
surface.SetMaterial(mat)
|
||||
end
|
||||
end
|
||||
|
||||
if self.m_Type == CIRCLE_OUTLINED then
|
||||
render.ClearStencil()
|
||||
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilTestMask(0xFF)
|
||||
render.SetStencilWriteMask(0xFF)
|
||||
render.SetStencilReferenceValue(0x01)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_NEVER)
|
||||
render.SetStencilFailOperation(STENCIL_REPLACE)
|
||||
render.SetStencilZFailOperation(STENCIL_REPLACE)
|
||||
|
||||
self.m_ChildCircle()
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_GREATER)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
|
||||
surface.DrawPoly(self.m_Vertices)
|
||||
render.SetStencilEnable(false)
|
||||
elseif self.m_Type == CIRCLE_BLURRED then
|
||||
render.ClearStencil()
|
||||
|
||||
render.SetStencilEnable(true)
|
||||
render.SetStencilTestMask(0xFF)
|
||||
render.SetStencilWriteMask(0xFF)
|
||||
render.SetStencilReferenceValue(0x01)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_NEVER)
|
||||
render.SetStencilFailOperation(STENCIL_REPLACE)
|
||||
render.SetStencilZFailOperation(STENCIL_REPLACE)
|
||||
|
||||
surface.DrawPoly(self.m_Vertices)
|
||||
|
||||
render.SetStencilCompareFunction(STENCIL_LESSEQUAL)
|
||||
render.SetStencilFailOperation(STENCIL_KEEP)
|
||||
render.SetStencilZFailOperation(STENCIL_KEEP)
|
||||
|
||||
surface.SetMaterial(blur)
|
||||
|
||||
local sw, sh = ScrW(), ScrH()
|
||||
|
||||
for i = 1, self.m_BlurLayers do
|
||||
blur:SetFloat("$blur", (i / self.m_BlurLayers) * self.m_BlurDensity)
|
||||
blur:Recompute()
|
||||
|
||||
render.UpdateScreenEffectTexture()
|
||||
surface.DrawTexturedRect(0, 0, sw, sh)
|
||||
end
|
||||
render.SetStencilEnable(false)
|
||||
else
|
||||
surface.DrawPoly(self.m_Vertices)
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
CIRCLE.Draw = CIRCLE.__call
|
||||
end
|
||||
|
||||
do
|
||||
local err_number = "bad argument #%i to 'Translate' (number expected, got %s)"
|
||||
|
||||
function CIRCLE:Translate(x, y)
|
||||
assert(isnumber(x), string.format(err_number, 1, type(x)))
|
||||
assert(isnumber(y), string.format(err_number, 2, type(y)))
|
||||
|
||||
if x ~= 0 or y ~= 0 then
|
||||
self.m_X = self.m_X + x
|
||||
self.m_Y = self.m_Y + y
|
||||
|
||||
if self:IsValid() then
|
||||
for i = 1, self.m_Vertices.Count do
|
||||
local vertex = self.m_Vertices[i]
|
||||
|
||||
vertex.x = vertex.x + x
|
||||
vertex.y = vertex.y + y
|
||||
end
|
||||
|
||||
if self.m_Type == CIRCLE_OUTLINED and self.m_ChildCircle then
|
||||
self.m_ChildCircle:Translate(x, y)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local err_number = "bad argument #1 to 'Scale' (number expected, got %s)"
|
||||
|
||||
function CIRCLE:Scale(scale)
|
||||
assert(isnumber(scale), string.format(err_number, type(scale)))
|
||||
|
||||
if scale ~= 1 then
|
||||
self.m_Radius = self.m_Radius * scale
|
||||
|
||||
if self:IsValid() then
|
||||
local x, y = self.m_X, self.m_Y
|
||||
|
||||
for i = 1, self.m_Vertices.Count do
|
||||
local vertex = self.m_Vertices[i]
|
||||
|
||||
vertex.x = x + (vertex.x - x) * scale
|
||||
vertex.y = y + (vertex.y - y) * scale
|
||||
end
|
||||
|
||||
if self.m_Type == CIRCLE_OUTLINED and self.m_ChildCircle then
|
||||
self.m_ChildCircle:Scale(scale)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local err_number = "bad argument #1 to 'Rotate' (number expected, got %s)"
|
||||
|
||||
function CIRCLE:Rotate(rotation)
|
||||
assert(isnumber(rotation), string.format(err_number, type(rotation)))
|
||||
|
||||
if rotation ~= 0 then
|
||||
self.m_Rotation = self.m_Rotation + rotation
|
||||
|
||||
if self:IsValid() then
|
||||
local x, y = self.m_X, self.m_Y
|
||||
local vertices = self.m_Vertices
|
||||
local rotate_uv = self.m_RotateMaterial
|
||||
|
||||
RotateVertices(vertices, x, y, rotation, rotate_uv)
|
||||
|
||||
if self.m_Type == CIRCLE_OUTLINED and self.m_ChildCircle then
|
||||
self.m_ChildCircle:Rotate(rotation)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local function AccessorFunc(name, default, dirty, callback)
|
||||
local varname = "m_" .. name
|
||||
|
||||
CIRCLE["Get" .. name] = function(self)
|
||||
return self[varname]
|
||||
end
|
||||
|
||||
CIRCLE["Set" .. name] = function(self, value)
|
||||
if default ~= nil and value == nil then
|
||||
value = default
|
||||
end
|
||||
|
||||
if self[varname] ~= value then
|
||||
if dirty then
|
||||
self[dirty] = true
|
||||
end
|
||||
|
||||
if callback ~= nil then
|
||||
local new = callback(self, self[varname], value)
|
||||
value = new ~= nil and new or value
|
||||
end
|
||||
|
||||
self[varname] = value
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
CIRCLE[varname] = default
|
||||
end
|
||||
|
||||
local function OffsetVerticesX(circle, old, new)
|
||||
circle:Translate(new - old, 0)
|
||||
|
||||
if circle.m_Type == CIRCLE_OUTLINED and circle.m_ChildCircle then
|
||||
circle.m_ChildCircle:Translate(new - old, 0)
|
||||
end
|
||||
end
|
||||
|
||||
local function OffsetVerticesY(circle, old, new)
|
||||
circle:Translate(0, new - old)
|
||||
|
||||
if circle.m_Type == CIRCLE_OUTLINED and circle.m_ChildCircle then
|
||||
circle.m_ChildCircle:Translate(0, new - old)
|
||||
end
|
||||
end
|
||||
|
||||
local function UpdateRotation(circle, old, new)
|
||||
circle:Rotate(new - old)
|
||||
|
||||
if circle.m_Type == CIRCLE_OUTLINED and circle.m_ChildCircle then
|
||||
circle.m_ChildCircle:Rotate(new - old)
|
||||
end
|
||||
end
|
||||
|
||||
-- These are set internally. Only use them if you know what you're doing.
|
||||
AccessorFunc("Dirty", true)
|
||||
AccessorFunc("Vertices", false)
|
||||
AccessorFunc("ChildCircle", false)
|
||||
AccessorFunc("ShouldRender", true)
|
||||
|
||||
AccessorFunc("Color", false) -- The colour you want the circle to be. If set to false then surface.SetDrawColor's can be used.
|
||||
AccessorFunc("Material", false) -- The material you want the circle to render. If set to false then surface.SetMaterial can be used.
|
||||
AccessorFunc("RotateMaterial", true) -- Sets whether or not the circle's UV points should be rotated with the vertices.
|
||||
|
||||
AccessorFunc("Type", CIRCLE_FILLED, "m_Dirty") -- The circle's type.
|
||||
AccessorFunc("X", 0, false, OffsetVerticesX) -- The circle's X position relative to the top left of the screen.
|
||||
AccessorFunc("Y", 0, false, OffsetVerticesY) -- The circle's Y position relative to the top left of the screen.
|
||||
AccessorFunc("Radius", 8, "m_Dirty") -- The circle's radius.
|
||||
AccessorFunc("Rotation", 0, false, UpdateRotation) -- The circle's rotation, measured in degrees.
|
||||
AccessorFunc("StartAngle", 0, "m_Dirty") -- The circle's start angle, measured in degrees.
|
||||
AccessorFunc("EndAngle", 360, "m_Dirty") -- The circle's end angle, measured in degrees.
|
||||
AccessorFunc("Distance", 10, "m_Dirty") -- The maximum distance between each of the circle's vertices. This should typically be used for large circles in 3D2D.
|
||||
|
||||
AccessorFunc("BlurLayers", 3) -- The circle's blur layers if Type is set to CIRCLE_BLURRED.
|
||||
AccessorFunc("BlurDensity", 2) -- The circle's blur density if Type is set to CIRCLE_BLURRED.
|
||||
AccessorFunc("OutlineWidth", 10, "m_Dirty") -- The circle's outline width if Type is set to CIRCLE_OUTLINED.
|
||||
|
||||
function CIRCLE:SetPos(x, y)
|
||||
x = tonumber(x) or self.m_X
|
||||
y = tonumber(y) or self.m_Y
|
||||
|
||||
if self:IsValid() then
|
||||
self:Translate(x - self.m_X, y - self.m_Y)
|
||||
else
|
||||
self.m_X = x
|
||||
self.m_Y = y
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function CIRCLE:SetAngles(s, e)
|
||||
s = tonumber(s) or self.m_StartAngle
|
||||
e = tonumber(e) or self.m_EndAngle
|
||||
|
||||
self:SetDirty(self.m_Dirty or s ~= self.m_StartAngle or e ~= self.m_EndAngle)
|
||||
|
||||
self.m_StartAngle = s
|
||||
self.m_EndAngle = e
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
function CIRCLE:GetPos()
|
||||
return self.m_X, self.m_Y
|
||||
end
|
||||
|
||||
function CIRCLE:GetAngles()
|
||||
return self.m_StartAngle, self.m_EndAngle
|
||||
end
|
||||
end
|
||||
|
||||
_R.Circles = {
|
||||
_MT = CIRCLE,
|
||||
|
||||
New = New,
|
||||
RotateVertices = RotateVertices,
|
||||
CalculateVertices = CalculateVertices,
|
||||
}
|
||||
|
||||
return _R.Circles
|
||||
28
lua/includes/extensions/angle.lua
Normal file
28
lua/includes/extensions/angle.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local meta = FindMetaTable( "Angle" )
|
||||
|
||||
-- Nothing in here, still leaving this file here just in case
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Angle Snap to nearest interval of degrees
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SnapTo( component, degrees )
|
||||
|
||||
if ( degrees == 0 ) then ErrorNoHalt( "The snap degrees must be non-zero.\n" ); return self; end
|
||||
if ( !self[ component ] ) then ErrorNoHalt( "You must choose a valid component of Angle( p || pitch, y || yaw, r || roll ) to snap such as Angle( 80, 40, 30 ):SnapTo( \"p\", 90 ):SnapTo( \"y\", 45 ):SnapTo( \"r\", 40 ); and yes, you can keep adding snaps.\n" ); return self; end
|
||||
|
||||
self[ component ] = math.Round( self[ component ] / degrees ) * degrees
|
||||
self[ component ] = math.NormalizeAngle( self[ component ] )
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
27
lua/includes/extensions/client/entity.lua
Normal file
27
lua/includes/extensions/client/entity.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local meta = FindMetaTable( "Entity" )
|
||||
if ( !meta ) then return end
|
||||
|
||||
|
||||
--
|
||||
-- You can set the render angles and render origin on
|
||||
-- any entity. It will then render the entity at that
|
||||
-- origin using those angles.
|
||||
--
|
||||
-- Set them to nil if you don't want to override anything.
|
||||
--
|
||||
|
||||
AccessorFunc( meta, "m_RenderAngles", "RenderAngles" )
|
||||
AccessorFunc( meta, "m_RenderOrigin", "RenderOrigin" )
|
||||
24
lua/includes/extensions/client/globals.lua
Normal file
24
lua/includes/extensions/client/globals.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
|
||||
function ScreenScale( width )
|
||||
return width * ( ScrW() / 640.0 )
|
||||
end
|
||||
|
||||
function ScreenScaleH( height )
|
||||
return height * ( ScrH() / 480.0 )
|
||||
end
|
||||
|
||||
SScale = ScreenScale
|
||||
631
lua/includes/extensions/client/panel.lua
Normal file
631
lua/includes/extensions/client/panel.lua
Normal file
@@ -0,0 +1,631 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include ( "panel/animation.lua" )
|
||||
include ( "panel/dragdrop.lua" )
|
||||
include ( "panel/selections.lua" )
|
||||
include ( "panel/scriptedpanels.lua" )
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
AccessorFunc( meta, "m_strCookieName", "CookieName" )
|
||||
|
||||
meta.SetFGColorEx = meta.SetFGColor
|
||||
meta.SetBGColorEx = meta.SetBGColor
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetFGColor
|
||||
Desc: Override to make it possible to pass Color's
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetFGColor( r, g, b, a )
|
||||
|
||||
if ( istable( r ) ) then
|
||||
return self:SetFGColorEx( r.r, r.g, r.b, r.a )
|
||||
end
|
||||
|
||||
return self:SetFGColorEx( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetBGColor
|
||||
Desc: Override to make it possible to pass Color's
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetBGColor( r, g, b, a )
|
||||
|
||||
if ( istable( r ) ) then
|
||||
return self:SetBGColorEx( r.r, r.g, r.b, r.a )
|
||||
end
|
||||
|
||||
return self:SetBGColorEx( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetHeight( h )
|
||||
self:SetSize( self:GetWide(), h )
|
||||
end
|
||||
meta.SetTall = meta.SetHeight
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetWidth( w )
|
||||
self:SetSize( w, self:GetTall() )
|
||||
end
|
||||
meta.SetWide = meta.SetWidth
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Set/GetX/Y
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetX()
|
||||
local x, y = self:GetPos()
|
||||
return x
|
||||
end
|
||||
function meta:GetY()
|
||||
local x, y = self:GetPos()
|
||||
return y
|
||||
end
|
||||
function meta:SetX( x )
|
||||
self:SetPos( x, self:GetY() )
|
||||
end
|
||||
function meta:SetY( y )
|
||||
self:SetPos( self:GetX(), y )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StretchToParent (borders)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:StretchToParent( l, u, r, d )
|
||||
|
||||
local w, h = self:GetParent():GetSize()
|
||||
|
||||
if ( l != nil ) then
|
||||
self.x = l
|
||||
end
|
||||
|
||||
if ( u != nil ) then
|
||||
self.y = u
|
||||
end
|
||||
|
||||
if ( r != nil ) then
|
||||
self:SetWide( w - self.x - r )
|
||||
end
|
||||
|
||||
if ( d != nil ) then
|
||||
self:SetTall( h - self.y - d )
|
||||
end
|
||||
|
||||
--self:SetPos( l, u )
|
||||
--self:SetSize( w - (r + l), h - (d + u) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyHeight( pnl )
|
||||
self:SetTall( pnl:GetTall() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyWidth
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyWidth( pnl )
|
||||
self:SetWide( pnl:GetWide() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyPos
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyPos( pnl )
|
||||
self:SetPos( pnl:GetPos() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Align with the edge of the parent
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AlignBottom( m ) self:SetPos( self.x, self:GetParent():GetTall() - self:GetTall() - ( m or 0 ) ) end
|
||||
function meta:AlignRight( m ) self:SetPos( self:GetParent():GetWide() - self:GetWide() - ( m or 0 ), self.y ) end
|
||||
function meta:AlignTop( m ) self:SetPos( self.x, m or 0 ) end
|
||||
function meta:AlignLeft( m ) self:SetPos( m or 0, self.y ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Move relative to another panel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveAbove( pnl, m ) self:SetPos( self.x, pnl.y - self:GetTall() - ( m or 0 ) ) end
|
||||
function meta:MoveBelow( pnl, m ) self:SetPos( self.x, pnl.y + pnl:GetTall() + ( m or 0 ) ) end
|
||||
function meta:MoveRightOf( pnl, m ) self:SetPos( pnl.x + pnl:GetWide() + ( m or 0 ), self.y ) end
|
||||
function meta:MoveLeftOf( pnl, m ) self:SetPos( pnl.x - self:GetWide() - ( m or 0 ), self.y ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StretchRightTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:StretchRightTo( pnl, m ) self:SetWide( pnl.x - self.x - ( m or 0 ) ) end
|
||||
function meta:StretchBottomTo( pnl, m ) self:SetTall( pnl.y - self.y - ( m or 0 ) ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterVertical
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CenterVertical( fraction )
|
||||
self:SetY( self:GetParent():GetTall() * ( fraction or 0.5 ) - self:GetTall() * 0.5 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterHorizontal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CenterHorizontal( fraction )
|
||||
self:SetX( self:GetParent():GetWide() * ( fraction or 0.5 ) - self:GetWide() * 0.5 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterHorizontal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:Center()
|
||||
|
||||
self:CenterVertical()
|
||||
self:CenterHorizontal()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyBounds
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyBounds( pnl )
|
||||
|
||||
local x, y, w, h = pnl:GetBounds()
|
||||
|
||||
self:SetPos( x, y )
|
||||
self:SetSize( w, h )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookieNumber
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetCookieName( cookiename )
|
||||
|
||||
self.m_strCookieName = cookiename
|
||||
|
||||
-- If we have a loadcookies function, call it.
|
||||
if ( self.LoadCookies ) then
|
||||
self:LoadCookies()
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookieNumber
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetCookieNumber( cookiename, default )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return default end
|
||||
|
||||
return cookie.GetNumber( name .. "." .. cookiename, default )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetCookie( cookiename, default )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return default end
|
||||
|
||||
return cookie.GetString( name .. "." .. cookiename, default )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetCookie( cookiename, value )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return end
|
||||
|
||||
return cookie.Set( name .. "." .. cookiename, value )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DeleteCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:DeleteCookie( cookiename )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return end
|
||||
|
||||
return cookie.Delete( name .. "." .. cookiename )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: InvalidateParent
|
||||
-----------------------------------------------------------]]
|
||||
function meta:InvalidateParent( layoutnow )
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( !parent ) then return end
|
||||
if ( self.LayingOutParent ) then return end
|
||||
|
||||
self.LayingOutParent = true
|
||||
parent:InvalidateLayout( layoutnow )
|
||||
self.LayingOutParent = false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: PositionLabel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:PositionLabel( labelWidth, x, y, lbl, ctrl )
|
||||
|
||||
lbl:SetWide( labelWidth )
|
||||
lbl:SetPos( x, y )
|
||||
|
||||
ctrl.y = y
|
||||
ctrl:MoveRightOf( lbl, 0 )
|
||||
|
||||
return y + math.max( lbl:GetTall(), ctrl:GetTall() )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltip
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltip()
|
||||
return self.strTooltipText
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltipPanel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltipPanel()
|
||||
return self.pnlTooltipPanel
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltipDelay
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltipDelay()
|
||||
return self.numTooltipDelay
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltip
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltip( tooltip )
|
||||
self.strTooltipText = tooltip
|
||||
end
|
||||
meta.SetToolTip = meta.SetTooltip
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltipPanel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltipPanel( panel )
|
||||
self.pnlTooltipPanel = panel
|
||||
if ( IsValid( panel ) ) then panel:SetVisible( false ) end
|
||||
end
|
||||
meta.SetToolTipPanel = meta.SetTooltipPanel
|
||||
|
||||
-- Override which panel will be created instead of DTooltip
|
||||
function meta:SetTooltipPanelOverride( panel )
|
||||
self.pnlTooltipPanelOverride = panel
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltipDelay
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltipDelay( delay )
|
||||
self.numTooltipDelay = delay
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeToContentsY (Only works on Labels)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeToContentsY( addval )
|
||||
|
||||
local w, h = self:GetContentSize()
|
||||
if ( !w || !h ) then return end
|
||||
|
||||
self:SetTall( h + ( addval or 0 ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeToContentsX (Only works on Labels)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeToContentsX( addval )
|
||||
|
||||
local w, h = self:GetContentSize()
|
||||
if ( !w || !h ) then return end
|
||||
|
||||
self:SetWide( w + ( addval or 0 ) )
|
||||
|
||||
end
|
||||
|
||||
-- Make sure all children update their skin, if SOMEHOW they cached their skin before the parent
|
||||
local function InvalidateSkinRecurse( self )
|
||||
|
||||
for id, pnl in pairs( self:GetChildren() ) do
|
||||
InvalidateSkinRecurse( pnl )
|
||||
pnl.m_iSkinIndex = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetSkin
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetSkin( strSkin )
|
||||
|
||||
if ( self.m_ForceSkinName == strSkin ) then return end
|
||||
|
||||
self.m_ForceSkinName = strSkin
|
||||
self.m_iSkinIndex = nil
|
||||
|
||||
InvalidateSkinRecurse( self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetSkin
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetSkin()
|
||||
|
||||
local skin = nil
|
||||
|
||||
if ( derma.SkinChangeIndex() == self.m_iSkinIndex ) then
|
||||
|
||||
skin = self.m_Skin
|
||||
if ( skin ) then return skin end
|
||||
|
||||
end
|
||||
|
||||
-- We have a default skin
|
||||
if ( !skin && self.m_ForceSkinName ) then
|
||||
skin = derma.GetNamedSkin( self.m_ForceSkinName )
|
||||
end
|
||||
|
||||
-- No skin, inherit from parent
|
||||
local parent = self:GetParent()
|
||||
if ( !skin && IsValid( parent ) ) then
|
||||
skin = parent:GetSkin()
|
||||
end
|
||||
|
||||
-- Parent had no skin, use default
|
||||
if ( !skin ) then
|
||||
skin = derma.GetDefaultSkin()
|
||||
end
|
||||
|
||||
-- Save skin details on us so we don't have to keep looking up
|
||||
self.m_Skin = skin
|
||||
self.m_iSkinIndex = derma.SkinChangeIndex()
|
||||
|
||||
self:InvalidateLayout( false )
|
||||
|
||||
return skin
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ToggleVisible
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ToggleVisible()
|
||||
self:SetVisible( !self:IsVisible() )
|
||||
end
|
||||
|
||||
function meta:Distance( pnl )
|
||||
|
||||
if ( !IsValid( pnl ) ) then return 0 end
|
||||
|
||||
return self:DistanceFrom( pnl.x + pnl:GetWide() * 0.5, pnl.y + pnl:GetTall() * 0.5 )
|
||||
|
||||
end
|
||||
|
||||
function meta:DistanceFrom( x, y )
|
||||
|
||||
local x = self.x + self:GetWide() * 0.5 - x
|
||||
local y = self.y + self:GetTall() * 0.5 - y
|
||||
|
||||
return math.sqrt( x * x + y * y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Retusn the child position on this panel. Even if its parented to children of children.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetChildPosition( pnl )
|
||||
|
||||
local x = 0
|
||||
local y = 0
|
||||
|
||||
while ( IsValid( pnl ) && pnl != self ) do
|
||||
|
||||
x = x + pnl.x
|
||||
y = y + pnl.y
|
||||
|
||||
pnl = pnl:GetParent()
|
||||
|
||||
end
|
||||
|
||||
return x, y
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Returns true if the panel is valid. This does not
|
||||
check the type. If the passed object is anything other
|
||||
than a panel or nil, this will error. (speed)
|
||||
-----------------------------------------------------------]]
|
||||
function ValidPanel( pnl )
|
||||
|
||||
if ( !pnl ) then return false end
|
||||
|
||||
return pnl:IsValid()
|
||||
|
||||
end
|
||||
|
||||
function meta:InvalidateChildren( bRecurse )
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( bRecurse ) then
|
||||
v:InvalidateChildren( true )
|
||||
else
|
||||
v:InvalidateLayout( true )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function meta:IsOurChild( child )
|
||||
|
||||
if ( !IsValid( child ) ) then return false end
|
||||
|
||||
return child:HasParent( self )
|
||||
|
||||
end
|
||||
|
||||
function meta:CopyBase( pnl )
|
||||
|
||||
self:CopyBounds( pnl )
|
||||
self:Dock( pnl:GetDock() )
|
||||
|
||||
// TODO. More.
|
||||
|
||||
end
|
||||
|
||||
function meta:Add( pnl )
|
||||
|
||||
if ( isstring( pnl ) ) then
|
||||
local pnl = vgui.Create( pnl, self )
|
||||
return pnl
|
||||
end
|
||||
|
||||
if ( istable( pnl ) ) then
|
||||
local pnl = vgui.CreateFromTable( pnl, self )
|
||||
return pnl
|
||||
end
|
||||
|
||||
pnl:SetParent( self )
|
||||
return pnl
|
||||
|
||||
end
|
||||
|
||||
function meta:GetClosestChild( x, y )
|
||||
|
||||
local distance = 9999
|
||||
local closest = nil
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
local dist = v:DistanceFrom( x, y )
|
||||
if ( dist < distance ) then
|
||||
distance = dist
|
||||
closest = v
|
||||
end
|
||||
end
|
||||
|
||||
return closest, distance
|
||||
|
||||
end
|
||||
|
||||
function meta:LocalCursorPos()
|
||||
return self:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
end
|
||||
|
||||
function meta:MoveToAfter( pnl )
|
||||
|
||||
local children = self:GetParent():GetChildren()
|
||||
|
||||
-- remove us from the table
|
||||
table.RemoveByValue( children, self )
|
||||
|
||||
-- find the key, where we want to be
|
||||
local key = table.KeyFromValue( children, pnl )
|
||||
|
||||
if ( key ) then
|
||||
-- insert us where we wanna be
|
||||
table.insert( children, key + 1, self )
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
for k, v in ipairs( children ) do
|
||||
v:SetZPos( k )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:MoveToBefore( pnl )
|
||||
|
||||
local children = self:GetParent():GetChildren()
|
||||
|
||||
-- remove us from the table
|
||||
table.RemoveByValue( children, self )
|
||||
|
||||
-- find the key, where we want to be
|
||||
local key = table.KeyFromValue( children, pnl )
|
||||
|
||||
if ( key ) then
|
||||
-- insert us where we wanna be
|
||||
table.insert( children, key, self )
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
for k, v in ipairs( children ) do
|
||||
v:SetZPos( k )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:Clear()
|
||||
|
||||
for k, panel in ipairs( self:GetChildren() ) do
|
||||
panel:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:IsHovered()
|
||||
return vgui.GetHoveredPanel() == self
|
||||
end
|
||||
|
||||
function meta:Show()
|
||||
self:SetVisible( true )
|
||||
end
|
||||
|
||||
function meta:Hide()
|
||||
self:SetVisible( false )
|
||||
end
|
||||
|
||||
function meta:IsChildHovered( bImmediate )
|
||||
|
||||
local Hovered = vgui.GetHoveredPanel()
|
||||
if ( !IsValid( Hovered ) ) then return false end
|
||||
if ( Hovered == self ) then return false end
|
||||
|
||||
-- Check immediate child only (with support for old depth parameter)
|
||||
if ( bImmediate == true or bImmediate == 1 ) then return Hovered:GetParent() == self end
|
||||
|
||||
return Hovered:HasParent( self )
|
||||
|
||||
end
|
||||
375
lua/includes/extensions/client/panel/animation.lua
Normal file
375
lua/includes/extensions/client/panel/animation.lua
Normal file
@@ -0,0 +1,375 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTerm
|
||||
Desc: Kill the panel at this time
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTerm( term )
|
||||
|
||||
self.Term = SysTime() + term
|
||||
self:SetAnimationEnabled( true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AnimationThinkInternal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AnimationThinkInternal()
|
||||
|
||||
local systime = SysTime()
|
||||
|
||||
if ( self.Term && self.Term <= systime ) then self:Remove() return end
|
||||
if ( !self.m_AnimList ) then return end -- This can happen if we only have term
|
||||
|
||||
for k, anim in pairs( self.m_AnimList ) do
|
||||
|
||||
if ( systime >= anim.StartTime ) then
|
||||
|
||||
local Fraction = math.TimeFraction( anim.StartTime, anim.EndTime, systime )
|
||||
Fraction = math.Clamp( Fraction, 0, 1 )
|
||||
|
||||
if ( anim.Think ) then
|
||||
|
||||
local Frac = Fraction ^ anim.Ease
|
||||
|
||||
-- Ease of -1 == ease in out
|
||||
if ( anim.Ease < 0 ) then
|
||||
Frac = Fraction ^ ( 1.0 - ( ( Fraction - 0.5 ) ) )
|
||||
elseif ( anim.Ease > 0 && anim.Ease < 1 ) then
|
||||
Frac = 1 - ( ( 1 - Fraction ) ^ ( 1 / anim.Ease ) )
|
||||
end
|
||||
|
||||
anim:Think( self, Frac )
|
||||
end
|
||||
|
||||
if ( Fraction == 1 ) then
|
||||
|
||||
if ( anim.OnEnd ) then anim:OnEnd( self ) end
|
||||
|
||||
self.m_AnimList[k] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetAnimationEnabled
|
||||
Desc: Enables animations on a panel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetAnimationEnabled( b )
|
||||
|
||||
if ( !b ) then
|
||||
self.AnimationThink = nil
|
||||
return
|
||||
end
|
||||
|
||||
if ( self.AnimationThink ) then return end
|
||||
|
||||
self.AnimationThink = self.AnimationThinkInternal
|
||||
|
||||
end
|
||||
|
||||
function meta:Stop()
|
||||
|
||||
self.m_AnimList = {}
|
||||
|
||||
end
|
||||
|
||||
function meta:Queue()
|
||||
|
||||
self.m_AnimQueue = true
|
||||
|
||||
end
|
||||
|
||||
function meta:AnimTail()
|
||||
|
||||
local last = SysTime()
|
||||
|
||||
for k, anim in pairs( self.m_AnimList ) do
|
||||
last = math.max( last, anim.EndTime )
|
||||
end
|
||||
|
||||
return last
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: NewAnimation
|
||||
Desc: Creates a new animation
|
||||
-----------------------------------------------------------]]
|
||||
function meta:NewAnimation( length, delay, ease, callback )
|
||||
|
||||
if ( delay == nil ) then delay = 0 end
|
||||
if ( ease == nil ) then ease = -1 end
|
||||
|
||||
if ( self.m_AnimQueue ) then
|
||||
|
||||
delay = delay + self:AnimTail()
|
||||
self.m_AnimQueue = false
|
||||
|
||||
else
|
||||
|
||||
delay = delay + SysTime()
|
||||
|
||||
end
|
||||
|
||||
local anim = {
|
||||
EndTime = delay + length,
|
||||
StartTime = delay,
|
||||
Ease = ease,
|
||||
OnEnd = callback
|
||||
}
|
||||
|
||||
self:SetAnimationEnabled( true )
|
||||
if ( self.m_AnimList == nil ) then self.m_AnimList = {} end
|
||||
|
||||
table.insert( self.m_AnimList, anim )
|
||||
|
||||
return anim
|
||||
|
||||
end
|
||||
|
||||
local function MoveThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartPos ) then anim.StartPos = Vector( panel.x, panel.y, 0 ) end
|
||||
local pos = LerpVector( fraction, anim.StartPos, anim.Pos )
|
||||
panel:SetPos( pos.x, pos.y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MoveTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveTo( x, y, length, delay, ease, callback )
|
||||
|
||||
if ( self.x == x && self.y == y ) then return end
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
anim.Pos = Vector( x, y, 0 )
|
||||
anim.Think = MoveThink
|
||||
|
||||
end
|
||||
|
||||
local function SizeThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartSize ) then local w, h = panel:GetSize() anim.StartSize = Vector( w, h, 0 ) end
|
||||
|
||||
local size = LerpVector( fraction, anim.StartSize, anim.Size )
|
||||
|
||||
if ( anim.SizeX && anim.SizeY ) then
|
||||
panel:SetSize( size.x, size.y )
|
||||
elseif ( anim.SizeX ) then
|
||||
panel:SetWide( size.x )
|
||||
else
|
||||
panel:SetTall( size.y )
|
||||
end
|
||||
|
||||
if ( panel:GetDock() > 0 ) then
|
||||
panel:InvalidateParent()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeTo( w, h, length, delay, ease, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
|
||||
anim.SizeX = w != -1
|
||||
anim.SizeY = h != -1
|
||||
|
||||
if ( !anim.SizeX ) then w = self:GetWide() end
|
||||
if ( !anim.SizeY ) then h = self:GetTall() end
|
||||
|
||||
anim.Size = Vector( w, h, 0 )
|
||||
|
||||
anim.Think = SizeThink
|
||||
return anim
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SlideUp
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SlideUp( length )
|
||||
|
||||
local height = self:GetTall()
|
||||
local anim = self:SizeTo( -1, 0, length )
|
||||
anim.OnEnd = function()
|
||||
self:SetVisible( false )
|
||||
self:SetTall( height )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SlideDown
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SlideDown( length )
|
||||
|
||||
local height = self:GetTall()
|
||||
self:SetVisible( true )
|
||||
self:SetTall( 0 )
|
||||
|
||||
local anim = self:SizeTo( -1, height, length )
|
||||
|
||||
end
|
||||
|
||||
local function ColorThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartColor ) then anim.StartColor = panel:GetColor() end
|
||||
|
||||
panel:SetColor( Color( Lerp( fraction, anim.StartColor.r, anim.Color.r ),
|
||||
Lerp( fraction, anim.StartColor.g, anim.Color.g ),
|
||||
Lerp( fraction, anim.StartColor.b, anim.Color.b ),
|
||||
Lerp( fraction, anim.StartColor.a, anim.Color.a ) ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ColorTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ColorTo( col, length, delay, callback )
|
||||
|
||||
-- We can only use this on specific panel types!
|
||||
if ( !self.SetColor ) then return end
|
||||
if ( !self.GetColor ) then return end
|
||||
|
||||
local anim = self:NewAnimation( length, delay, nil, callback )
|
||||
anim.Color = col
|
||||
anim.Think = ColorThink
|
||||
|
||||
end
|
||||
|
||||
local function AlphaThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartAlpha ) then anim.StartAlpha = panel:GetAlpha() end
|
||||
|
||||
panel:SetAlpha( Lerp( fraction, anim.StartAlpha, anim.Alpha ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AlphaTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AlphaTo( alpha, length, delay, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, nil, callback )
|
||||
anim.Alpha = alpha
|
||||
anim.Think = AlphaThink
|
||||
|
||||
end
|
||||
|
||||
local function MoveByThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartPos ) then
|
||||
anim.StartPos = Vector( panel.x, panel.y, 0 )
|
||||
anim.Pos = anim.StartPos + anim.Pos
|
||||
end
|
||||
|
||||
local pos = LerpVector( fraction, anim.StartPos, anim.Pos )
|
||||
panel:SetPos( pos.x, pos.y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MoveBy
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveBy( x, y, length, delay, ease, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
anim.Pos = Vector( x, y, 0 )
|
||||
anim.Think = MoveByThink
|
||||
|
||||
end
|
||||
|
||||
-- This code is bad and will run forever, never reaching the targetpos.
|
||||
local function LerpPositions( anim, panel )
|
||||
|
||||
if ( !panel.TargetPos ) then return end
|
||||
|
||||
local Speed = FrameTime() * 100 * anim.Speed
|
||||
local Pos = Vector( panel.x, panel.y, 0 )
|
||||
local Distance = panel.TargetPos - Pos
|
||||
local Length = Distance:Length()
|
||||
|
||||
if ( anim.UseGravity && Length > 1 ) then
|
||||
Speed = Speed * ( Length * 0.1 )
|
||||
else
|
||||
Speed = Speed * 10
|
||||
end
|
||||
|
||||
if ( Length < Speed ) then
|
||||
panel:SetPosReal( panel.TargetPos.x, panel.TargetPos.y )
|
||||
panel.TargetPos = nil
|
||||
return
|
||||
end
|
||||
|
||||
Distance:Normalize()
|
||||
Distance = Pos + ( Distance * Speed )
|
||||
|
||||
panel:SetPosReal( Distance.x, Distance.y )
|
||||
|
||||
end
|
||||
|
||||
local function NewSetPos( self, x, y )
|
||||
|
||||
self.TargetPos = Vector( x, y )
|
||||
|
||||
end
|
||||
|
||||
local function NewGetPos( self )
|
||||
|
||||
return self.TargetPos.x, self.TargetPos.y
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LerpPositions
|
||||
-----------------------------------------------------------]]
|
||||
function meta:LerpPositions( speed, usegravity )
|
||||
|
||||
if ( self.SetPosReal ) then return end
|
||||
|
||||
NewSetPos( self, self:GetPos() )
|
||||
|
||||
self.SetPosReal = self.SetPos
|
||||
self.SetPos = NewSetPos
|
||||
self.GetPosReal = self.GetPos
|
||||
self.GetPos = NewGetPos
|
||||
|
||||
self.LerpAnim = self:NewAnimation( 86400 )
|
||||
self.LerpAnim.Speed = speed
|
||||
self.LerpAnim.UseGravity = usegravity
|
||||
self.LerpAnim.Think = LerpPositions
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- DisableLerp
|
||||
--
|
||||
function meta:DisableLerp()
|
||||
|
||||
self.LerpAnim = nil
|
||||
self.SetPos = self.SetPosReal
|
||||
self.GetPos = self.GetPosReal
|
||||
|
||||
end
|
||||
591
lua/includes/extensions/client/panel/dragdrop.lua
Normal file
591
lua/includes/extensions/client/panel/dragdrop.lua
Normal file
@@ -0,0 +1,591 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
dragndrop = {}
|
||||
|
||||
function dragndrop.Clear()
|
||||
|
||||
dragndrop.m_Receiver = nil
|
||||
dragndrop.m_ReceiverSlot = nil
|
||||
dragndrop.m_HoverStart = nil
|
||||
dragndrop.m_MouseCode = 0
|
||||
dragndrop.m_DragWatch = nil
|
||||
dragndrop.m_MouseX = 0
|
||||
dragndrop.m_MouseY = 0
|
||||
dragndrop.m_DraggingMain = nil
|
||||
dragndrop.m_Dragging = nil
|
||||
dragndrop.m_DropMenu = nil
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.IsDragging()
|
||||
|
||||
if ( dragndrop.m_Dragging != nil ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.HandleDroppedInGame()
|
||||
|
||||
local panel = vgui.GetHoveredPanel()
|
||||
if ( !IsValid( panel ) ) then return end
|
||||
if ( panel:GetClassName() != "CGModBase" ) then return end
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.Drop()
|
||||
|
||||
if ( dragndrop.HandleDroppedInGame() ) then
|
||||
dragndrop.StopDragging()
|
||||
return
|
||||
end
|
||||
|
||||
-- Show the menu
|
||||
if ( dragndrop.m_MouseCode == MOUSE_RIGHT && dragndrop.m_ReceiverSlot && dragndrop.m_ReceiverSlot.Menu ) then
|
||||
|
||||
local x, y = dragndrop.m_Receiver:LocalCursorPos()
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu.OnRemove = function( m ) -- If user clicks outside of the menu - drop the dragging
|
||||
dragndrop.StopDragging()
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_ReceiverSlot.Menu ) do
|
||||
|
||||
menu:AddOption( v, function()
|
||||
|
||||
dragndrop.CallReceiverFunction( true, k, x, y )
|
||||
dragndrop.StopDragging()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
|
||||
dragndrop.m_DropMenu = menu
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
dragndrop.CallReceiverFunction( true, nil, nil, nil )
|
||||
dragndrop.StopDragging()
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.StartDragging()
|
||||
|
||||
if ( !dragndrop.m_DragWatch:IsSelected() ) then
|
||||
|
||||
dragndrop.m_Dragging = { dragndrop.m_DragWatch }
|
||||
|
||||
else
|
||||
|
||||
local canvas = dragndrop.m_DragWatch:GetSelectionCanvas()
|
||||
dragndrop.m_Dragging = {}
|
||||
|
||||
for k, v in pairs( canvas:GetSelectedChildren() ) do
|
||||
|
||||
if ( !v.m_DragSlot ) then continue end
|
||||
|
||||
table.insert( dragndrop.m_Dragging, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
v:OnStartDragging()
|
||||
|
||||
end
|
||||
|
||||
dragndrop.m_DraggingMain = dragndrop.m_DragWatch
|
||||
dragndrop.m_DraggingMain:MouseCapture( true )
|
||||
dragndrop.m_DragWatch = nil
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.StopDragging()
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
dragndrop.m_Receiver:DragHoverEnd()
|
||||
dragndrop.m_Receiver = nil
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging or {} ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
v:OnStopDragging()
|
||||
|
||||
end
|
||||
|
||||
dragndrop.Clear()
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.UpdateReceiver()
|
||||
|
||||
local hovered = vgui.GetHoveredPanel()
|
||||
local receiver = nil
|
||||
local receiverslot = nil
|
||||
|
||||
if ( IsValid( hovered ) ) then
|
||||
receiver, receiverslot = hovered:GetValidReceiverSlot()
|
||||
end
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
|
||||
if ( receiver == dragndrop.m_Receiver ) then return end
|
||||
|
||||
dragndrop.m_Receiver:DragHoverEnd()
|
||||
|
||||
end
|
||||
|
||||
if ( !IsValid( receiver ) ) then
|
||||
dragndrop.m_Receiver = nil
|
||||
dragndrop.m_ReceiverSlot = nil
|
||||
end
|
||||
|
||||
dragndrop.m_Receiver = receiver
|
||||
dragndrop.m_ReceiverSlot = receiverslot
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Return all the dragged panels that match this name
|
||||
--
|
||||
function dragndrop.GetDroppable( name )
|
||||
|
||||
if ( !name ) then return dragndrop.m_Dragging end
|
||||
if ( !dragndrop.m_Dragging ) then return end
|
||||
|
||||
local t = {}
|
||||
for id, pnl in pairs( dragndrop.m_Dragging ) do
|
||||
if ( pnl.m_DragSlot && pnl.m_DragSlot[ name ] ) then table.insert( t, pnl ) end
|
||||
end
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.CallReceiverFunction( bDoDrop, command, mx, my )
|
||||
|
||||
if ( !dragndrop.m_ReceiverSlot ) then return end
|
||||
if ( !IsValid( dragndrop.m_Receiver ) ) then return end
|
||||
|
||||
local x, y = dragndrop.m_Receiver:LocalCursorPos()
|
||||
if ( mx ) then x = mx end
|
||||
if ( my ) then y = my end
|
||||
|
||||
if ( dragndrop.m_ReceiverSlot.Func ) then
|
||||
|
||||
local droppable = dragndrop.GetDroppable( dragndrop.m_ReceiverSlot.Name )
|
||||
|
||||
dragndrop.m_ReceiverSlot.Func( dragndrop.m_Receiver, droppable, bDoDrop, command, x, y )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.Think()
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
--
|
||||
-- We're dragging but no mouse buttons are down..
|
||||
-- So force the drop whereever it is!
|
||||
--
|
||||
--[[if ( dragndrop.m_Dragging != nil && !input.IsMouseDown( MOUSE_LEFT ) && !input.IsMouseDown( MOUSE_RIGHT ) ) then
|
||||
dragndrop.m_Dragging:DragMouseRelease( dragndrop.m_MouseCode )
|
||||
return
|
||||
end]]
|
||||
|
||||
--
|
||||
-- We're holding down a panel, watch for start of dragging
|
||||
--
|
||||
if ( IsValid( dragndrop.m_DragWatch ) ) then
|
||||
|
||||
local dist = math.abs( dragndrop.m_MouseX - gui.MouseX() ) + math.abs( dragndrop.m_MouseY - gui.MouseY() )
|
||||
if ( dist > 20 ) then
|
||||
dragndrop.StartDragging()
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( dragndrop.m_Dragging != nil ) then
|
||||
|
||||
dragndrop.HoverThink()
|
||||
dragndrop.UpdateReceiver()
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
dragndrop.CallReceiverFunction( false )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "DrawOverlay", "DragNDropPaint", function()
|
||||
|
||||
if ( dragndrop.m_Dragging == nil ) then return end
|
||||
if ( dragndrop.m_DraggingMain == nil ) then return end
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
local hold_offset_x = 65535
|
||||
local hold_offset_y = 65535
|
||||
|
||||
-- Find the top, left most panel
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
hold_offset_x = math.min( hold_offset_x, v.x )
|
||||
hold_offset_y = math.min( hold_offset_y, v.y )
|
||||
|
||||
end
|
||||
|
||||
local wasEnabled = DisableClipping( true )
|
||||
|
||||
local Alpha = 0.7
|
||||
if ( IsValid( dragndrop.m_Hovered ) ) then Alpha = 0.8 end
|
||||
surface.SetAlphaMultiplier( Alpha )
|
||||
|
||||
local ox = gui.MouseX() - hold_offset_x + 8
|
||||
local oy = gui.MouseY() - hold_offset_y + 8
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
local dist = 512 - v:Distance( dragndrop.m_DraggingMain )
|
||||
|
||||
if ( dist < 0 ) then continue end
|
||||
|
||||
dist = dist / 512
|
||||
surface.SetAlphaMultiplier( Alpha * dist )
|
||||
|
||||
v.PaintingDragging = true
|
||||
v:PaintAt( ox + v.x - v:GetWide() / 2, oy + v.y - v:GetTall() / 2 ) -- fill the gap between the top left corner and the mouse position
|
||||
v.PaintingDragging = nil
|
||||
|
||||
end
|
||||
|
||||
surface.SetAlphaMultiplier( 1.0 )
|
||||
|
||||
DisableClipping( wasEnabled )
|
||||
|
||||
end )
|
||||
hook.Add( "Think", "DragNDropThink", dragndrop.Think )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
--
|
||||
--
|
||||
-- Panel Drag n Drop Extensions
|
||||
--
|
||||
--
|
||||
--
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
--
|
||||
-- Make this panel droppable
|
||||
--
|
||||
function meta:Droppable( name )
|
||||
|
||||
self.m_DragSlot = self.m_DragSlot or {}
|
||||
|
||||
self.m_DragSlot[ name ] = {}
|
||||
|
||||
return self.m_DragSlot[ name ]
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Make this pannel a drop target
|
||||
--
|
||||
function meta:Receiver( name, func, menu )
|
||||
|
||||
self.m_ReceiverSlot = self.m_ReceiverSlot or {}
|
||||
|
||||
self.m_ReceiverSlot[ name ] = {}
|
||||
self.m_ReceiverSlot[ name ].Name = name
|
||||
self.m_ReceiverSlot[ name ].Func = func
|
||||
self.m_ReceiverSlot[ name ].Menu = menu
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Drag parent means that when we start to
|
||||
-- drag this panel, we'll really start
|
||||
-- dragging the defined parent
|
||||
--
|
||||
function meta:SetDragParent( parent )
|
||||
self.m_pDragParent = parent
|
||||
end
|
||||
|
||||
function meta:GetValidReceiverSlot()
|
||||
|
||||
if ( self.m_ReceiverSlot ) then
|
||||
|
||||
-- Find matching slot..
|
||||
for k, v in pairs( self.m_ReceiverSlot ) do
|
||||
|
||||
if ( !dragndrop.m_DraggingMain.m_DragSlot ) then continue end
|
||||
|
||||
local slot = dragndrop.m_DraggingMain.m_DragSlot[ k ]
|
||||
if ( !slot ) then continue end
|
||||
|
||||
return self, v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( !IsValid( self:GetParent() ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:GetParent():GetValidReceiverSlot()
|
||||
|
||||
end
|
||||
|
||||
function meta:IsDraggable()
|
||||
|
||||
return self.m_DragSlot != nil
|
||||
|
||||
end
|
||||
|
||||
function meta:IsDragging()
|
||||
|
||||
if ( !self.m_DragSlot ) then return false end
|
||||
|
||||
return self.Dragging
|
||||
|
||||
end
|
||||
|
||||
function meta:DroppedOn( pnl )
|
||||
-- For override.
|
||||
end
|
||||
|
||||
function meta:OnDrop()
|
||||
|
||||
-- We're being dropped on something
|
||||
-- we can create a new panel here and return it, so that instead of
|
||||
-- dropping us - it drops the new panel instead! We remain where we are!
|
||||
|
||||
-- By default we return ourself
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
function meta:OnStartDragging()
|
||||
|
||||
self.Dragging = true
|
||||
self:InvalidateLayout()
|
||||
|
||||
if ( self:IsSelectable() ) then
|
||||
|
||||
local canvas = self:GetSelectionCanvas()
|
||||
|
||||
if ( IsValid( canvas ) && !self:IsSelected() ) then
|
||||
canvas:UnselectAll()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:OnStopDragging()
|
||||
self.Dragging = false
|
||||
end
|
||||
|
||||
function meta:DragMousePress( mcode )
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
if ( dragndrop.IsDragging() ) then dragndrop.StopDragging() return end
|
||||
|
||||
if ( IsValid( self.m_pDragParent ) and self.m_pDragParent ~= self ) then
|
||||
return self.m_pDragParent:DragMousePress( mcode )
|
||||
end
|
||||
|
||||
if ( !self.m_DragSlot ) then return end
|
||||
|
||||
dragndrop.Clear()
|
||||
dragndrop.m_MouseCode = mcode
|
||||
dragndrop.m_DragWatch = self
|
||||
dragndrop.m_MouseX = gui.MouseX()
|
||||
dragndrop.m_MouseY = gui.MouseY()
|
||||
|
||||
end
|
||||
|
||||
function meta:DragClick( mcode )
|
||||
|
||||
self:MouseCapture( true )
|
||||
-- Clicking one mouse button while dragging with another!
|
||||
-- Return true to stop us clicking and selecting stuff below..
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function meta:DragMouseRelease( mcode )
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
-- This wasn't the button we clicked with - so don't release drag
|
||||
if ( dragndrop.IsDragging() && dragndrop.m_MouseCode != mcode ) then
|
||||
|
||||
return self:DragClick( mcode )
|
||||
|
||||
end
|
||||
|
||||
if ( !dragndrop.IsDragging() ) then
|
||||
dragndrop.Clear()
|
||||
return false
|
||||
end
|
||||
|
||||
dragndrop.Drop()
|
||||
|
||||
-- Todo.. we should only do this if we enabled it!
|
||||
if ( gui.EnableScreenClicker ) then
|
||||
gui.EnableScreenClicker( false )
|
||||
end
|
||||
|
||||
self:MouseCapture( false )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function meta:SetDropTarget( x, y, w, h )
|
||||
|
||||
if ( !self.m_bDrawingPaintOver ) then
|
||||
self.m_OldPaintOver = self.PaintOver
|
||||
self.m_bDrawingPaintOver = true
|
||||
end
|
||||
|
||||
self.PaintOver = function()
|
||||
|
||||
if ( self.m_OldPaintOver ) then
|
||||
self:m_OldPaintOver()
|
||||
end
|
||||
|
||||
self:DrawDragHover( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Drag Hover
|
||||
--
|
||||
-- These functions are used for things like trees
|
||||
-- So that when you hover over the tree while dragging something
|
||||
-- it will open up the tree. This works regardless of whether the
|
||||
-- is droppable or not.
|
||||
--
|
||||
-- Implement DragHoverClick in your panel class to get this functionality
|
||||
--
|
||||
function meta:DragHover( HoverTime )
|
||||
|
||||
--
|
||||
-- Call DragHoverClick if we've been hovering for 0.1 seconds..
|
||||
--
|
||||
if ( HoverTime < 0.1 ) then dragndrop.m_bHoverClick = false end
|
||||
if ( HoverTime > 0.1 && !dragndrop.m_bHoverClick ) then
|
||||
|
||||
self:DragHoverClick( HoverTime )
|
||||
dragndrop.m_bHoverClick = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:DrawDragHover( x, y, w, h )
|
||||
|
||||
DisableClipping( true )
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 100 )
|
||||
surface.DrawRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 220, 255, 230 )
|
||||
surface.DrawOutlinedRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 100, 255, 50 )
|
||||
surface.DrawOutlinedRect( x - 1, y - 1, w + 2, h + 2 )
|
||||
|
||||
DisableClipping( false )
|
||||
|
||||
end
|
||||
|
||||
function meta:DragHoverEnd()
|
||||
|
||||
if ( !self.m_bDrawingPaintOver ) then return end
|
||||
|
||||
self.PaintOver = self.m_OldPaintOver
|
||||
self.m_bDrawingPaintOver = false
|
||||
|
||||
end
|
||||
|
||||
function meta:DragHoverClick( HoverTime )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
--
|
||||
-- This is called to open stuff when you're hovering over it.
|
||||
--
|
||||
--
|
||||
|
||||
local LastHoverThink = nil
|
||||
local LastHoverChangeTime = 0
|
||||
local LastX = 0
|
||||
local LastY = 0
|
||||
|
||||
function dragndrop.HoverThink()
|
||||
|
||||
local hovered = vgui.GetHoveredPanel()
|
||||
local x = gui.MouseX()
|
||||
local y = gui.MouseY()
|
||||
|
||||
-- Hovering a different panel
|
||||
if ( LastHoverThink != hovered or x != LastX or y != LastY ) then
|
||||
|
||||
LastHoverChangeTime = SysTime()
|
||||
LastHoverThink = hovered
|
||||
|
||||
end
|
||||
|
||||
-- Hovered panel might do stuff when we're hovering it
|
||||
-- so give it a chance to do that now.
|
||||
if ( IsValid( LastHoverThink ) ) then
|
||||
|
||||
LastX = x
|
||||
LastY = y
|
||||
LastHoverThink:DragHover( SysTime() - LastHoverChangeTime )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
139
lua/includes/extensions/client/panel/scriptedpanels.lua
Normal file
139
lua/includes/extensions/client/panel/scriptedpanels.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local PanelFactory = {}
|
||||
|
||||
local panel_metatable = FindMetaTable( "Panel" )
|
||||
|
||||
baseclass.Set( "Panel", panel_metatable )
|
||||
baseclass.Set( "Label", panel_metatable )
|
||||
baseclass.Set( "EditablePanel", panel_metatable )
|
||||
|
||||
-- Keep the old function
|
||||
vgui.CreateX = vgui.Create
|
||||
|
||||
function vgui.GetControlTable( classname )
|
||||
return PanelFactory[ classname ]
|
||||
end
|
||||
|
||||
function vgui.Exists( classname )
|
||||
return PanelFactory[ classname ] != nil
|
||||
end
|
||||
|
||||
function vgui.Create( classname, parent, name )
|
||||
|
||||
-- Is this a user-created panel?
|
||||
if ( PanelFactory[ classname ] ) then
|
||||
|
||||
local metatable = PanelFactory[ classname ]
|
||||
|
||||
local panel = vgui.Create( metatable.Base, parent, name or classname )
|
||||
if ( !panel ) then
|
||||
Error( "Tried to create panel with invalid base '" .. metatable.Base .. "'\n" );
|
||||
end
|
||||
|
||||
table.Merge( panel:GetTable(), metatable )
|
||||
panel.BaseClass = PanelFactory[ metatable.Base ]
|
||||
panel.ClassName = classname
|
||||
|
||||
-- Call the Init function if we have it
|
||||
if ( panel.Init ) then
|
||||
panel:Init()
|
||||
end
|
||||
|
||||
panel:Prepare()
|
||||
|
||||
return panel
|
||||
|
||||
end
|
||||
|
||||
return vgui.CreateX( classname, parent, name or classname )
|
||||
|
||||
end
|
||||
|
||||
function vgui.CreateFromTable( metatable, parent, name )
|
||||
|
||||
if ( !istable( metatable ) ) then return nil end
|
||||
|
||||
local panel = vgui.Create( metatable.Base, parent, name )
|
||||
|
||||
table.Merge( panel:GetTable(), metatable )
|
||||
panel.BaseClass = PanelFactory[ metatable.Base ]
|
||||
|
||||
-- Call the Init function if we have it
|
||||
if ( panel.Init ) then
|
||||
panel:Init()
|
||||
end
|
||||
|
||||
panel:Prepare()
|
||||
|
||||
return panel
|
||||
|
||||
end
|
||||
|
||||
function vgui.Register( classname, mtable, base )
|
||||
|
||||
-- Remove the global
|
||||
PANEL = nil
|
||||
|
||||
-- Default base is Panel
|
||||
mtable.Base = base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
PanelFactory[ classname ] = mtable
|
||||
baseclass.Set( classname, mtable )
|
||||
|
||||
local mt = {}
|
||||
mt.__index = function( t, k )
|
||||
|
||||
if ( PanelFactory[ mtable.Base ] && PanelFactory[ mtable.Base ][k] ) then return PanelFactory[ mtable.Base ][k] end
|
||||
return panel_metatable[k]
|
||||
|
||||
end
|
||||
|
||||
setmetatable( mtable, mt )
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
|
||||
function vgui.RegisterTable( mtable, base )
|
||||
|
||||
-- Remove the global
|
||||
PANEL = nil
|
||||
|
||||
mtable.Base = base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
|
||||
function vgui.RegisterFile( filename )
|
||||
|
||||
local OldPanel = PANEL
|
||||
|
||||
PANEL = {}
|
||||
|
||||
-- The included file should fill the PANEL global.
|
||||
include( filename )
|
||||
|
||||
local mtable = PANEL
|
||||
PANEL = OldPanel
|
||||
|
||||
mtable.Base = mtable.Base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
259
lua/includes/extensions/client/panel/selections.lua
Normal file
259
lua/includes/extensions/client/panel/selections.lua
Normal file
@@ -0,0 +1,259 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local StartX = 0
|
||||
local StartY = 0
|
||||
local SelectionCanvas = nil
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
function meta:SetSelectionCanvas( bSet )
|
||||
|
||||
self.m_bSelectionCanvas = bSet
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelectionCanvas()
|
||||
|
||||
return self.m_bSelectionCanvas
|
||||
|
||||
end
|
||||
|
||||
function meta:SetSelectable( bSet )
|
||||
|
||||
self.m_bSelectable = bSet
|
||||
|
||||
end
|
||||
|
||||
function meta:ToggleSelection()
|
||||
|
||||
self:SetSelected( !self.m_bSelected )
|
||||
|
||||
end
|
||||
|
||||
function meta:UnselectAll()
|
||||
|
||||
self:SetSelected( false )
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
v:UnselectAll()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function meta:SetSelected( bSet )
|
||||
|
||||
if ( self.m_bSelected == bSet ) then return end
|
||||
|
||||
self.m_bSelected = bSet
|
||||
|
||||
if ( self.ApplySchemeSettings ) then
|
||||
self:ApplySchemeSettings()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelected( bSet )
|
||||
|
||||
if ( !self:IsSelectable() ) then return false end
|
||||
return self.m_bSelected == true
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelectable()
|
||||
|
||||
return self.m_bSelectable == true
|
||||
|
||||
end
|
||||
|
||||
local function GetSelectionRect()
|
||||
|
||||
if ( !SelectionCanvas ) then
|
||||
debug.Trace()
|
||||
return
|
||||
end
|
||||
|
||||
local CurX, CurY = SelectionCanvas:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
|
||||
local x = math.min( CurX, StartX )
|
||||
local y = math.min( CurY, StartY )
|
||||
|
||||
local w = math.abs( CurX - StartX )
|
||||
local h = math.abs( CurY - StartY )
|
||||
|
||||
return x, y, w, h
|
||||
|
||||
end
|
||||
|
||||
function meta:DrawSelections()
|
||||
|
||||
if ( !self.m_bSelectable ) then return end
|
||||
if ( !self.m_bSelected ) then return end
|
||||
|
||||
local w, h = self:GetSize()
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 100 )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
end
|
||||
|
||||
local function PaintSelectionBox( self )
|
||||
|
||||
if ( !IsValid( SelectionCanvas ) ) then return end
|
||||
local x, y, w, h = GetSelectionRect()
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 50 )
|
||||
surface.DrawRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 200, 255, 200 )
|
||||
surface.DrawOutlinedRect( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
function meta:GetSelectionCanvas()
|
||||
|
||||
if ( !self.m_bSelectionCanvas ) then
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( IsValid( parent ) ) then
|
||||
return parent:GetSelectionCanvas()
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
|
||||
function meta:StartBoxSelection()
|
||||
|
||||
if ( !self.m_bSelectionCanvas ) then
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( IsValid( parent ) ) then
|
||||
return parent:StartBoxSelection()
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
self:MouseCapture( true )
|
||||
|
||||
if ( !input.IsShiftDown() && !input.IsControlDown() ) then
|
||||
self:UnselectAll()
|
||||
end
|
||||
|
||||
SelectionCanvas = self
|
||||
|
||||
StartX, StartY = self:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
|
||||
self.PaintOver_Old = self.PaintOver
|
||||
self.PaintOver = PaintSelectionBox
|
||||
|
||||
end
|
||||
|
||||
function meta:GetChildrenInRect( x, y, w, h )
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
local vw, vh = v:GetSize()
|
||||
|
||||
if ( !self:IsVisible() ) then continue end
|
||||
if ( x > v.x + vw ) then continue end
|
||||
if ( y > v.y + vh ) then continue end
|
||||
if ( v.x > x + w ) then continue end
|
||||
if ( v.y > y + h ) then continue end
|
||||
|
||||
if ( v.m_bSelectable ) then
|
||||
table.insert( tab, v )
|
||||
end
|
||||
|
||||
table.Add( tab, v:GetChildrenInRect( x - v.x, y - v.y, w, h ) )
|
||||
|
||||
end
|
||||
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function meta:GetSelectedChildren()
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( v:IsSelected() ) then
|
||||
table.insert( tab, v )
|
||||
end
|
||||
|
||||
table.Add( tab, v:GetSelectedChildren() )
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function meta:NumSelectedChildren()
|
||||
|
||||
local i = 0
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( v:IsSelected() ) then
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return i
|
||||
|
||||
end
|
||||
|
||||
function meta:EndBoxSelection()
|
||||
|
||||
if ( SelectionCanvas != self ) then return false end
|
||||
|
||||
self:MouseCapture( false )
|
||||
|
||||
self.PaintOver = self.PaintOver_Old
|
||||
self.PaintOver_Old = nil
|
||||
|
||||
for k, v in ipairs( self:GetChildrenInRect( GetSelectionRect() ) ) do
|
||||
|
||||
-- If player is holding shift, add new planels to existing selections, do not toggle
|
||||
-- This mimics already familiar behavior of Windows Explorer, etc
|
||||
if ( input.IsShiftDown() ) then
|
||||
v:SetSelected( true )
|
||||
else
|
||||
v:ToggleSelection()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
SelectionCanvas = nil
|
||||
StartX, StartY = 0, 0
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
86
lua/includes/extensions/client/player.lua
Normal file
86
lua/includes/extensions/client/player.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
|
||||
local playerOptions = {}
|
||||
local bindTranslation = {}
|
||||
bindTranslation["slot1"] = 1
|
||||
bindTranslation["slot2"] = 2
|
||||
bindTranslation["slot3"] = 3
|
||||
bindTranslation["slot4"] = 4
|
||||
bindTranslation["slot5"] = 5
|
||||
bindTranslation["slot6"] = 6
|
||||
bindTranslation["slot7"] = 7
|
||||
bindTranslation["slot8"] = 8
|
||||
bindTranslation["slot9"] = 9
|
||||
bindTranslation["slot0"] = 0
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: PlayerOption
|
||||
Params: <name> <timeout> <input function> <draw function>
|
||||
Desc:
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AddPlayerOption( name, timeout, in_func, draw_func )
|
||||
|
||||
local option = {}
|
||||
option.timeout = timeout
|
||||
option.in_func = in_func
|
||||
option.draw_func = draw_func
|
||||
|
||||
if (timeout != -1) then
|
||||
option.timeout = CurTime() + timeout
|
||||
end
|
||||
|
||||
playerOptions[ name ] = option
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function hook_PlayerOptionInput( pl, bind, down )
|
||||
|
||||
if (!down || !bindTranslation[bind]) then return end
|
||||
|
||||
for k, v in pairs( playerOptions ) do
|
||||
|
||||
if ( v.timeout == -1 || v.timeout > CurTime() ) then
|
||||
|
||||
-- If the function returns true then remove this player option
|
||||
if ( v.in_func( bindTranslation[bind] ) ) then
|
||||
playerOptions[k] = nil
|
||||
end
|
||||
|
||||
return true
|
||||
else
|
||||
playerOptions[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PlayerBindPress", "PlayerOptionInput", hook_PlayerOptionInput )
|
||||
|
||||
local function hook_PlayerOptionDraw()
|
||||
|
||||
for k, v in pairs( playerOptions ) do
|
||||
|
||||
if (v.draw_func) then v.draw_func() end
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "HUDPaint", "PlayerOptionDraw", hook_PlayerOptionDraw )
|
||||
209
lua/includes/extensions/client/render.lua
Normal file
209
lua/includes/extensions/client/render.lua
Normal file
@@ -0,0 +1,209 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- We don't want this to run in menu state, and render.GetAmbientLightColor doesn't exist in menu state
|
||||
if ( !render || !render.GetAmbientLightColor ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Short aliases for stencil constants
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
STENCIL_NEVER = STENCILCOMPARISONFUNCTION_NEVER
|
||||
STENCIL_LESS = STENCILCOMPARISONFUNCTION_LESS
|
||||
STENCIL_EQUAL = STENCILCOMPARISONFUNCTION_EQUAL
|
||||
STENCIL_LESSEQUAL = STENCILCOMPARISONFUNCTION_LESSEQUAL
|
||||
STENCIL_GREATER = STENCILCOMPARISONFUNCTION_GREATER
|
||||
STENCIL_NOTEQUAL = STENCILCOMPARISONFUNCTION_NOTEQUAL
|
||||
STENCIL_GREATEREQUAL = STENCILCOMPARISONFUNCTION_GREATEREQUAL
|
||||
STENCIL_ALWAYS = STENCILCOMPARISONFUNCTION_ALWAYS
|
||||
|
||||
STENCIL_KEEP = STENCILOPERATION_KEEP
|
||||
STENCIL_ZERO = STENCILOPERATION_ZERO
|
||||
STENCIL_REPLACE = STENCILOPERATION_REPLACE
|
||||
STENCIL_INCRSAT = STENCILOPERATION_INCRSAT
|
||||
STENCIL_DECRSAT = STENCILOPERATION_DECRSAT
|
||||
STENCIL_INVERT = STENCILOPERATION_INVERT
|
||||
STENCIL_INCR = STENCILOPERATION_INCR
|
||||
STENCIL_DECR = STENCILOPERATION_DECR
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ClearRenderTarget
|
||||
Params: <texture> <color>
|
||||
Desc: Clear a render target
|
||||
-----------------------------------------------------------]]
|
||||
function render.ClearRenderTarget( rt, color )
|
||||
|
||||
local OldRT = render.GetRenderTarget();
|
||||
render.SetRenderTarget( rt )
|
||||
render.Clear( color.r, color.g, color.b, color.a )
|
||||
render.SetRenderTarget( OldRT )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SupportsHDR
|
||||
Params:
|
||||
Desc: Return true if the client supports HDR
|
||||
-----------------------------------------------------------]]
|
||||
function render.SupportsHDR( )
|
||||
|
||||
if ( render.GetDXLevel() < 80 ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyTexture
|
||||
Params: <texture from> <texture to>
|
||||
Desc: Copy the contents of one texture to another
|
||||
-----------------------------------------------------------]]
|
||||
function render.CopyTexture( from, to )
|
||||
|
||||
local OldRT = render.GetRenderTarget();
|
||||
|
||||
render.SetRenderTarget( from )
|
||||
render.CopyRenderTargetToTexture( to )
|
||||
|
||||
render.SetRenderTarget( OldRT )
|
||||
|
||||
end
|
||||
|
||||
local matColor = Material( "color" )
|
||||
|
||||
function render.SetColorMaterial()
|
||||
render.SetMaterial( matColor )
|
||||
end
|
||||
|
||||
local matColorIgnoreZ = Material( "color_ignorez" )
|
||||
|
||||
function render.SetColorMaterialIgnoreZ()
|
||||
render.SetMaterial( matColorIgnoreZ )
|
||||
end
|
||||
|
||||
local mat_BlurX = Material( "pp/blurx" )
|
||||
local mat_BlurY = Material( "pp/blury" )
|
||||
local tex_Bloom1 = render.GetBloomTex1()
|
||||
|
||||
function render.BlurRenderTarget( rt, sizex, sizey, passes )
|
||||
|
||||
mat_BlurX:SetTexture( "$basetexture", rt )
|
||||
mat_BlurY:SetTexture( "$basetexture", tex_Bloom1 )
|
||||
mat_BlurX:SetFloat( "$size", sizex )
|
||||
mat_BlurY:SetFloat( "$size", sizey )
|
||||
|
||||
for i=1, passes+1 do
|
||||
|
||||
render.SetRenderTarget( tex_Bloom1 )
|
||||
render.SetMaterial( mat_BlurX )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
render.SetRenderTarget( rt )
|
||||
render.SetMaterial( mat_BlurY )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function cam.Start2D()
|
||||
|
||||
return cam.Start( { type = '2D' } )
|
||||
|
||||
end
|
||||
|
||||
function cam.Start3D( pos, ang, fov, x, y, w, h, znear, zfar )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = '3D';
|
||||
tab.origin = pos
|
||||
tab.angles = ang
|
||||
|
||||
if ( fov != nil ) then tab.fov = fov end
|
||||
|
||||
if ( x != nil && y != nil && w != nil && h != nil ) then
|
||||
|
||||
tab.x = x
|
||||
tab.y = y
|
||||
tab.w = w
|
||||
tab.h = h
|
||||
tab.aspect = ( w / h )
|
||||
|
||||
end
|
||||
|
||||
if ( znear != nil && zfar != nil ) then
|
||||
|
||||
tab.znear = znear
|
||||
tab.zfar = zfar
|
||||
|
||||
end
|
||||
|
||||
return cam.Start( tab )
|
||||
|
||||
end
|
||||
|
||||
local matFSB = Material( "pp/motionblur" )
|
||||
|
||||
function render.DrawTextureToScreen( tex )
|
||||
|
||||
matFSB:SetFloat( "$alpha", 1.0 )
|
||||
matFSB:SetTexture( "$basetexture", tex )
|
||||
|
||||
render.SetMaterial( matFSB )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
end
|
||||
|
||||
function render.DrawTextureToScreenRect( tex, x, y, w, h )
|
||||
|
||||
matFSB:SetFloat( "$alpha", 1.0 )
|
||||
matFSB:SetTexture( "$basetexture", tex )
|
||||
|
||||
render.SetMaterial( matFSB )
|
||||
render.DrawScreenQuadEx( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This isn't very fast. If you're doing something every frame you should find a way to
|
||||
-- cache a ClientsideModel and keep it around! This is fine for rendering to a render
|
||||
-- target once - or something.
|
||||
--
|
||||
|
||||
function render.Model( tbl, ent )
|
||||
|
||||
local inent = ent
|
||||
|
||||
if ( ent == nil ) then
|
||||
ent = ClientsideModel( tbl.model or "error.mdl", RENDERGROUP_OTHER )
|
||||
end
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetModel( tbl.model or "error.mdl" )
|
||||
ent:SetNoDraw( true )
|
||||
|
||||
ent:SetPos( tbl.pos or vector_origin )
|
||||
ent:SetAngles( tbl.angle or angle_zero )
|
||||
ent:DrawModel()
|
||||
|
||||
--
|
||||
-- If we created the model, then remove it!
|
||||
--
|
||||
if ( inent != ent ) then
|
||||
ent:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
36
lua/includes/extensions/coroutine.lua
Normal file
36
lua/includes/extensions/coroutine.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- The client needs this file
|
||||
--
|
||||
AddCSLuaFile()
|
||||
|
||||
if ( !coroutine ) then return end
|
||||
|
||||
--
|
||||
-- Name: coroutine.wait
|
||||
-- Desc: Yield's the coroutine for so many seconds before returning.\n\nThis should only be called in a coroutine. This function uses CurTime() - not RealTime().
|
||||
-- Arg1: number|seconds|The number of seconds to wait
|
||||
-- Ret1:
|
||||
--
|
||||
function coroutine.wait( seconds )
|
||||
|
||||
local endtime = CurTime() + seconds
|
||||
while ( true ) do
|
||||
|
||||
if ( endtime < CurTime() ) then return end
|
||||
|
||||
coroutine.yield()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
61
lua/includes/extensions/debug.lua
Normal file
61
lua/includes/extensions/debug.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( !debug ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Trace
|
||||
Desc: Dumps a trace to the console..
|
||||
|
||||
Trace:
|
||||
1: Line 21 "Trace" includes/extensions/debug.lua
|
||||
2: Line 222 "WriteTable" includes/modules/saverestore.lua
|
||||
3: Line 170 "WriteVar" includes/modules/saverestore.lua
|
||||
4: Line 259 "WriteTable" includes/modules/saverestore.lua
|
||||
5: Line 170 "WriteVar" includes/modules/saverestore.lua
|
||||
6: Line 259 "WriteTable" includes/modules/saverestore.lua
|
||||
7: Line 272 "Func" includes/extensions/entity_networkvars.lua
|
||||
8: Line 396 "(null)" includes/modules/saverestore.lua
|
||||
|
||||
This trace shows that the function was called from the engine (line 8) in save restore.
|
||||
Save restore then called something in entity_networkvars for some reason. Then
|
||||
that function called WriteTable(6), which called other functions until it got to the trace
|
||||
in 1 which was called by WriteTable in saverestore.lua
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function debug.Trace()
|
||||
|
||||
local level = 1
|
||||
|
||||
Msg( "\nTrace:\n" )
|
||||
|
||||
while true do
|
||||
|
||||
local info = debug.getinfo( level, "Sln" )
|
||||
if ( !info ) then break end
|
||||
|
||||
if ( info.what ) == "C" then
|
||||
|
||||
Msg( string.format( "\t%i: C function\t\"%s\"\n", level, info.name ) )
|
||||
|
||||
else
|
||||
|
||||
Msg( string.format( "\t%i: Line %d\t\"%s\"\t\t%s\n", level, info.currentline, info.name, info.short_src ) )
|
||||
|
||||
end
|
||||
|
||||
level = level + 1
|
||||
|
||||
end
|
||||
|
||||
Msg( "\n" )
|
||||
|
||||
end
|
||||
698
lua/includes/extensions/entity.lua
Normal file
698
lua/includes/extensions/entity.lua
Normal file
@@ -0,0 +1,698 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
function meta:GetShouldPlayPickupSound()
|
||||
return self.m_bPlayPickupSound or false
|
||||
end
|
||||
|
||||
function meta:SetShouldPlayPickupSound( bPlaySound )
|
||||
self.m_bPlayPickupSound = tobool( bPlaySound ) or false
|
||||
end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[ key ]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = self:GetTable()
|
||||
if ( tab ) then
|
||||
local tabval = tab[ key ]
|
||||
if ( tabval != nil ) then return tabval end
|
||||
end
|
||||
|
||||
--
|
||||
-- Legacy: sometimes use self.Owner to get the owner.. so lets carry on supporting that stupidness
|
||||
-- This needs to be retired, just like self.Entity was.
|
||||
--
|
||||
if ( key == "Owner" ) then return meta.GetOwner( self ) end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Short cut to add entities to the table
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetVar( name, default )
|
||||
|
||||
local Val = self:GetTable()[ name ]
|
||||
if ( Val == nil ) then return default end
|
||||
|
||||
return Val
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function meta:SetCreator( ply --[[= NULL]] )
|
||||
if ( ply == nil ) then
|
||||
ply = NULL
|
||||
elseif ( !isentity( ply ) ) then
|
||||
error( "bad argument #1 to 'SetCreator' (Entity expected, got " .. type( ply ) .. ")", 2 )
|
||||
end
|
||||
|
||||
self.m_PlayerCreator = ply
|
||||
end
|
||||
|
||||
function meta:GetCreator()
|
||||
return self.m_PlayerCreator or NULL
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Returns true if the entity has constraints attached to it
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsConstrained()
|
||||
|
||||
if ( CLIENT ) then return self:GetNWBool( "IsConstrained" ) end
|
||||
|
||||
local c = self:GetTable().Constraints
|
||||
local bIsConstrained = false
|
||||
|
||||
if ( c ) then
|
||||
|
||||
for k, v in pairs( c ) do
|
||||
if ( IsValid( v ) ) then bIsConstrained = true break end
|
||||
c[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:SetNWBool( "IsConstrained", bIsConstrained )
|
||||
return bIsConstrained
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Short cut to set tables on the entity table
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetVar( name, value )
|
||||
|
||||
self:GetTable()[ name ] = value
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CallOnRemove
|
||||
Desc: Call this function when this entity dies.
|
||||
Calls the function like Function( <entity>, <optional args> )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CallOnRemove( name, func, ... )
|
||||
|
||||
local mytable = self:GetTable()
|
||||
mytable.OnDieFunctions = mytable.OnDieFunctions or {}
|
||||
|
||||
mytable.OnDieFunctions[ name ] = { Name = name, Function = func, Args = { ... } }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RemoveCallOnRemove
|
||||
Desc: Removes the named hook
|
||||
-----------------------------------------------------------]]
|
||||
function meta:RemoveCallOnRemove( name )
|
||||
|
||||
local mytable = self:GetTable()
|
||||
mytable.OnDieFunctions = mytable.OnDieFunctions or {}
|
||||
mytable.OnDieFunctions[ name ] = nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Simple mechanism for calling the die functions.
|
||||
-----------------------------------------------------------]]
|
||||
local function DoDieFunction( ent )
|
||||
|
||||
if ( !ent or !ent.OnDieFunctions ) then return end
|
||||
|
||||
for k, v in pairs( ent.OnDieFunctions ) do
|
||||
|
||||
-- Functions aren't saved - so this could be nil if we loaded a game.
|
||||
if ( v && v.Function ) then
|
||||
|
||||
v.Function( ent, unpack( v.Args ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "EntityRemoved", "DoDieFunction", DoDieFunction )
|
||||
|
||||
function meta:PhysWake()
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( !IsValid( phys ) ) then return end
|
||||
|
||||
phys:Wake()
|
||||
|
||||
end
|
||||
|
||||
local GetColorOriginal4 = meta.GetColor4Part -- Do not use me! I will be removed
|
||||
local GetColorOriginal = meta.GetColor
|
||||
function meta:GetColor()
|
||||
|
||||
-- Backwards comp slower method
|
||||
if ( !GetColorOriginal4 ) then
|
||||
return GetColorOriginal( self )
|
||||
end
|
||||
|
||||
return Color( GetColorOriginal4( self ) )
|
||||
|
||||
end
|
||||
|
||||
local SetColorOriginal4 = meta.SetColor4Part -- Do not use me! I will be removed
|
||||
local SetColorOriginal = meta.SetColor
|
||||
function meta:SetColor( col )
|
||||
|
||||
-- Backwards comp slower method
|
||||
if ( !SetColorOriginal4 ) then
|
||||
return SetColorOriginal( self, col )
|
||||
end
|
||||
|
||||
-- Even more backwards compat
|
||||
if ( !col ) then
|
||||
return SetColorOriginal4( self, 255, 255, 255, 255 )
|
||||
end
|
||||
|
||||
SetColorOriginal4( self, col.r, col.g, col.b, col.a )
|
||||
|
||||
end
|
||||
|
||||
function meta:GetChildBones( bone )
|
||||
|
||||
local bonecount = self:GetBoneCount()
|
||||
if ( bonecount == 0 or bonecount < bone ) then return end
|
||||
|
||||
local bones = {}
|
||||
|
||||
for k = 0, bonecount - 1 do
|
||||
if ( self:GetBoneParent( k ) != bone ) then continue end
|
||||
table.insert( bones, k )
|
||||
end
|
||||
|
||||
return bones
|
||||
|
||||
end
|
||||
|
||||
function DTVar_ReceiveProxyGL( ent, name, id, val )
|
||||
if ( ent.CallDTVarProxies ) then
|
||||
ent:CallDTVarProxies( name, id, val )
|
||||
end
|
||||
end
|
||||
|
||||
function meta:InstallDataTable()
|
||||
|
||||
self.dt = {}
|
||||
local typetable = {}
|
||||
local datatable = {}
|
||||
local keytable = {}
|
||||
local dtmeta = {}
|
||||
local editing = {}
|
||||
|
||||
dtmeta.__index = function ( ent, key )
|
||||
|
||||
local dt = datatable[ key ]
|
||||
if ( dt == nil ) then return end
|
||||
|
||||
return dt.GetFunc( self, dt.index, key )
|
||||
|
||||
end
|
||||
|
||||
dtmeta.__newindex = function( ent, key, value )
|
||||
|
||||
local dt = datatable[ key ]
|
||||
if ( dt == nil ) then return end
|
||||
|
||||
dt.SetFunc( self, dt.index, value )
|
||||
|
||||
end
|
||||
|
||||
local function FindUnusedIndex( typename )
|
||||
|
||||
local tbl = typetable[ typename ]
|
||||
if ( !tbl ) then return 0 end
|
||||
|
||||
for i = 0, 31 do
|
||||
if ( !tbl[i] ) then return i end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.IsDTVarSlotUsed = function( ent, typename, index )
|
||||
|
||||
local tbl = typetable[ typename ]
|
||||
if ( !tbl or !tbl[index] ) then return false end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
self.DTVar = function( ent, typename, index, name )
|
||||
|
||||
if ( isstring( index ) && !name ) then
|
||||
name = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local SetFunc = ent[ "SetDT" .. typename ]
|
||||
local GetFunc = ent[ "GetDT" .. typename ]
|
||||
|
||||
if ( !SetFunc or !GetFunc ) then
|
||||
MsgN( "Couldn't addvar ", name, " - type ", typename, " is invalid!" )
|
||||
return
|
||||
end
|
||||
|
||||
local data = {
|
||||
index = index,
|
||||
name = name,
|
||||
SetFunc = SetFunc,
|
||||
GetFunc = GetFunc,
|
||||
typename = typename,
|
||||
Notify = {}
|
||||
}
|
||||
|
||||
typetable[ typename ] = typetable[ typename ] or {}
|
||||
typetable[ typename ][ index ] = data
|
||||
datatable[ name ] = data
|
||||
|
||||
return data
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Access to the editing table
|
||||
--
|
||||
self.GetEditingData = function()
|
||||
return editing
|
||||
end
|
||||
|
||||
--
|
||||
-- Adds an editable variable.
|
||||
--
|
||||
self.SetupEditing = function( ent, name, keyname, data )
|
||||
|
||||
if ( !data ) then return end
|
||||
|
||||
if ( !data.title ) then data.title = name end
|
||||
|
||||
editing[ keyname ] = data
|
||||
|
||||
end
|
||||
|
||||
self.SetupKeyValue = function( ent, keyname, kvtype, setfunc, getfunc, other_data )
|
||||
|
||||
keyname = keyname:lower()
|
||||
|
||||
keytable[ keyname ] = {
|
||||
KeyName = keyname,
|
||||
Set = setfunc,
|
||||
Get = getfunc,
|
||||
Type = kvtype
|
||||
}
|
||||
|
||||
if ( other_data ) then
|
||||
|
||||
table.Merge( keytable[ keyname ], other_data )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local CallProxies = function( ent, tbl, name, oldval, newval )
|
||||
|
||||
for i = 1, #tbl do
|
||||
tbl[ i ]( ent, name, oldval, newval )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.CallDTVarProxies = function( ent, typename, index, newVal )
|
||||
|
||||
local t = typetable[ typename ] && typetable[ typename ][ index ] or nil
|
||||
if ( t ) then
|
||||
CallProxies( ent, t.Notify, t.name, t.GetFunc( ent, index ), newVal )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.NetworkVar = function( ent, typename, index, name, other_data )
|
||||
|
||||
if ( isstring( index ) && ( istable( name ) or !name ) ) then
|
||||
other_data = name
|
||||
name = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local t = ent.DTVar( ent, typename, index, name )
|
||||
|
||||
-- Some addons call these on the entity table, and that used to work, so we keep that
|
||||
ent[ "Set" .. name ] = function( selfent, value )
|
||||
CallProxies( ent, t.Notify, name, t.GetFunc( ent, index ), value )
|
||||
t.SetFunc( ent, index, value )
|
||||
end
|
||||
|
||||
ent[ "Get" .. name ] = function( selfent )
|
||||
return t.GetFunc( ent, index )
|
||||
end
|
||||
|
||||
if ( !other_data ) then return end
|
||||
|
||||
-- This KeyName stuff is absolutely unnecessary, there's absolutely no reason for it to exist
|
||||
-- But we cannot remove it now because dupes will break. It should've used the "name" variable
|
||||
if ( other_data.KeyName ) then
|
||||
ent:SetupKeyValue( other_data.KeyName, typename, ent[ "Set" .. name ], ent[ "Get" .. name ], other_data )
|
||||
ent:SetupEditing( name, other_data.KeyName, other_data.Edit )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a function that gets called when the variable changes
|
||||
-- Note: this doesn't work on the client yet - which drastically reduces its usefulness.
|
||||
--
|
||||
self.NetworkVarNotify = function( ent, name, func )
|
||||
|
||||
if ( !datatable[ name ] ) then error( "calling NetworkVarNotify on missing network var " .. name ) end
|
||||
|
||||
table.insert( datatable[ name ].Notify, func )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Create an accessor of an element. This is mainly so you can use spare
|
||||
-- network vars (vectors, angles) to network single floats.
|
||||
--
|
||||
self.NetworkVarElement = function( ent, typename, index, element, name, other_data )
|
||||
|
||||
if ( isstring( index ) && isstring( element ) ) then
|
||||
other_data = name
|
||||
name = element
|
||||
element = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local t = ent.DTVar( ent, typename, index, name )
|
||||
t.element = element
|
||||
|
||||
ent[ "Set" .. name ] = function( selfent, value )
|
||||
local old = t.GetFunc( selfent, index )
|
||||
old[ element ] = value
|
||||
t.SetFunc( selfent, index, old )
|
||||
end
|
||||
|
||||
ent[ "Get" .. name ] = function( selfent )
|
||||
return t.GetFunc( selfent, index )[ element ]
|
||||
end
|
||||
|
||||
if ( !other_data ) then return end
|
||||
|
||||
-- This KeyName stuff is absolutely unnecessary, there's absolutely no reason for it to exist
|
||||
-- But we cannot remove it now because dupes will break. It should've used the "name" variable
|
||||
if ( other_data.KeyName ) then
|
||||
ent:SetupKeyValue( other_data.KeyName, "float", ent[ "Set" .. name ], ent[ "Get" .. name ], other_data )
|
||||
ent:SetupEditing( name, other_data.KeyName, other_data.Edit )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.SetNetworkKeyValue = function( ent, key, value )
|
||||
|
||||
key = key:lower()
|
||||
|
||||
local k = keytable[ key ]
|
||||
if ( !k ) then return end
|
||||
|
||||
local v = util.StringToType( value, k.Type )
|
||||
if ( v == nil ) then return end
|
||||
|
||||
k.Set( ent, v )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
self.GetNetworkKeyValue = function( ent, key )
|
||||
|
||||
key = key:lower()
|
||||
|
||||
local k = keytable[ key ]
|
||||
if ( !k ) then return end
|
||||
|
||||
return k.Get( ent )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the duplicator system to get the network vars
|
||||
--
|
||||
self.GetNetworkVars = function( ent )
|
||||
|
||||
local dt = {}
|
||||
|
||||
for k, v in pairs( datatable ) do
|
||||
|
||||
-- Don't try to save entities (yet?)
|
||||
if ( v.typename == "Entity" ) then continue end
|
||||
|
||||
if ( v.element ) then
|
||||
dt[ k ] = v.GetFunc( ent, v.index )[ v.element ]
|
||||
else
|
||||
dt[ k ] = v.GetFunc( ent, v.index )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If there's nothing in our table - then return nil.
|
||||
--
|
||||
if ( table.IsEmpty( dt ) ) then return nil end
|
||||
|
||||
return dt
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the duplicator system to restore from network vars
|
||||
--
|
||||
self.RestoreNetworkVars = function( ent, tab )
|
||||
|
||||
if ( !tab ) then return end
|
||||
|
||||
-- Loop this entities data table
|
||||
for k, v in pairs( datatable ) do
|
||||
|
||||
-- If it contains this entry
|
||||
if ( tab[ k ] == nil ) then continue end
|
||||
|
||||
-- Support old saves/dupes with incorrectly saved data
|
||||
if ( v.element && ( isangle( tab[ k ] ) or isvector( tab[ k ] ) ) ) then
|
||||
tab[ k ] = tab[ k ][ v.element ]
|
||||
end
|
||||
|
||||
-- Set it.
|
||||
if ( ent[ "Set" .. k ] ) then
|
||||
ent[ "Set" .. k ]( ent, tab[ k ] )
|
||||
else
|
||||
v.SetFunc( ent, v.index, tab[ k ] )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
setmetatable( self.dt, dtmeta )
|
||||
|
||||
--
|
||||
-- In sandbox the client can edit certain values on certain entities
|
||||
-- we implement this here incase any other gamemodes want to use it
|
||||
-- although it is of course deactivated by default.
|
||||
--
|
||||
|
||||
--
|
||||
-- This function takes a keyname and a value - both strings.
|
||||
--
|
||||
--
|
||||
-- Called serverside it will set the value.
|
||||
--
|
||||
self.EditValue = function( ent, variable, value )
|
||||
|
||||
if ( !isstring( variable ) ) then return end
|
||||
if ( !isstring( value ) ) then return end
|
||||
|
||||
--
|
||||
-- It can be called clientside to send a message to the server
|
||||
-- to request a change of value.
|
||||
--
|
||||
if ( CLIENT ) then
|
||||
|
||||
net.Start( "editvariable" )
|
||||
net.WriteEntity( ent )
|
||||
net.WriteString( variable )
|
||||
net.WriteString( value )
|
||||
net.SendToServer()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called serverside it simply changes the value
|
||||
--
|
||||
if ( SERVER ) then
|
||||
|
||||
ent:SetNetworkKeyValue( variable, value )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
util.AddNetworkString( "editvariable" )
|
||||
|
||||
net.Receive( "editvariable", function( len, client )
|
||||
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
if ( !isfunction( ent.GetEditingData ) ) then return end
|
||||
if ( ent.AdminOnly && !( client:IsAdmin() or game.SinglePlayer() ) ) then return end
|
||||
|
||||
local key = net.ReadString()
|
||||
|
||||
-- Is this key in our edit table?
|
||||
local editor = ent:GetEditingData()[ key ]
|
||||
if ( !istable( editor ) ) then return end
|
||||
|
||||
local val = net.ReadString()
|
||||
hook.Run( "VariableEdited", ent, client, key, val, editor )
|
||||
|
||||
end )
|
||||
|
||||
function meta:GetUnFreezable()
|
||||
return self.m_bUnFreezable or false
|
||||
end
|
||||
|
||||
function meta:SetUnFreezable( bFreeze )
|
||||
self.m_bUnFreezable = tobool( bFreeze ) or false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Networked var proxies
|
||||
--
|
||||
function meta:SetNetworked2VarProxy( name, func )
|
||||
|
||||
if ( !self.NWVarProxies ) then
|
||||
self.NWVarProxies = {}
|
||||
end
|
||||
|
||||
self.NWVarProxies[ name ] = func
|
||||
|
||||
end
|
||||
|
||||
function meta:GetNetworked2VarProxy( name )
|
||||
|
||||
if ( self.NWVarProxies ) then
|
||||
local func = self.NWVarProxies[ name ]
|
||||
if ( isfunction( func ) ) then
|
||||
return func
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
meta.SetNW2VarProxy = meta.SetNetworked2VarProxy
|
||||
meta.GetNW2VarProxy = meta.GetNetworked2VarProxy
|
||||
|
||||
hook.Add( "EntityNetworkedVarChanged", "NetworkedVars", function( ent, name, oldValue, newValue )
|
||||
|
||||
if ( ent.NWVarProxies ) then
|
||||
local func = ent.NWVarProxies[ name ]
|
||||
|
||||
if ( isfunction( func ) ) then
|
||||
func( ent, name, oldValue, newValue )
|
||||
end
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Vehicle Extensions
|
||||
--
|
||||
local vehicle = FindMetaTable( "Vehicle" )
|
||||
|
||||
--
|
||||
-- We steal some DT slots by default for vehicles
|
||||
-- to control the third person view. You should use
|
||||
-- these functions if you want to play with them because
|
||||
-- they might eventually be moved into the engine - so manually
|
||||
-- editing the DT values will stop working.
|
||||
--
|
||||
function vehicle:SetVehicleClass( s )
|
||||
|
||||
self:SetDTString( 3, s )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetVehicleClass()
|
||||
|
||||
return self:GetDTString( 3 )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:SetThirdPersonMode( b )
|
||||
|
||||
self:SetDTBool( 3, b )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetThirdPersonMode()
|
||||
|
||||
return self:GetDTBool( 3 )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:SetCameraDistance( dist )
|
||||
|
||||
self:SetDTFloat( 3, dist )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetCameraDistance()
|
||||
|
||||
return self:GetDTFloat( 3 )
|
||||
|
||||
end
|
||||
58
lua/includes/extensions/ents.lua
Normal file
58
lua/includes/extensions/ents.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function ents.FindByClassAndParent( classname, entity )
|
||||
|
||||
if ( !IsValid( entity ) ) then return end
|
||||
|
||||
local list = ents.FindByClass( classname )
|
||||
if ( !list ) then return end
|
||||
|
||||
local out = {}
|
||||
for k, v in ipairs( list ) do
|
||||
|
||||
if ( !IsValid(v) ) then continue end
|
||||
|
||||
local p = v:GetParent()
|
||||
if ( !IsValid(p) ) then continue end
|
||||
if ( p != entity ) then continue end
|
||||
|
||||
table.insert( out, v )
|
||||
|
||||
end
|
||||
|
||||
if ( #out == 0 ) then return end
|
||||
|
||||
return out
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
local inext = ipairs({})
|
||||
local EntityCache = nil
|
||||
|
||||
function ents.Iterator()
|
||||
|
||||
if ( EntityCache == nil ) then EntityCache = ents.GetAll() end
|
||||
|
||||
return inext, EntityCache, 0
|
||||
|
||||
end
|
||||
|
||||
local function InvalidateEntityCache( ent )
|
||||
|
||||
EntityCache = nil
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "OnEntityCreated", "ents.Iterator", InvalidateEntityCache )
|
||||
hook.Add( "EntityRemoved", "ents.Iterator", InvalidateEntityCache )
|
||||
49
lua/includes/extensions/file.lua
Normal file
49
lua/includes/extensions/file.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
function file.Read( filename, path )
|
||||
|
||||
if ( path == true ) then path = "GAME" end
|
||||
if ( path == nil || path == false ) then path = "DATA" end
|
||||
|
||||
local f = file.Open( filename, "rb", path )
|
||||
if ( !f ) then return end
|
||||
|
||||
local str = f:Read( f:Size() )
|
||||
|
||||
f:Close()
|
||||
|
||||
if ( !str ) then str = "" end
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
function file.Write( filename, contents )
|
||||
|
||||
local f = file.Open( filename, "wb", "DATA" )
|
||||
if ( !f ) then return end
|
||||
|
||||
f:Write( contents )
|
||||
f:Close()
|
||||
|
||||
end
|
||||
|
||||
function file.Append( filename, contents )
|
||||
|
||||
local f = file.Open( filename, "ab", "DATA" )
|
||||
if ( !f ) then return end
|
||||
|
||||
f:Write( contents )
|
||||
f:Close()
|
||||
|
||||
end
|
||||
64
lua/includes/extensions/game.lua
Normal file
64
lua/includes/extensions/game.lua
Normal file
@@ -0,0 +1,64 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local AmmoTypes = {}
|
||||
|
||||
--
|
||||
-- Called by modders to add a new ammo type.
|
||||
-- Ammo types aren't something you can add on the fly. You have one
|
||||
-- opportunity during loadtime. The ammo types should also be IDENTICAL on
|
||||
-- server and client.
|
||||
-- If they're not you will receive errors and maybe even crashes.
|
||||
--
|
||||
--
|
||||
-- game.AddAmmoType(
|
||||
-- {
|
||||
-- name = "customammo",
|
||||
-- dmgtype = DMG_BULLET,
|
||||
-- tracer = TRACER_LINE_AND_WHIZ,
|
||||
-- plydmg = 20,
|
||||
-- npcdmg = 20,
|
||||
-- force = 100,
|
||||
-- minsplash = 10,
|
||||
-- maxsplash = 100
|
||||
-- })
|
||||
--
|
||||
function game.AddAmmoType( tbl )
|
||||
if ( !isstring( tbl.name ) ) then
|
||||
ErrorNoHalt( "bad argument #1 to 'AddAmmoType' ('name' key expected a string, got " .. type( tbl.name ) .. ")\n" )
|
||||
return
|
||||
end
|
||||
|
||||
local name = string.lower( tbl.name )
|
||||
|
||||
for id, ammo in ipairs( AmmoTypes ) do
|
||||
if ( name == string.lower( ammo.name ) ) then
|
||||
AmmoTypes[ id ] = tbl
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( AmmoTypes, tbl )
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the engine to retrive the ammo types.
|
||||
-- You should never have to call this manually.
|
||||
--
|
||||
function game.BuildAmmoTypes()
|
||||
--
|
||||
-- Sort the table by name here to assure that the ammo types
|
||||
-- are inserted in the same order on both server and client
|
||||
--
|
||||
table.SortByMember( AmmoTypes, "name", true )
|
||||
|
||||
return AmmoTypes
|
||||
end
|
||||
310
lua/includes/extensions/math.lua
Normal file
310
lua/includes/extensions/math.lua
Normal file
@@ -0,0 +1,310 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "math/ease.lua" )
|
||||
|
||||
math.tau = 2 * math.pi
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DistanceSqr( low, high )
|
||||
Desc: Squared Distance between two 2d points, use this instead of math.Distance as it is more cpu efficient.
|
||||
------------------------------------------------------------]]
|
||||
function math.DistanceSqr( x1, y1, x2, y2 )
|
||||
local xd = x2 - x1
|
||||
local yd = y2 - y1
|
||||
return xd * xd + yd * yd
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Distance( low, high )
|
||||
Desc: Distance between two 2d points
|
||||
------------------------------------------------------------]]
|
||||
function math.Distance( x1, y1, x2, y2 )
|
||||
local xd = x2 - x1
|
||||
local yd = y2 - y1
|
||||
return math.sqrt( xd * xd + yd * yd )
|
||||
end
|
||||
math.Dist = math.Distance -- Backwards compatibility
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: BinToInt( bin )
|
||||
Desc: Convert a binary string to an integer number
|
||||
------------------------------------------------------------]]
|
||||
function math.BinToInt( bin )
|
||||
return tonumber( bin, 2 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IntToBin( int )
|
||||
Desc: Convert an integer number to a binary string (the string len will be a multiple of three)
|
||||
------------------------------------------------------------]]
|
||||
local intbin = {
|
||||
["0"] = "000", ["1"] = "001", ["2"] = "010", ["3"] = "011",
|
||||
["4"] = "100", ["5"] = "101", ["6"] = "110", ["7"] = "111"
|
||||
}
|
||||
|
||||
function math.IntToBin( int )
|
||||
local str = string.gsub( string.format( "%o", int ), "(.)", function ( d ) return intbin[ d ] end )
|
||||
return str
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Clamp( in, low, high )
|
||||
Desc: Clamp value between 2 values
|
||||
------------------------------------------------------------]]
|
||||
function math.Clamp( _in, low, high )
|
||||
return math.min( math.max( _in, low ), high )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Rand( low, high )
|
||||
Desc: Random number between low and high
|
||||
-----------------------------------------------------------]]
|
||||
function math.Rand( low, high )
|
||||
return low + ( high - low ) * math.random()
|
||||
end
|
||||
|
||||
math.Max = math.max
|
||||
math.Min = math.min
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: EaseInOut(fProgress, fEaseIn, fEaseOut)
|
||||
Desc: Provided by garry from the facewound source and converted
|
||||
to Lua by me :p
|
||||
Usage: math.EaseInOut(0.1, 0.5, 0.5) - all parameters should be between 0 and 1
|
||||
-----------------------------------------------------------]]
|
||||
function math.EaseInOut( fProgress, fEaseIn, fEaseOut )
|
||||
|
||||
if ( fEaseIn == nil ) then fEaseIn = 0 end
|
||||
if ( fEaseOut == nil ) then fEaseOut = 1 end
|
||||
|
||||
if ( fProgress == 0 or fProgress == 1 ) then return fProgress end
|
||||
|
||||
local fSumEase = fEaseIn + fEaseOut
|
||||
|
||||
if ( fSumEase == 0 ) then return fProgress end
|
||||
if ( fSumEase > 1 ) then
|
||||
fEaseIn = fEaseIn / fSumEase
|
||||
fEaseOut = fEaseOut / fSumEase
|
||||
end
|
||||
|
||||
local fProgressCalc = 1 / ( 2 - fEaseIn - fEaseOut )
|
||||
|
||||
if ( fProgress < fEaseIn ) then
|
||||
return ( ( fProgressCalc / fEaseIn ) * fProgress * fProgress )
|
||||
elseif ( fProgress < 1 - fEaseOut ) then
|
||||
return ( fProgressCalc * ( 2 * fProgress - fEaseIn ) )
|
||||
else
|
||||
fProgress = 1 - fProgress
|
||||
return ( 1 - ( fProgressCalc / fEaseOut ) * fProgress * fProgress )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function KNOT( i, tinc ) return ( i - 3 ) * tinc end
|
||||
|
||||
function math.calcBSplineN( i, k, t, tinc )
|
||||
|
||||
if ( k == 1 ) then
|
||||
|
||||
if ( ( KNOT( i, tinc ) <= t ) and ( t < KNOT( i + 1, tinc ) ) ) then
|
||||
|
||||
return 1
|
||||
|
||||
else
|
||||
|
||||
return 0
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local ft = ( t - KNOT( i, tinc ) ) * math.calcBSplineN( i, k - 1, t, tinc )
|
||||
local fb = KNOT( i + k - 1, tinc ) - KNOT( i, tinc )
|
||||
|
||||
local st = ( KNOT( i + k, tinc ) - t ) * math.calcBSplineN( i + 1, k - 1, t, tinc )
|
||||
local sb = KNOT( i + k, tinc ) - KNOT( i + 1, tinc )
|
||||
|
||||
local first = 0
|
||||
local second = 0
|
||||
|
||||
if ( fb > 0 ) then
|
||||
|
||||
first = ft / fb
|
||||
|
||||
end
|
||||
if ( sb > 0 ) then
|
||||
|
||||
second = st / sb
|
||||
|
||||
end
|
||||
|
||||
return first + second
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function math.BSplinePoint( tDiff, tPoints, tMax )
|
||||
|
||||
local Q = Vector( 0, 0, 0 )
|
||||
local tinc = tMax / ( #tPoints - 3 )
|
||||
|
||||
tDiff = tDiff + tinc
|
||||
|
||||
for idx, pt in pairs( tPoints ) do
|
||||
|
||||
local n = math.calcBSplineN( idx, 4, tDiff, tinc )
|
||||
Q = Q + ( n * pt )
|
||||
|
||||
end
|
||||
|
||||
return Q
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Cubic hermite spline
|
||||
p0, p1 - points; m0, m1 - tangets; t - fraction along the curve (0-1)
|
||||
-----------------------------------------------------------]]
|
||||
function math.CHSpline( t, p0, m0, p1, m1 )
|
||||
|
||||
if ( t >= 1 ) then return p1 end
|
||||
if ( t <= 0 ) then return p0 end
|
||||
|
||||
local t2 = t * t
|
||||
local t3 = t * t2
|
||||
|
||||
return p0 * ( 2 * t3 - 3 * t2 + 1 ) +
|
||||
m0 * ( t3 - 2 * t2 + t ) +
|
||||
p1 * ( -2 * t3 + 3 * t2 ) +
|
||||
m1 * ( t3 - t2 )
|
||||
|
||||
end
|
||||
|
||||
-- Round to the nearest integer
|
||||
function math.Round( num, idp )
|
||||
|
||||
local mult = 10 ^ ( idp or 0 )
|
||||
return math.floor( num * mult + 0.5 ) / mult
|
||||
|
||||
end
|
||||
|
||||
-- Rounds towards zero
|
||||
function math.Truncate( num, idp )
|
||||
|
||||
local mult = 10 ^ ( idp or 0 )
|
||||
local FloorOrCeil = num < 0 and math.ceil or math.floor
|
||||
|
||||
return FloorOrCeil( num * mult ) / mult
|
||||
|
||||
end
|
||||
|
||||
function math.Approach( cur, target, inc )
|
||||
|
||||
inc = math.abs( inc )
|
||||
|
||||
if ( cur < target ) then
|
||||
|
||||
return math.min( cur + inc, target )
|
||||
|
||||
elseif ( cur > target ) then
|
||||
|
||||
return math.max( cur - inc, target )
|
||||
|
||||
end
|
||||
|
||||
return target
|
||||
|
||||
end
|
||||
|
||||
function math.NormalizeAngle( a )
|
||||
return ( a + 180 ) % 360 - 180
|
||||
end
|
||||
|
||||
function math.AngleDifference( a, b )
|
||||
|
||||
local diff = math.NormalizeAngle( a - b )
|
||||
|
||||
if ( diff < 180 ) then
|
||||
return diff
|
||||
end
|
||||
|
||||
return diff - 360
|
||||
|
||||
end
|
||||
|
||||
function math.ApproachAngle( cur, target, inc )
|
||||
|
||||
local diff = math.AngleDifference( target, cur )
|
||||
|
||||
return math.Approach( cur, cur + diff, inc )
|
||||
|
||||
end
|
||||
|
||||
function math.TimeFraction( Start, End, Current )
|
||||
return ( Current - Start ) / ( End - Start )
|
||||
end
|
||||
|
||||
function math.Remap( value, inMin, inMax, outMin, outMax )
|
||||
return outMin + ( ( ( value - inMin ) / ( inMax - inMin ) ) * ( outMax - outMin ) )
|
||||
end
|
||||
|
||||
-- Snaps the provided number to the nearest multiple
|
||||
function math.SnapTo( num, multiple )
|
||||
return math.floor( num / multiple + 0.5 ) * multiple
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CubicBezier( frac, p0, p1, p2, p3 )
|
||||
Desc: Lerp point between points with cubic bezier
|
||||
-----------------------------------------------------------]]
|
||||
function math.CubicBezier( frac, p0, p1, p2, p3 )
|
||||
local frac2 = frac * frac
|
||||
local inv = 1 - frac
|
||||
local inv2 = inv * inv
|
||||
|
||||
return inv2 * inv * p0 + 3 * inv2 * frac * p1 + 3 * inv * frac2 * p2 + frac2 * frac * p3
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: QuadraticBezier( frac, p0, p1, p2 )
|
||||
Desc: Lerp point between points with quadratic bezier
|
||||
-----------------------------------------------------------]]
|
||||
function math.QuadraticBezier( frac, p0, p1, p2 )
|
||||
local frac2 = frac * frac
|
||||
local inv = 1 - frac
|
||||
local inv2 = inv * inv
|
||||
|
||||
return inv2 * p0 + 2 * inv * frac * p1 + frac2 * p2
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Factorial( num )
|
||||
Desc: Calculate the factorial value of num
|
||||
-----------------------------------------------------------]]
|
||||
function math.Factorial( num )
|
||||
|
||||
if ( num < 0 ) then
|
||||
return nil
|
||||
elseif ( num < 2 ) then
|
||||
return 1
|
||||
end
|
||||
|
||||
local res = 1
|
||||
|
||||
for i = 2, num do
|
||||
res = res * i
|
||||
end
|
||||
|
||||
return res
|
||||
|
||||
end
|
||||
201
lua/includes/extensions/math/ease.lua
Normal file
201
lua/includes/extensions/math/ease.lua
Normal file
@@ -0,0 +1,201 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
module("math.ease", package.seeall)
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Source code of functions
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
-- https://github.com/Facepunch/garrysmod/pull/1755
|
||||
-- https://web.archive.org/web/20201212082306/https://easings.net/
|
||||
-- https://web.archive.org/web/20201218211606/https://raw.githubusercontent.com/ai/easings.net/master/src/easings.yml
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Easing constants
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
local c1 = 1.70158
|
||||
local c3 = c1 + 1
|
||||
local c2 = c1 * 1.525
|
||||
local c4 = ( 2 * math.pi ) / 3
|
||||
local c5 = ( 2 * math.pi ) / 4.5
|
||||
local n1 = 7.5625
|
||||
local d1 = 2.75
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
To reduce _G lookups, we'll localize some commonly
|
||||
used functions in this extension
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
local pi = math.pi
|
||||
local cos = math.cos
|
||||
local sin = math.sin
|
||||
local sqrt = math.sqrt
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Easing functions
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
function InSine( x )
|
||||
return 1 - cos( ( x * pi ) / 2 )
|
||||
end
|
||||
|
||||
function OutSine( x )
|
||||
return sin( ( x * pi ) / 2 )
|
||||
end
|
||||
|
||||
function InOutSine( x )
|
||||
return -( cos( pi * x ) - 1 ) / 2
|
||||
end
|
||||
|
||||
function InQuad( x )
|
||||
return x ^ 2
|
||||
end
|
||||
|
||||
function OutQuad( x )
|
||||
return 1 - ( 1 - x ) * ( 1 - x )
|
||||
end
|
||||
|
||||
function InOutQuad( x )
|
||||
return x < 0.5 && 2 * x ^ 2 || 1 - ( ( -2 * x + 2 ) ^ 2 ) / 2
|
||||
end
|
||||
|
||||
function InCubic( x )
|
||||
return x ^ 3
|
||||
end
|
||||
|
||||
function OutCubic( x )
|
||||
return 1 - ( ( 1 - x ) ^ 3 )
|
||||
end
|
||||
|
||||
function InOutCubic( x )
|
||||
return x < 0.5 && 4 * x ^ 3 || 1 - ( ( -2 * x + 2 ) ^ 3 ) / 2
|
||||
end
|
||||
|
||||
function InQuart( x )
|
||||
return x ^ 4
|
||||
end
|
||||
|
||||
function OutQuart( x )
|
||||
return 1 - ( ( 1 - x ) ^ 4 )
|
||||
end
|
||||
|
||||
function InOutQuart( x )
|
||||
return x < 0.5 && 8 * x ^ 4 || 1 - ( ( -2 * x + 2 ) ^ 4 ) / 2
|
||||
end
|
||||
|
||||
function InQuint( x )
|
||||
return x ^ 5
|
||||
end
|
||||
|
||||
function OutQuint( x )
|
||||
return 1 - ( ( 1 - x ) ^ 5 )
|
||||
end
|
||||
|
||||
function InOutQuint( x )
|
||||
return x < 0.5 && 16 * x ^ 5 || 1 - ( ( -2 * x + 2 ) ^ 5 ) / 2
|
||||
end
|
||||
|
||||
function InExpo( x )
|
||||
return x == 0 && 0 || ( 2 ^ ( 10 * x - 10 ) )
|
||||
end
|
||||
|
||||
function OutExpo( x )
|
||||
return x == 1 && 1 || 1 - ( 2 ^ ( -10 * x ) )
|
||||
end
|
||||
|
||||
function InOutExpo( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| x < 0.5 && ( 2 ^ ( 20 * x - 10 ) ) / 2
|
||||
|| ( 2 - ( 2 ^ ( -20 * x + 10 ) ) ) / 2
|
||||
end
|
||||
|
||||
function InCirc( x )
|
||||
return 1 - sqrt( 1 - ( x ^ 2 ) )
|
||||
end
|
||||
|
||||
function OutCirc( x )
|
||||
return sqrt( 1 - ( ( x - 1 ) ^ 2 ) )
|
||||
end
|
||||
|
||||
function InOutCirc( x )
|
||||
return x < 0.5
|
||||
&& ( 1 - sqrt( 1 - ( ( 2 * x ) ^ 2 ) ) ) / 2
|
||||
|| ( sqrt( 1 - ( ( -2 * x + 2 ) ^ 2 ) ) + 1 ) / 2
|
||||
end
|
||||
|
||||
function InBack( x )
|
||||
return c3 * x ^ 3 - c1 * x ^ 2
|
||||
end
|
||||
|
||||
function OutBack( x )
|
||||
return 1 + c3 * ( ( x - 1 ) ^ 3 ) + c1 * ( ( x - 1 ) ^ 2 )
|
||||
end
|
||||
|
||||
function InOutBack( x )
|
||||
return x < 0.5
|
||||
&& ( ( ( 2 * x ) ^ 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2
|
||||
|| ( ( ( 2 * x - 2 ) ^ 2 ) * ( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2
|
||||
end
|
||||
|
||||
function InElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| -( 2 ^ ( 10 * x - 10 ) ) * sin( ( x * 10 - 10.75 ) * c4 )
|
||||
end
|
||||
|
||||
function OutElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| ( 2 ^ ( -10 * x ) ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1
|
||||
end
|
||||
|
||||
function InOutElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| x < 0.5
|
||||
&& -( ( 2 ^ ( 20 * x - 10 ) ) * sin( ( 20 * x - 11.125 ) * c5 ) ) / 2
|
||||
|| ( ( 2 ^ ( -20 * x + 10 ) ) * sin( ( 20 * x - 11.125 ) * c5 ) ) / 2 + 1
|
||||
end
|
||||
|
||||
function InBounce( x )
|
||||
return 1 - OutBounce( 1 - x )
|
||||
end
|
||||
|
||||
function OutBounce( x )
|
||||
if ( x < 1 / d1 ) then
|
||||
return n1 * x ^ 2
|
||||
elseif ( x < 2 / d1 ) then
|
||||
x = x - ( 1.5 / d1 )
|
||||
return n1 * x ^ 2 + 0.75
|
||||
elseif ( x < 2.5 / d1 ) then
|
||||
x = x - ( 2.25 / d1 )
|
||||
return n1 * x ^ 2 + 0.9375
|
||||
else
|
||||
x = x - ( 2.625 / d1 )
|
||||
return n1 * x ^ 2 + 0.984375
|
||||
end
|
||||
end
|
||||
|
||||
function InOutBounce( x )
|
||||
return x < 0.5
|
||||
&& ( 1 - OutBounce( 1 - 2 * x ) ) / 2
|
||||
|| ( 1 + OutBounce( 2 * x - 1 ) ) / 2
|
||||
end
|
||||
268
lua/includes/extensions/motionsensor.lua
Normal file
268
lua/includes/extensions/motionsensor.lua
Normal file
@@ -0,0 +1,268 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Should never really happen.
|
||||
--
|
||||
motionsensor = motionsensor or {}
|
||||
|
||||
|
||||
--
|
||||
-- These bones are used to draw the debug
|
||||
-- kinect skeleton. You just need to loop through
|
||||
-- and draw a line between each of these bones.
|
||||
--
|
||||
motionsensor.DebugBones =
|
||||
{
|
||||
-- Torso
|
||||
{ SENSORBONE.HEAD, SENSORBONE.SHOULDER },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SHOULDER_LEFT },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SHOULDER_RIGHT },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SPINE },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.HIP },
|
||||
{ SENSORBONE.HIP, SENSORBONE.HIP_LEFT },
|
||||
{ SENSORBONE.HIP, SENSORBONE.HIP_RIGHT },
|
||||
|
||||
-- Left Arm
|
||||
{ SENSORBONE.SHOULDER_LEFT, SENSORBONE.ELBOW_LEFT },
|
||||
{ SENSORBONE.ELBOW_LEFT, SENSORBONE.WRIST_LEFT },
|
||||
{ SENSORBONE.WRIST_LEFT, SENSORBONE.HAND_LEFT },
|
||||
|
||||
-- Right Arm
|
||||
{ SENSORBONE.SHOULDER_RIGHT, SENSORBONE.ELBOW_RIGHT },
|
||||
{ SENSORBONE.ELBOW_RIGHT, SENSORBONE.WRIST_RIGHT },
|
||||
{ SENSORBONE.WRIST_RIGHT, SENSORBONE.HAND_RIGHT },
|
||||
|
||||
-- left leg
|
||||
{ SENSORBONE.HIP_LEFT, SENSORBONE.KNEE_LEFT },
|
||||
{ SENSORBONE.KNEE_LEFT, SENSORBONE.ANKLE_LEFT },
|
||||
{ SENSORBONE.ANKLE_LEFT, SENSORBONE.FOOT_LEFT },
|
||||
|
||||
-- right leg
|
||||
{ SENSORBONE.HIP_RIGHT, SENSORBONE.KNEE_RIGHT },
|
||||
{ SENSORBONE.KNEE_RIGHT, SENSORBONE.ANKLE_RIGHT },
|
||||
{ SENSORBONE.ANKLE_RIGHT, SENSORBONE.FOOT_RIGHT },
|
||||
}
|
||||
|
||||
motionsensor.ChooseBuilderFromEntity = function( ent )
|
||||
|
||||
local builders = list.Get( "SkeletonConvertor" )
|
||||
|
||||
for k, v in pairs( builders ) do
|
||||
|
||||
if ( v:IsApplicable( ent ) ) then return k end
|
||||
|
||||
end
|
||||
|
||||
return "ValveBiped"
|
||||
|
||||
end
|
||||
|
||||
motionsensor.ProcessAngle = function( translator, sensor, pos, ang, special_vectors, boneid, v )
|
||||
|
||||
local a = nil
|
||||
local b = nil
|
||||
local up = special_vectors["up"]
|
||||
|
||||
--
|
||||
-- Using a vector from another angle.
|
||||
-- If the angle isn't processed yet return
|
||||
-- we will be added to the list to process again.
|
||||
--
|
||||
if ( v.up_up ) then
|
||||
if ( !ang[ v.up_up ] ) then return end
|
||||
up = ang[ v.up_up ]:Up()
|
||||
end
|
||||
|
||||
if ( v.up_dn ) then
|
||||
if ( !ang[ v.up_dn ] ) then return end
|
||||
up = ang[ v.up_dn ]:Up() * -1
|
||||
end
|
||||
|
||||
if ( v.up_fwd ) then
|
||||
if ( !ang[ v.up_fwd ] ) then return end
|
||||
up = ang[ v.up_fwd ]:Forward()
|
||||
end
|
||||
|
||||
if ( v.up_lft ) then
|
||||
if ( !ang[ v.up_lft ] ) then return end
|
||||
up = ang[ v.up_lft ]:Right() * -1
|
||||
end
|
||||
|
||||
if ( v.up_rgt ) then
|
||||
if ( !ang[ v.up_rgt ] ) then return end
|
||||
up = ang[ v.up_rgt ]:Right()
|
||||
end
|
||||
|
||||
--
|
||||
-- From -> To vectors
|
||||
--
|
||||
if ( v.from_sensor ) then a = sensor[ v.from_sensor ] end
|
||||
if ( v.to_sensor ) then b = sensor[ v.to_sensor ] end
|
||||
if ( v.from ) then a = pos[ v.from ] end
|
||||
if ( v.to ) then b = pos[ v.to ] end
|
||||
|
||||
--
|
||||
-- We can offer special vectors to define 'up'
|
||||
--
|
||||
if ( isstring( v.up ) ) then
|
||||
up = special_vectors[ v.up ]
|
||||
end
|
||||
|
||||
if ( a == nil or b == nil or up == nil ) then return end
|
||||
|
||||
ang[ boneid ] = ( a - b ):GetNormal():AngleEx( up:GetNormal() );
|
||||
|
||||
if ( v.adjust ) then
|
||||
ang[ boneid ] = ang[ boneid ] + v.adjust
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Processes the AnglesTable from a skeleton constructor
|
||||
--
|
||||
motionsensor.ProcessAnglesTable = function( translator, sensor, pos, rotation )
|
||||
|
||||
if ( !translator.AnglesTable ) then return {} end
|
||||
|
||||
local ang = {}
|
||||
|
||||
local special_vectors = {}
|
||||
special_vectors["right"] = rotation:Right()
|
||||
special_vectors["left"] = special_vectors["right"] * -1
|
||||
special_vectors["up"] = rotation:Up()
|
||||
special_vectors["down"] = special_vectors["up"] * -1
|
||||
special_vectors["forward"] = special_vectors["down"]:Cross( special_vectors["right"] )
|
||||
special_vectors["backward"] = special_vectors["forward"] * -1
|
||||
|
||||
special_vectors["hips_left"] = ( sensor[SENSORBONE.HIP_RIGHT] - sensor[SENSORBONE.HIP_LEFT] ):GetNormal()
|
||||
special_vectors["hips_up"] = ( sensor[SENSORBONE.HIP] - sensor[SENSORBONE.SHOULDER] ):GetNormal()
|
||||
special_vectors["hips_back"] = special_vectors["hips_up"]:Cross( special_vectors["hips_left"] )
|
||||
special_vectors["hips_fwd"] = special_vectors["hips_back"] * -1
|
||||
|
||||
special_vectors["chest_lft"] = ( sensor[SENSORBONE.SHOULDER_RIGHT] - sensor[SENSORBONE.SHOULDER_LEFT] ):GetNormal()
|
||||
special_vectors["chest_rgt"] = special_vectors["chest_lft"] * -1
|
||||
special_vectors["chest_up"] = ( sensor[SENSORBONE.SPINE] - sensor[SENSORBONE.SHOULDER] ):GetNormal()
|
||||
special_vectors["chest_dn"] = special_vectors["chest_up"] * -1
|
||||
special_vectors["chest_bck"] = special_vectors["chest_up"]:Cross( special_vectors["chest_lft"] )
|
||||
special_vectors["chest_fwd"] = special_vectors["chest_bck"] * -1
|
||||
|
||||
special_vectors["head_up"] = ( sensor[SENSORBONE.SHOULDER] - sensor[SENSORBONE.HEAD] ):GetNormal()
|
||||
special_vectors["head_back"] = special_vectors["head_up"]:Cross( special_vectors["chest_lft"] )
|
||||
|
||||
local reprocess = {}
|
||||
|
||||
for k, v in pairs( translator.AnglesTable ) do
|
||||
|
||||
table.insert( reprocess, k )
|
||||
|
||||
end
|
||||
|
||||
for iPasses = 1, 5 do
|
||||
|
||||
local cur_process = reprocess
|
||||
reprocess = {}
|
||||
|
||||
for k, v in pairs( cur_process ) do
|
||||
|
||||
if ( !motionsensor.ProcessAngle( translator, sensor, pos, ang, special_vectors, v, translator.AnglesTable[v] ) ) then
|
||||
table.insert( reprocess, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( table.IsEmpty( reprocess ) ) then
|
||||
--DebugInfo( 0, iPasses .. " Passes" )
|
||||
return ang
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If we got here then we're doing something wrong.
|
||||
-- It should have out'ed before completing 5 passes.
|
||||
--
|
||||
DebugInfo( 0, "motionsensor.ProcessAnglesTable: 4+ passes!" )
|
||||
return ang
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Processes the PositionTable from a skeleton constructor
|
||||
--
|
||||
motionsensor.ProcessPositionTable = function( translator, sensor )
|
||||
|
||||
if ( !translator.PositionTable ) then return {} end
|
||||
|
||||
local pos = {}
|
||||
|
||||
for k, v in pairs( translator.PositionTable ) do
|
||||
|
||||
-- A number means get value straight from the sensor
|
||||
if ( isnumber( v ) ) then pos[ k ] = sensor[ v ] end
|
||||
|
||||
if ( istable( v ) and v.type == "lerp" ) then
|
||||
|
||||
pos[ k ] = LerpVector( v.value, sensor[ v.from ], sensor[ v.to ] )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return pos
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called to build the skeleton
|
||||
--
|
||||
motionsensor.BuildSkeleton = function( translator, player, rotation )
|
||||
|
||||
--
|
||||
-- The kinect animations are recorded on the skunt, so rotate towards the player
|
||||
--
|
||||
rotation:RotateAroundAxis( rotation:Up(), -90 )
|
||||
|
||||
--
|
||||
-- Pre-get and rotate all the player positions
|
||||
--
|
||||
local sensor = {}
|
||||
for i = 0, 19 do
|
||||
sensor[ i ] = player:MotionSensorPos( i )
|
||||
sensor[ i ]:Rotate( rotation )
|
||||
end
|
||||
|
||||
if ( translator.PrePosition ) then
|
||||
translator:PrePosition( sensor )
|
||||
end
|
||||
|
||||
--
|
||||
-- Fill out the position table..
|
||||
--
|
||||
local pos = motionsensor.ProcessPositionTable( translator, sensor )
|
||||
|
||||
--
|
||||
-- Fill out the angles
|
||||
--
|
||||
local ang = motionsensor.ProcessAnglesTable( translator, sensor, pos, rotation )
|
||||
|
||||
--
|
||||
-- Allow the bone builder to make any last minute changes
|
||||
--
|
||||
translator:Complete( player, sensor, rotation, pos, ang )
|
||||
|
||||
return pos, ang, sensor
|
||||
|
||||
end
|
||||
|
||||
260
lua/includes/extensions/net.lua
Normal file
260
lua/includes/extensions/net.lua
Normal file
@@ -0,0 +1,260 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- This is just enough for the entity index. This however is not perfect
|
||||
-- as the entity at given index may have changed during transport.
|
||||
-- If this becomes a problem, inclusion of entity's serial will also be necessary
|
||||
local MAX_EDICT_BITS = 13
|
||||
|
||||
TYPE_COLOR = 255
|
||||
|
||||
net.Receivers = {}
|
||||
|
||||
--
|
||||
-- Set up a function to receive network messages
|
||||
--
|
||||
function net.Receive( name, func )
|
||||
|
||||
net.Receivers[ name:lower() ] = func
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- A message has been received from the network..
|
||||
--
|
||||
function net.Incoming( len, client )
|
||||
|
||||
local i = net.ReadHeader()
|
||||
local strName = util.NetworkIDToString( i )
|
||||
|
||||
if ( !strName ) then return end
|
||||
|
||||
local func = net.Receivers[ strName:lower() ]
|
||||
if ( !func ) then return end
|
||||
|
||||
--
|
||||
-- len includes the 16 bit int which told us the message name
|
||||
--
|
||||
len = len - 16
|
||||
|
||||
func( len, client )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Read/Write a boolean to the stream
|
||||
--
|
||||
net.WriteBool = net.WriteBit
|
||||
|
||||
function net.ReadBool()
|
||||
|
||||
return net.ReadBit() == 1
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Read/Write an entity to the stream
|
||||
--
|
||||
function net.WriteEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then
|
||||
net.WriteUInt( 0, MAX_EDICT_BITS )
|
||||
else
|
||||
net.WriteUInt( ent:EntIndex(), MAX_EDICT_BITS )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadEntity()
|
||||
|
||||
local i = net.ReadUInt( MAX_EDICT_BITS )
|
||||
if ( !i ) then return end
|
||||
|
||||
return Entity( i )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Read/Write a player to the stream
|
||||
--
|
||||
function net.WritePlayer( ply )
|
||||
|
||||
if ( !IsValid( ply ) || !ply:IsPlayer() ) then
|
||||
net.WriteUInt( 0, 8 )
|
||||
else
|
||||
net.WriteUInt( ply:EntIndex(), 8 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadPlayer()
|
||||
|
||||
local i = net.ReadUInt( 8 )
|
||||
if ( !i ) then return end
|
||||
|
||||
local ply = Entity( i )
|
||||
return ply
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Read/Write a color to/from the stream
|
||||
--
|
||||
function net.WriteColor( col, writeAlpha )
|
||||
if ( writeAlpha == nil ) then writeAlpha = true end
|
||||
|
||||
assert( IsColor( col ), "net.WriteColor: color expected, got ".. type( col ) )
|
||||
|
||||
local r, g, b, a = col:Unpack()
|
||||
net.WriteUInt( r, 8 )
|
||||
net.WriteUInt( g, 8 )
|
||||
net.WriteUInt( b, 8 )
|
||||
|
||||
if ( writeAlpha ) then
|
||||
net.WriteUInt( a, 8 )
|
||||
end
|
||||
end
|
||||
|
||||
function net.ReadColor( readAlpha )
|
||||
if ( readAlpha == nil ) then readAlpha = true end
|
||||
|
||||
local r, g, b =
|
||||
net.ReadUInt( 8 ),
|
||||
net.ReadUInt( 8 ),
|
||||
net.ReadUInt( 8 )
|
||||
|
||||
local a = 255
|
||||
if ( readAlpha ) then a = net.ReadUInt( 8 ) end
|
||||
|
||||
return Color( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Write a whole table to the stream
|
||||
-- This is less optimal than writing each
|
||||
-- item indivdually and in a specific order
|
||||
-- because it adds type information before each var
|
||||
--
|
||||
function net.WriteTable( tab, seq )
|
||||
|
||||
if ( seq ) then
|
||||
|
||||
local len = #tab
|
||||
net.WriteUInt( len, 32 )
|
||||
|
||||
for i = 1, len do
|
||||
|
||||
net.WriteType( tab[ i ] )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
net.WriteType( k )
|
||||
net.WriteType( v )
|
||||
|
||||
end
|
||||
|
||||
-- End of table
|
||||
net.WriteType( nil )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadTable( seq )
|
||||
|
||||
local tab = {}
|
||||
|
||||
if ( seq ) then
|
||||
|
||||
for i = 1, net.ReadUInt( 32 ) do
|
||||
|
||||
tab[ i ] = net.ReadType()
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
while true do
|
||||
|
||||
local k = net.ReadType()
|
||||
if ( k == nil ) then break end
|
||||
|
||||
tab[ k ] = net.ReadType()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
net.WriteVars =
|
||||
{
|
||||
[TYPE_NIL] = function ( t, v ) net.WriteUInt( t, 8 ) end,
|
||||
[TYPE_STRING] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteString( v ) end,
|
||||
[TYPE_NUMBER] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteDouble( v ) end,
|
||||
[TYPE_TABLE] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteTable( v ) end,
|
||||
[TYPE_BOOL] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteBool( v ) end,
|
||||
[TYPE_ENTITY] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteEntity( v ) end,
|
||||
[TYPE_VECTOR] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteVector( v ) end,
|
||||
[TYPE_ANGLE] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteAngle( v ) end,
|
||||
[TYPE_MATRIX] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteMatrix( v ) end,
|
||||
[TYPE_COLOR] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteColor( v ) end,
|
||||
}
|
||||
|
||||
function net.WriteType( v )
|
||||
local typeid = nil
|
||||
|
||||
if IsColor( v ) then
|
||||
typeid = TYPE_COLOR
|
||||
else
|
||||
typeid = TypeID( v )
|
||||
end
|
||||
|
||||
local wv = net.WriteVars[ typeid ]
|
||||
if ( wv ) then return wv( typeid, v ) end
|
||||
|
||||
error( "net.WriteType: Couldn't write " .. type( v ) .. " (type " .. typeid .. ")" )
|
||||
|
||||
end
|
||||
|
||||
net.ReadVars =
|
||||
{
|
||||
[TYPE_NIL] = function () return nil end,
|
||||
[TYPE_STRING] = function () return net.ReadString() end,
|
||||
[TYPE_NUMBER] = function () return net.ReadDouble() end,
|
||||
[TYPE_TABLE] = function () return net.ReadTable() end,
|
||||
[TYPE_BOOL] = function () return net.ReadBool() end,
|
||||
[TYPE_ENTITY] = function () return net.ReadEntity() end,
|
||||
[TYPE_VECTOR] = function () return net.ReadVector() end,
|
||||
[TYPE_ANGLE] = function () return net.ReadAngle() end,
|
||||
[TYPE_MATRIX] = function () return net.ReadMatrix() end,
|
||||
[TYPE_COLOR] = function () return net.ReadColor() end,
|
||||
}
|
||||
|
||||
function net.ReadType( typeid )
|
||||
|
||||
typeid = typeid or net.ReadUInt( 8 )
|
||||
|
||||
local rv = net.ReadVars[ typeid ]
|
||||
if ( rv ) then return rv() end
|
||||
|
||||
error( "net.ReadType: Couldn't read type " .. typeid )
|
||||
|
||||
end
|
||||
339
lua/includes/extensions/player.lua
Normal file
339
lua/includes/extensions/player.lua
Normal file
@@ -0,0 +1,339 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
local entity = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[key]
|
||||
if ( val ~= nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity metatable
|
||||
--
|
||||
local entval = entity[key]
|
||||
if ( entval ~= nil ) then return entval end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = entity.GetTable( self )
|
||||
if ( tab ) then
|
||||
return tab[ key ]
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
if ( !sql.TableExists( "playerpdata" ) ) then
|
||||
|
||||
sql.Query( "CREATE TABLE IF NOT EXISTS playerpdata ( infoid TEXT NOT NULL PRIMARY KEY, value TEXT );" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DebugInfo
|
||||
Desc: Prints debug information for the player
|
||||
( this is just an example )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:DebugInfo()
|
||||
|
||||
Msg( "Name: " .. self:Name() .. "\n" )
|
||||
Msg( "Pos: " .. tostring( self:GetPos() ) .. "\n" )
|
||||
|
||||
end
|
||||
|
||||
-- Helpful aliases
|
||||
meta.GetName = meta.Nick
|
||||
meta.Name = meta.Nick
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ConCommand
|
||||
Desc: Overrides the default ConCommand function
|
||||
-----------------------------------------------------------]]
|
||||
if ( CLIENT ) then
|
||||
|
||||
local SendConCommand = meta.ConCommand
|
||||
local CommandList = nil
|
||||
|
||||
function meta:ConCommand( command, bSkipQueue )
|
||||
|
||||
if ( bSkipQueue or IsConCommandBlocked( command ) ) then
|
||||
SendConCommand( self, command )
|
||||
else
|
||||
CommandList = CommandList or {}
|
||||
table.insert( CommandList, command )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function SendQueuedConsoleCommands()
|
||||
|
||||
if ( !CommandList ) then return end
|
||||
|
||||
local BytesSent = 0
|
||||
|
||||
for k, v in pairs( CommandList ) do
|
||||
|
||||
SendConCommand( LocalPlayer(), v )
|
||||
CommandList[ k ] = nil
|
||||
|
||||
-- Only send x bytes per tick
|
||||
BytesSent = BytesSent + v:len()
|
||||
if ( BytesSent > 128 ) then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Turn the table into a nil so we can return easy
|
||||
if ( table.IsEmpty( CommandList ) ) then
|
||||
|
||||
CommandList = nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Tick", "SendQueuedConsoleCommands", SendQueuedConsoleCommands )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetPData
|
||||
Saves persist data for this player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetPData( name, default )
|
||||
|
||||
-- First try looking up using the new key
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( key ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then
|
||||
|
||||
-- Not found? Look using the old key
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then return default end
|
||||
|
||||
end
|
||||
|
||||
return val
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
SetPData
|
||||
Set persistant data
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetPData( name, value )
|
||||
|
||||
-- Remove old value
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) )
|
||||
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
return sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( " .. SQLStr( key ) .. ", " .. SQLStr( value ) .. " )" ) ~= false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
RemovePData
|
||||
Remove persistant data
|
||||
-----------------------------------------------------------]]
|
||||
function meta:RemovePData( name )
|
||||
|
||||
-- First old key
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
local removed = sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) ) ~= false
|
||||
|
||||
-- Then new key
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
local removed2 = sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( key ) ) ~= false
|
||||
|
||||
return removed or removed2
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If they have their preferred default weapon then switch to it
|
||||
--
|
||||
function meta:SwitchToDefaultWeapon()
|
||||
|
||||
local weapon = self:GetInfo( "cl_defaultweapon" )
|
||||
|
||||
if ( self:HasWeapon( weapon ) ) then
|
||||
self:SelectWeapon( weapon )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Can use flashlight?
|
||||
--
|
||||
function meta:AllowFlashlight( bAble ) self.m_bFlashlight = bAble end
|
||||
function meta:CanUseFlashlight() return self.m_bFlashlight == true end
|
||||
|
||||
-- A function to set up player hands, so coders don't have to copy all the code everytime.
|
||||
-- Call this in PlayerSpawn hook
|
||||
function meta:SetupHands( ply )
|
||||
|
||||
local oldhands = self:GetHands()
|
||||
if ( IsValid( oldhands ) ) then
|
||||
oldhands:Remove()
|
||||
end
|
||||
|
||||
local hands = ents.Create( "gmod_hands" )
|
||||
if ( IsValid( hands ) ) then
|
||||
hands:DoSetup( self, ply )
|
||||
hands:Spawn()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Those functions have been removed from the engine since AddFlag and RemoveFlag
|
||||
-- made them obsolete, but we'll keep a Lua version of them for backward compatibility
|
||||
--
|
||||
if ( SERVER ) then
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Freeze
|
||||
Freezes or unfreezes the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:Freeze( b )
|
||||
|
||||
if ( b ) then
|
||||
self:AddFlags( FL_FROZEN )
|
||||
else
|
||||
self:RemoveFlags( FL_FROZEN )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GodEnable
|
||||
Enables godmode on the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GodEnable()
|
||||
|
||||
self:AddFlags( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GodDisable
|
||||
Disables godmode on the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GodDisable()
|
||||
|
||||
self:RemoveFlags( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
IsFrozen
|
||||
Returns true if the player is frozen
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsFrozen()
|
||||
|
||||
return self:IsFlagSet( FL_FROZEN )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
HasGodMode
|
||||
Returns true if the player is in godmode
|
||||
-----------------------------------------------------------]]
|
||||
function meta:HasGodMode()
|
||||
|
||||
return self:IsFlagSet( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
-- These are totally in the wrong place.
|
||||
function player.GetByAccountID( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:AccountID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetByUniqueID( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:UniqueID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetBySteamID( ID )
|
||||
ID = string.upper( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:SteamID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetBySteamID64( ID )
|
||||
ID = tostring( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:SteamID64() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local inext = ipairs( {} )
|
||||
local PlayerCache = nil
|
||||
|
||||
function player.Iterator()
|
||||
|
||||
if ( PlayerCache == nil ) then PlayerCache = player.GetAll() end
|
||||
|
||||
return inext, PlayerCache, 0
|
||||
|
||||
end
|
||||
|
||||
local function InvalidatePlayerCache( ent )
|
||||
|
||||
if ( ent:IsPlayer() ) then PlayerCache = nil end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "OnEntityCreated", "player.Iterator", InvalidatePlayerCache )
|
||||
hook.Add( "EntityRemoved", "player.Iterator", InvalidatePlayerCache )
|
||||
139
lua/includes/extensions/player_auth.lua
Normal file
139
lua/includes/extensions/player_auth.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
if ( not meta ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsAdmin
|
||||
Desc: Returns if a player is an admin.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsAdmin()
|
||||
|
||||
if ( self:IsSuperAdmin() ) then return true end
|
||||
if ( self:IsUserGroup( "admin" ) ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsSuperAdmin
|
||||
Desc: Returns if a player is a superadmin.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsSuperAdmin()
|
||||
|
||||
return self:IsUserGroup( "superadmin" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsUserGroup
|
||||
Desc: Returns if a player is in the specified usergroup.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsUserGroup( name )
|
||||
|
||||
if ( not self:IsValid() ) then return false end
|
||||
|
||||
return self:GetUserGroup() == name
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetUserGroup
|
||||
Desc: Returns the player's usergroup.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetUserGroup()
|
||||
|
||||
return self:GetNWString( "UserGroup", "user" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
This is the meat and spunk of the player auth system
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
if ( not SERVER ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetUserGroup
|
||||
Desc: Sets the player's usergroup. ( Serverside Only )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetUserGroup( name )
|
||||
|
||||
self:SetNWString( "UserGroup", name )
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- SteamIds table..
|
||||
-- STEAM_0:1:7099:
|
||||
-- name = garry
|
||||
-- group = superadmin
|
||||
|
||||
local SteamIDs = {}
|
||||
|
||||
local function LoadUsersFile()
|
||||
|
||||
local txt = file.Read( "settings/users.txt", "MOD" )
|
||||
if ( not txt ) then MsgN( "Failed to load settings/users.txt!" ) return end
|
||||
|
||||
-- Load the users file
|
||||
local UsersKV = util.KeyValuesToTable( txt )
|
||||
if ( not UsersKV ) then MsgN( "Failed to parse settings/users.txt!" ) return end
|
||||
|
||||
SteamIDs = {}
|
||||
|
||||
-- Extract the data into the SteamIDs table
|
||||
for key, tab in pairs( UsersKV ) do
|
||||
for name, steamid in pairs( tab ) do
|
||||
SteamIDs[ steamid ] = {}
|
||||
SteamIDs[ steamid ].name = name
|
||||
SteamIDs[ steamid ].group = key
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
LoadUsersFile()
|
||||
|
||||
function util.GetUserGroups()
|
||||
|
||||
return SteamIDs
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PlayerInitialSpawn", "PlayerAuthSpawn", function( ply )
|
||||
|
||||
local steamid = ply:SteamID()
|
||||
|
||||
if ( game.SinglePlayer() or ply:IsListenServerHost() ) then
|
||||
ply:SetUserGroup( "superadmin" )
|
||||
return
|
||||
end
|
||||
|
||||
if ( SteamIDs[ steamid ] == nil ) then
|
||||
ply:SetUserGroup( "user" )
|
||||
return
|
||||
end
|
||||
|
||||
-- Admin SteamID need to be fully authenticated by Steam!
|
||||
if ( ply.IsFullyAuthenticated and not ply:IsFullyAuthenticated() ) then
|
||||
ply:ChatPrint( string.format( "Hey '%s' - Your SteamID wasn't fully authenticated, so your usergroup has not been set to '%s'.", SteamIDs[ steamid ].name, SteamIDs[ steamid ].group ) )
|
||||
ply:ChatPrint( "Try restarting Steam." )
|
||||
return
|
||||
end
|
||||
|
||||
ply:SetUserGroup( SteamIDs[ steamid ].group )
|
||||
ply:ChatPrint( string.format( "Hey '%s' - You're in the '%s' group on this server.", SteamIDs[ steamid ].name, SteamIDs[ steamid ].group ) )
|
||||
|
||||
end )
|
||||
461
lua/includes/extensions/string.lua
Normal file
461
lua/includes/extensions/string.lua
Normal file
@@ -0,0 +1,461 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local string = string
|
||||
local math = math
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.ToTable( string )
|
||||
-----------------------------------------------------------]]
|
||||
function string.ToTable( input )
|
||||
local tbl = {}
|
||||
|
||||
-- For numbers, as some addons do this..
|
||||
local str = tostring( input )
|
||||
|
||||
for i = 1, #str do
|
||||
tbl[i] = string.sub( str, i, i )
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.JavascriptSafe( string )
|
||||
Desc: Takes a string and escapes it for insertion in to a JavaScript string
|
||||
-----------------------------------------------------------]]
|
||||
local javascript_escape_replacements = {
|
||||
["\\"] = "\\\\",
|
||||
["\0"] = "\\x00" ,
|
||||
["\b"] = "\\b" ,
|
||||
["\t"] = "\\t" ,
|
||||
["\n"] = "\\n" ,
|
||||
["\v"] = "\\v" ,
|
||||
["\f"] = "\\f" ,
|
||||
["\r"] = "\\r" ,
|
||||
["\""] = "\\\"",
|
||||
["\'"] = "\\\'",
|
||||
["`"] = "\\`",
|
||||
["$"] = "\\$",
|
||||
["{"] = "\\{",
|
||||
["}"] = "\\}"
|
||||
}
|
||||
|
||||
function string.JavascriptSafe( str )
|
||||
|
||||
str = string.gsub( str, ".", javascript_escape_replacements )
|
||||
|
||||
-- U+2028 and U+2029 are treated as line separators in JavaScript, handle separately as they aren't single-byte
|
||||
str = string.gsub( str, "\226\128\168", "\\\226\128\168" )
|
||||
str = string.gsub( str, "\226\128\169", "\\\226\128\169" )
|
||||
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.PatternSafe( string )
|
||||
Desc: Takes a string and escapes it for insertion in to a Lua pattern
|
||||
-----------------------------------------------------------]]
|
||||
local pattern_escape_replacements = {
|
||||
["("] = "%(",
|
||||
[")"] = "%)",
|
||||
["."] = "%.",
|
||||
["%"] = "%%",
|
||||
["+"] = "%+",
|
||||
["-"] = "%-",
|
||||
["*"] = "%*",
|
||||
["?"] = "%?",
|
||||
["["] = "%[",
|
||||
["]"] = "%]",
|
||||
["^"] = "%^",
|
||||
["$"] = "%$",
|
||||
["\0"] = "%z"
|
||||
}
|
||||
|
||||
function string.PatternSafe( str )
|
||||
return ( string.gsub( str, ".", pattern_escape_replacements ) )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: explode(seperator ,string)
|
||||
Desc: Takes a string and turns it into a table
|
||||
Usage: string.explode( " ", "Seperate this string")
|
||||
-----------------------------------------------------------]]
|
||||
local totable = string.ToTable
|
||||
local string_sub = string.sub
|
||||
local string_find = string.find
|
||||
local string_len = string.len
|
||||
function string.Explode( separator, str, withpattern )
|
||||
if ( separator == "" ) then return totable( str ) end
|
||||
if ( withpattern == nil ) then withpattern = false end
|
||||
|
||||
local ret = {}
|
||||
local current_pos = 1
|
||||
|
||||
for i = 1, string_len( str ) do
|
||||
local start_pos, end_pos = string_find( str, separator, current_pos, not withpattern )
|
||||
if ( not start_pos ) then break end
|
||||
ret[ i ] = string_sub( str, current_pos, start_pos - 1 )
|
||||
current_pos = end_pos + 1
|
||||
end
|
||||
|
||||
ret[ #ret + 1 ] = string_sub( str, current_pos )
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function string.Split( str, delimiter )
|
||||
return string.Explode( delimiter, str )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Implode( seperator, Table)
|
||||
Desc: Takes a table and turns it into a string
|
||||
Usage: string.Implode( " ", { "This", "Is", "A", "Table" } )
|
||||
-----------------------------------------------------------]]
|
||||
function string.Implode( seperator, Table ) return
|
||||
table.concat( Table, seperator )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetExtensionFromFilename( path )
|
||||
Desc: Returns extension from path
|
||||
Usage: string.GetExtensionFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetExtensionFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return nil end
|
||||
if ( c == "." ) then return string.sub( path, i + 1 ) end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StripExtension( path )
|
||||
-----------------------------------------------------------]]
|
||||
function string.StripExtension( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return path end
|
||||
if ( c == "." ) then return string.sub( path, 1, i - 1 ) end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPathFromFilename( path )
|
||||
Desc: Returns path from filepath
|
||||
Usage: string.GetPathFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetPathFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return string.sub( path, 1, i ) end
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetFileFromFilename( path )
|
||||
Desc: Returns file with extension from path
|
||||
Usage: string.GetFileFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetFileFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return string.sub( path, i + 1 ) end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------
|
||||
Name: FormattedTime( TimeInSeconds, Format )
|
||||
Desc: Given a time in seconds, returns formatted time
|
||||
If 'Format' is not specified the function returns a table
|
||||
conatining values for hours, mins, secs, ms
|
||||
|
||||
Examples: string.FormattedTime( 123.456, "%02i:%02i:%02i") ==> "02:03:45"
|
||||
string.FormattedTime( 123.456, "%02i:%02i") ==> "02:03"
|
||||
string.FormattedTime( 123.456, "%2i:%02i") ==> " 2:03"
|
||||
string.FormattedTime( 123.456 ) ==> { h = 0, m = 2, s = 3, ms = 45 }
|
||||
-------------------------------------------------------------------]]
|
||||
function string.FormattedTime( seconds, format )
|
||||
if ( not seconds ) then seconds = 0 end
|
||||
local hours = math.floor( seconds / 3600 )
|
||||
local minutes = math.floor( ( seconds / 60 ) % 60 )
|
||||
local millisecs = ( seconds - math.floor( seconds ) ) * 100
|
||||
seconds = math.floor( seconds % 60 )
|
||||
|
||||
if ( format ) then
|
||||
return string.format( format, minutes, seconds, millisecs )
|
||||
else
|
||||
return { h = hours, m = minutes, s = seconds, ms = millisecs }
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Old time functions
|
||||
-----------------------------------------------------------]]
|
||||
function string.ToMinutesSecondsMilliseconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i:%02i" ) end
|
||||
function string.ToMinutesSeconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i" ) end
|
||||
|
||||
local function pluralizeString( str, quantity )
|
||||
return str .. ( ( quantity ~= 1 ) and "s" or "" )
|
||||
end
|
||||
|
||||
function string.NiceTime( seconds )
|
||||
|
||||
if ( seconds == nil ) then return "a few seconds" end
|
||||
|
||||
if ( seconds < 60 ) then
|
||||
local t = math.floor( seconds )
|
||||
return t .. pluralizeString( " second", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 ) then
|
||||
local t = math.floor( seconds / 60 )
|
||||
return t .. pluralizeString( " minute", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 ) then
|
||||
local t = math.floor( seconds / (60 * 60) )
|
||||
return t .. pluralizeString( " hour", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 * 7 ) then
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 ) )
|
||||
return t .. pluralizeString( " day", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 * 365 ) then
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 * 7 ) )
|
||||
return t .. pluralizeString( " week", t )
|
||||
end
|
||||
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 * 365 ) )
|
||||
return t .. pluralizeString( " year", t )
|
||||
|
||||
end
|
||||
|
||||
function string.Left( str, num ) return string.sub( str, 1, num ) end
|
||||
function string.Right( str, num ) return string.sub( str, -num ) end
|
||||
|
||||
function string.Replace( str, tofind, toreplace )
|
||||
local tbl = string.Explode( tofind, str )
|
||||
if ( tbl[ 1 ] ) then return table.concat( tbl, toreplace ) end
|
||||
return str
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Trim( s )
|
||||
Desc: Removes leading and trailing spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.Trim( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^" .. char .. "*(.-)" .. char .. "*$" ) or s
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TrimRight( s )
|
||||
Desc: Removes trailing spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.TrimRight( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^(.-)" .. char .. "*$" ) or s
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TrimLeft( s )
|
||||
Desc: Removes leading spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.TrimLeft( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^" .. char .. "*(.+)$" ) or s
|
||||
end
|
||||
|
||||
function string.NiceSize( size )
|
||||
|
||||
size = tonumber( size )
|
||||
|
||||
if ( size <= 0 ) then return "0" end
|
||||
if ( size < 1000 ) then return size .. " Bytes" end
|
||||
if ( size < 1000 * 1000 ) then return math.Round( size / 1000, 2 ) .. " KB" end
|
||||
if ( size < 1000 * 1000 * 1000 ) then return math.Round( size / ( 1000 * 1000 ), 2 ) .. " MB" end
|
||||
|
||||
return math.Round( size / ( 1000 * 1000 * 1000 ), 2 ) .. " GB"
|
||||
|
||||
end
|
||||
|
||||
-- Note: These use Lua index numbering, not what you'd expect
|
||||
-- ie they start from 1, not 0.
|
||||
|
||||
function string.SetChar( s, k, v )
|
||||
|
||||
return string.sub( s, 0, k - 1 ) .. v .. string.sub( s, k + 1 )
|
||||
|
||||
end
|
||||
|
||||
function string.GetChar( s, k )
|
||||
|
||||
return string.sub( s, k, k )
|
||||
|
||||
end
|
||||
|
||||
local meta = getmetatable( "" )
|
||||
|
||||
function meta:__index( key )
|
||||
|
||||
local val = string[ key ]
|
||||
if ( val ~= nil ) then
|
||||
return val
|
||||
elseif ( tonumber( key ) ) then
|
||||
return string.sub( self, key, key )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function string.StartsWith( str, start )
|
||||
|
||||
return string.sub( str, 1, string.len( start ) ) == start
|
||||
|
||||
end
|
||||
string.StartWith = string.StartsWith
|
||||
|
||||
function string.EndsWith( str, endStr )
|
||||
|
||||
return endStr == "" or string.sub( str, -string.len( endStr ) ) == endStr
|
||||
|
||||
end
|
||||
|
||||
function string.FromColor( color )
|
||||
|
||||
return Format( "%i %i %i %i", color.r, color.g, color.b, color.a )
|
||||
|
||||
end
|
||||
|
||||
function string.ToColor( str )
|
||||
|
||||
local r, g, b, a = string.match( str, "(%d+) (%d+) (%d+) (%d+)" )
|
||||
|
||||
local col = Color( 255, 255, 255, 255 )
|
||||
col.r = tonumber( r ) or 255
|
||||
col.g = tonumber( g ) or 255
|
||||
col.b = tonumber( b ) or 255
|
||||
col.a = tonumber( a ) or 255
|
||||
|
||||
return col
|
||||
|
||||
end
|
||||
|
||||
function string.Comma( number, str )
|
||||
|
||||
if ( str ~= nil and not isstring( str ) ) then
|
||||
error( "bad argument #2 to 'string.Comma' (string expected, got " .. type( str ) .. ")" )
|
||||
elseif ( str ~= nil and string.match( str, "%d" ) ~= nil ) then
|
||||
error( "bad argument #2 to 'string.Comma' (non-numerical values expected, got " .. str .. ")" )
|
||||
end
|
||||
|
||||
local replace = str == nil and "%1,%2" or "%1" .. str .. "%2"
|
||||
|
||||
if ( isnumber( number ) ) then
|
||||
number = string.format( "%f", number )
|
||||
number = string.match( number, "^(.-)%.?0*$" ) -- Remove trailing zeros
|
||||
end
|
||||
|
||||
local index = -1
|
||||
while index ~= 0 do number, index = string.gsub( number, "^(-?%d+)(%d%d%d)", replace ) end
|
||||
|
||||
return number
|
||||
|
||||
end
|
||||
|
||||
function string.Interpolate( str, lookuptable )
|
||||
|
||||
return ( string.gsub( str, "{([_%a][_%w]*)}", lookuptable ) )
|
||||
|
||||
end
|
||||
|
||||
function string.CardinalToOrdinal( cardinal )
|
||||
|
||||
local basedigit = cardinal % 10
|
||||
|
||||
if ( basedigit == 1 ) then
|
||||
if ( cardinal % 100 == 11 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "st"
|
||||
elseif ( basedigit == 2 ) then
|
||||
if ( cardinal % 100 == 12 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "nd"
|
||||
elseif ( basedigit == 3 ) then
|
||||
if ( cardinal % 100 == 13 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "rd"
|
||||
end
|
||||
|
||||
return cardinal .. "th"
|
||||
|
||||
end
|
||||
|
||||
function string.NiceName( name )
|
||||
|
||||
name = name:Replace( "_", " " )
|
||||
|
||||
-- Try to split text into words, where words would start with single uppercase character
|
||||
local newParts = {}
|
||||
for id, str in ipairs( string.Explode( " ", name ) ) do
|
||||
local wordStart = 1
|
||||
for i = 2, str:len() do
|
||||
local c = str[ i ]
|
||||
if ( c:upper() == c ) then
|
||||
local toAdd = str:sub( wordStart, i - 1 )
|
||||
if ( toAdd:upper() == toAdd ) then continue end
|
||||
table.insert( newParts, toAdd )
|
||||
wordStart = i
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.insert( newParts, str:sub( wordStart, str:len() ) )
|
||||
end
|
||||
|
||||
-- Capitalize
|
||||
--[[
|
||||
for i, word in ipairs( newParts ) do
|
||||
if ( #word == 1 ) then
|
||||
newParts[i] = string.upper( word )
|
||||
else
|
||||
newParts[i] = string.upper( string.sub( word, 1, 1 ) ) .. string.sub( word, 2 )
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat( newParts, " " )]]
|
||||
|
||||
local ret = table.concat( newParts, " " )
|
||||
ret = string.upper( string.sub( ret, 1, 1 ) ) .. string.sub( ret, 2 )
|
||||
return ret
|
||||
|
||||
end
|
||||
815
lua/includes/extensions/table.lua
Normal file
815
lua/includes/extensions/table.lua
Normal file
@@ -0,0 +1,815 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function table.Pack( ... )
|
||||
return { ... }, select( "#", ... )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Inherit( t, base )
|
||||
Desc: Copies any missing data from base to t
|
||||
-----------------------------------------------------------]]
|
||||
function table.Inherit( t, base )
|
||||
|
||||
for k, v in pairs( base ) do
|
||||
if ( t[ k ] == nil ) then t[ k ] = v end
|
||||
end
|
||||
|
||||
t[ "BaseClass" ] = base
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Copy(t, lookup_table)
|
||||
Desc: Taken straight from http://lua-users.org/wiki/PitLibTablestuff
|
||||
and modified to the new Lua 5.1 code by me.
|
||||
Original function by PeterPrade!
|
||||
-----------------------------------------------------------]]
|
||||
function table.Copy( t, lookup_table )
|
||||
if ( t == nil ) then return nil end
|
||||
|
||||
local copy = {}
|
||||
setmetatable( copy, debug.getmetatable( t ) )
|
||||
for i, v in pairs( t ) do
|
||||
if ( !istable( v ) ) then
|
||||
copy[ i ] = v
|
||||
else
|
||||
lookup_table = lookup_table or {}
|
||||
lookup_table[ t ] = copy
|
||||
if ( lookup_table[ v ] ) then
|
||||
copy[ i ] = lookup_table[ v ] -- we already copied this table. reuse the copy.
|
||||
else
|
||||
copy[ i ] = table.Copy( v, lookup_table ) -- not yet copied. copy it.
|
||||
end
|
||||
end
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Empty( tab )
|
||||
Desc: Empty a table
|
||||
-----------------------------------------------------------]]
|
||||
function table.Empty( tab )
|
||||
for k, v in pairs( tab ) do
|
||||
tab[ k ] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsEmpty( tab )
|
||||
Desc: Returns whether a table has iterable items in it, useful for non-sequential tables
|
||||
-----------------------------------------------------------]]
|
||||
function table.IsEmpty( tab )
|
||||
return next( tab ) == nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyFromTo( FROM, TO )
|
||||
Desc: Make TO exactly the same as FROM - but still the same table.
|
||||
-----------------------------------------------------------]]
|
||||
function table.CopyFromTo( from, to )
|
||||
|
||||
-- Erase values from table TO
|
||||
table.Empty( to )
|
||||
|
||||
-- Copy values over
|
||||
table.Merge( to, from )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Merge
|
||||
Desc: xx
|
||||
-----------------------------------------------------------]]
|
||||
function table.Merge( dest, source, forceOverride )
|
||||
|
||||
for k, v in pairs( source ) do
|
||||
if ( !forceOverride and istable( v ) and istable( dest[ k ] ) ) then
|
||||
-- don't overwrite one table with another
|
||||
-- instead merge them recurisvely
|
||||
table.Merge( dest[ k ], v )
|
||||
else
|
||||
dest[ k ] = v
|
||||
end
|
||||
end
|
||||
|
||||
return dest
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HasValue
|
||||
Desc: Returns whether the value is in given table
|
||||
-----------------------------------------------------------]]
|
||||
function table.HasValue( t, val )
|
||||
for k, v in pairs( t ) do
|
||||
if ( v == val ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Add( dest, source )
|
||||
Desc: Unlike merge this adds the two tables together and discards keys.
|
||||
-----------------------------------------------------------]]
|
||||
function table.Add( dest, source )
|
||||
-- The tables should be different otherwise this will just freeze the whole game
|
||||
if ( dest == source ) then return dest end
|
||||
|
||||
-- At least one of them needs to be a table or this whole thing will fall on its ass
|
||||
if ( !istable( source ) ) then return dest end
|
||||
if ( !istable( dest ) ) then dest = {} end
|
||||
|
||||
for k, v in pairs( source ) do
|
||||
table.insert( dest, v )
|
||||
end
|
||||
|
||||
return dest
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortDesc( table )
|
||||
Desc: Like Lua's default sort, but descending
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortDesc( t )
|
||||
return table.sort( t, function( a, b ) return a > b end )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortByKey( table )
|
||||
Desc: Returns a table sorted numerically by Key value
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortByKey( t, desc )
|
||||
|
||||
local temp = {}
|
||||
|
||||
for key, _ in pairs( t ) do table.insert( temp, key ) end
|
||||
if ( desc ) then
|
||||
table.sort( temp, function( a, b ) return t[ a ] < t[ b ] end )
|
||||
else
|
||||
table.sort( temp, function( a, b ) return t[ a ] > t[ b ] end )
|
||||
end
|
||||
|
||||
return temp
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Count( table )
|
||||
Desc: Returns the number of keys in a table
|
||||
-----------------------------------------------------------]]
|
||||
function table.Count( t )
|
||||
local i = 0
|
||||
for k in pairs( t ) do i = i + 1 end
|
||||
return i
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Random( table )
|
||||
Desc: Return a random key
|
||||
-----------------------------------------------------------]]
|
||||
function table.Random( t )
|
||||
local rk = math.random( 1, table.Count( t ) )
|
||||
local i = 1
|
||||
for k, v in pairs( t ) do
|
||||
if ( i == rk ) then return v, k end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Shuffle( table )
|
||||
Desc: Performs an inline Fisher-Yates shuffle on the table in O(n) time
|
||||
-----------------------------------------------------------]]
|
||||
function table.Shuffle( t )
|
||||
local n = #t
|
||||
for i = 1, n - 1 do
|
||||
local j = math.random( i, n )
|
||||
t[ i ], t[ j ] = t[ j ], t[ i ]
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
Name: table.IsSequential( table )
|
||||
Desc: Returns true if the tables
|
||||
keys are sequential
|
||||
-------------------------------------------------------------------------]]
|
||||
function table.IsSequential( t )
|
||||
local i = 1
|
||||
for key, value in pairs( t ) do
|
||||
if ( t[ i ] == nil ) then return false end
|
||||
i = i + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.ToString( table,name,nice )
|
||||
Desc: Convert a simple table to a string
|
||||
table = the table you want to convert (table)
|
||||
name = the name of the table (string)
|
||||
nice = whether to add line breaks and indents (bool)
|
||||
-----------------------------------------------------------]]
|
||||
local function MakeTable( t, nice, indent, done )
|
||||
local str = ""
|
||||
done = done or {}
|
||||
indent = indent or 0
|
||||
|
||||
local idt = ""
|
||||
if ( nice ) then idt = string.rep( "\t", indent ) end
|
||||
|
||||
local nl, tab = "", ""
|
||||
if ( nice ) then nl, tab = "\n", "\t" end
|
||||
|
||||
local sequential = table.IsSequential( t )
|
||||
|
||||
for key, value in pairs( t ) do
|
||||
|
||||
str = str .. idt .. tab .. tab
|
||||
|
||||
if !sequential then
|
||||
if ( isnumber( key ) or isbool( key ) ) then
|
||||
key = "[" .. tostring( key ) .. "]" .. tab .. "="
|
||||
else
|
||||
key = tostring( key ) .. tab .. "="
|
||||
end
|
||||
else
|
||||
key = ""
|
||||
end
|
||||
|
||||
if ( istable( value ) and !done[ value ] ) then
|
||||
|
||||
if ( IsColor( value ) ) then
|
||||
done[ value ] = true
|
||||
value = "Color(" .. value.r .. "," .. value.g .. "," .. value.b .. "," .. value.a .. ")"
|
||||
str = str .. key .. tab .. value .. "," .. nl
|
||||
else
|
||||
done[ value ] = true
|
||||
str = str .. key .. tab .. '{' .. nl .. MakeTable( value, nice, indent + 1, done )
|
||||
str = str .. idt .. tab .. tab .. tab .. tab .. "}," .. nl
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if ( isstring( value ) ) then
|
||||
value = '"' .. tostring( value ) .. '"'
|
||||
elseif ( isvector( value ) ) then
|
||||
value = "Vector(" .. value.x .. "," .. value.y .. "," .. value.z .. ")"
|
||||
elseif ( isangle( value ) ) then
|
||||
value = "Angle(" .. value.pitch .. "," .. value.yaw .. "," .. value.roll .. ")"
|
||||
else
|
||||
value = tostring( value )
|
||||
end
|
||||
|
||||
str = str .. key .. tab .. value .. "," .. nl
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
function table.ToString( t, n, nice )
|
||||
local nl, tab = "", ""
|
||||
if ( nice ) then nl, tab = "\n", "\t" end
|
||||
|
||||
local str = ""
|
||||
if ( n ) then str = n .. tab .. "=" .. tab end
|
||||
return str .. "{" .. nl .. MakeTable( t, nice ) .. "}"
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Sanitise( table )
|
||||
Desc: Converts a table containing vectors, angles, bools so it can be converted to and from keyvalues
|
||||
-----------------------------------------------------------]]
|
||||
function table.Sanitise( t, done )
|
||||
|
||||
done = done or {}
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs ( t ) do
|
||||
|
||||
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
|
||||
|
||||
done[ v ] = true
|
||||
tbl[ k ] = table.Sanitise( v, done )
|
||||
|
||||
else
|
||||
|
||||
if ( isvector( v ) ) then
|
||||
|
||||
local x, y, z = v.x, v.y, v.z
|
||||
if y == 0 then y = nil end
|
||||
if z == 0 then z = nil end
|
||||
tbl[ k ] = { __type = "Vector", x = x, y = y, z = z }
|
||||
|
||||
elseif ( isangle( v ) ) then
|
||||
|
||||
local p, y, r = v.pitch, v.yaw, v.roll
|
||||
if p == 0 then p = nil end
|
||||
if y == 0 then y = nil end
|
||||
if r == 0 then r = nil end
|
||||
tbl[ k ] = { __type = "Angle", p = p, y = y, r = r }
|
||||
|
||||
elseif ( IsColor( v ) ) then
|
||||
|
||||
local r, g, b, a = v.r, v.g, v.b, v.a
|
||||
if r == 255 then r = nil end
|
||||
if g == 255 then g = nil end
|
||||
if b == 255 then b = nil end
|
||||
if a == 255 then a = nil end
|
||||
tbl[ k ] = { __type = "Color", r = r, g = g, b = b, a = a }
|
||||
|
||||
elseif ( isbool( v ) ) then
|
||||
|
||||
tbl[ k ] = { __type = "Bool", tostring( v ) }
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = tostring( v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tbl
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.DeSanitise( table )
|
||||
Desc: Converts a Sanitised table back
|
||||
-----------------------------------------------------------]]
|
||||
function table.DeSanitise( t, done )
|
||||
|
||||
done = done or {}
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs ( t ) do
|
||||
|
||||
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
|
||||
|
||||
done[ v ] = true
|
||||
|
||||
if ( v.__type ) then
|
||||
|
||||
if ( v.__type == "Vector" ) then
|
||||
|
||||
tbl[ k ] = Vector( v.x or 0, v.y, v.z )
|
||||
|
||||
elseif ( v.__type == "Angle" ) then
|
||||
|
||||
tbl[ k ] = Angle( v.p or 0, v.y, v.r )
|
||||
|
||||
elseif ( v.__type == "Color" ) then
|
||||
|
||||
tbl[ k ] = Color( v.r or 255, v.g or 255, v.b or 255, v.a or 255 )
|
||||
|
||||
elseif ( v.__type == "Bool" ) then
|
||||
|
||||
tbl[ k ] = ( v[ 1 ] == "true" )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = table.DeSanitise( v, done )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tbl
|
||||
|
||||
end
|
||||
|
||||
function table.ForceInsert( t, v )
|
||||
|
||||
if ( t == nil ) then t = {} end
|
||||
|
||||
table.insert( t, v )
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortByMember( table )
|
||||
Desc: Sorts table by named member
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortByMember( tab, memberName, bAsc )
|
||||
|
||||
local TableMemberSort = function( a, b, MemberName, bReverse )
|
||||
|
||||
--
|
||||
-- All this error checking kind of sucks, but really is needed
|
||||
--
|
||||
if ( !istable( a ) ) then return !bReverse end
|
||||
if ( !istable( b ) ) then return bReverse end
|
||||
if ( !a[ MemberName ] ) then return !bReverse end
|
||||
if ( !b[ MemberName ] ) then return bReverse end
|
||||
|
||||
if ( isstring( a[ MemberName ] ) ) then
|
||||
|
||||
if ( bReverse ) then
|
||||
return a[ MemberName ]:lower() < b[ MemberName ]:lower()
|
||||
else
|
||||
return a[ MemberName ]:lower() > b[ MemberName ]:lower()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( bReverse ) then
|
||||
return a[ MemberName ] < b[ MemberName ]
|
||||
else
|
||||
return a[ MemberName ] > b[ MemberName ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.sort( tab, function( a, b ) return TableMemberSort( a, b, memberName, bAsc or false ) end )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.LowerKeyNames( table )
|
||||
Desc: Lowercase the keynames of all tables
|
||||
-----------------------------------------------------------]]
|
||||
function table.LowerKeyNames( tab )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
-- Recurse
|
||||
if ( istable( v ) ) then
|
||||
v = table.LowerKeyNames( v )
|
||||
end
|
||||
|
||||
OutTable[ k ] = v
|
||||
|
||||
if ( isstring( k ) ) then
|
||||
|
||||
OutTable[ k ] = nil
|
||||
OutTable[ string.lower( k ) ] = v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.CollapseKeyValue( table )
|
||||
Desc: Collapses a table with keyvalue structure
|
||||
-----------------------------------------------------------]]
|
||||
function table.CollapseKeyValue( Table )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( Table ) do
|
||||
|
||||
local Val = v.Value
|
||||
|
||||
if ( istable( Val ) ) then
|
||||
Val = table.CollapseKeyValue( Val )
|
||||
end
|
||||
|
||||
OutTable[ v.Key ] = Val
|
||||
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.ClearKeys( table, bSaveKey )
|
||||
Desc: Clears the keys, converting to a numbered format
|
||||
-----------------------------------------------------------]]
|
||||
function table.ClearKeys( Table, bSaveKey )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( Table ) do
|
||||
if ( bSaveKey ) then
|
||||
v.__key = k
|
||||
end
|
||||
table.insert( OutTable, v )
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
local function keyValuePairs( state )
|
||||
|
||||
state.Index = state.Index + 1
|
||||
|
||||
local keyValue = state.KeyValues[ state.Index ]
|
||||
if ( !keyValue ) then return end
|
||||
|
||||
return keyValue.key, keyValue.val
|
||||
|
||||
end
|
||||
|
||||
local function toKeyValues( tbl )
|
||||
|
||||
local result = {}
|
||||
|
||||
for k, v in pairs( tbl ) do
|
||||
table.insert( result, { key = k, val = v } )
|
||||
end
|
||||
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
local function getKeys( tbl )
|
||||
|
||||
local keys = {}
|
||||
|
||||
for k in pairs( tbl ) do
|
||||
table.insert( keys, k )
|
||||
end
|
||||
|
||||
return keys
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by TABLE KEY
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairs( pTable, Desc )
|
||||
|
||||
local keys = getKeys( pTable )
|
||||
|
||||
if ( Desc ) then
|
||||
table.sort( keys, function( a, b )
|
||||
return a > b
|
||||
end )
|
||||
else
|
||||
table.sort( keys, function( a, b )
|
||||
return a < b
|
||||
end )
|
||||
end
|
||||
|
||||
local i, key
|
||||
return function()
|
||||
i, key = next( keys, i )
|
||||
return key, pTable[key]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by VALUE
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairsByValue( pTable, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
if ( Desc ) then
|
||||
table.sort( sortedTbl, function( a, b ) return a.val > b.val end )
|
||||
else
|
||||
table.sort( sortedTbl, function( a, b ) return a.val < b.val end )
|
||||
end
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by Member Value (All table entries must be a table!)
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairsByMemberValue( pTable, pValueName, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
for k, v in pairs( sortedTbl ) do
|
||||
v.member = v.val[ pValueName ]
|
||||
end
|
||||
|
||||
table.SortByMember( sortedTbl, "member", !Desc )
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
-----------------------------------------------------------]]
|
||||
function RandomPairs( pTable, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
for k, v in pairs( sortedTbl ) do
|
||||
v.rand = math.random( 1, 1000000 )
|
||||
end
|
||||
|
||||
-- descending/ascending for a random order, really?
|
||||
if ( Desc ) then
|
||||
table.sort( sortedTbl, function( a, b ) return a.rand > b.rand end )
|
||||
else
|
||||
table.sort( sortedTbl, function( a, b ) return a.rand < b.rand end )
|
||||
end
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetFirstKey
|
||||
-----------------------------------------------------------]]
|
||||
function table.GetFirstKey( t )
|
||||
local k, _ = next( t )
|
||||
return k
|
||||
end
|
||||
|
||||
function table.GetFirstValue( t )
|
||||
local _, v = next( t )
|
||||
return v
|
||||
end
|
||||
|
||||
function table.GetLastKey( t )
|
||||
local k, _ = next( t, table.Count( t ) - 1 )
|
||||
return k
|
||||
end
|
||||
|
||||
function table.GetLastValue( t )
|
||||
local _, v = next( t, table.Count( t ) - 1 )
|
||||
return v
|
||||
end
|
||||
|
||||
function table.FindNext( tab, val )
|
||||
local bfound = false
|
||||
for k, v in pairs( tab ) do
|
||||
if ( bfound ) then return v end
|
||||
if ( val == v ) then bfound = true end
|
||||
end
|
||||
|
||||
return table.GetFirstValue( tab )
|
||||
end
|
||||
|
||||
function table.FindPrev( tab, val )
|
||||
|
||||
local last = table.GetLastValue( tab )
|
||||
for k, v in pairs( tab ) do
|
||||
if ( val == v ) then return last end
|
||||
last = v
|
||||
end
|
||||
|
||||
return last
|
||||
|
||||
end
|
||||
|
||||
function table.GetWinningKey( tab )
|
||||
|
||||
local highest = -math.huge
|
||||
local winner = nil
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
if ( v > highest ) then
|
||||
winner = k
|
||||
highest = v
|
||||
end
|
||||
end
|
||||
|
||||
return winner
|
||||
|
||||
end
|
||||
|
||||
function table.KeyFromValue( tbl, val )
|
||||
for key, value in pairs( tbl ) do
|
||||
if ( value == val ) then return key end
|
||||
end
|
||||
end
|
||||
|
||||
function table.RemoveByValue( tbl, val )
|
||||
|
||||
local key = table.KeyFromValue( tbl, val )
|
||||
if ( !key ) then return false end
|
||||
|
||||
if ( isnumber( key ) ) then
|
||||
table.remove( tbl, key )
|
||||
else
|
||||
tbl[ key ] = nil
|
||||
end
|
||||
|
||||
return key
|
||||
|
||||
end
|
||||
|
||||
function table.KeysFromValue( tbl, val )
|
||||
local res = {}
|
||||
for key, value in pairs( tbl ) do
|
||||
if ( value == val ) then res[ #res + 1 ] = key end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function table.MemberValuesFromKey( tab, key )
|
||||
local res = {}
|
||||
for k, v in pairs( tab ) do
|
||||
if ( istable( v ) and v[ key ] != nil ) then res[ #res + 1 ] = v[ key ] end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function table.Reverse( tbl )
|
||||
|
||||
local len = #tbl
|
||||
local ret = {}
|
||||
|
||||
for i = len, 1, -1 do
|
||||
ret[ len - i + 1 ] = tbl[ i ]
|
||||
end
|
||||
|
||||
return ret
|
||||
|
||||
end
|
||||
|
||||
function table.ForEach( tab, funcname )
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
funcname( k, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function table.GetKeys( tab )
|
||||
|
||||
local keys = {}
|
||||
local id = 1
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
keys[ id ] = k
|
||||
id = id + 1
|
||||
end
|
||||
|
||||
return keys
|
||||
|
||||
end
|
||||
|
||||
function table.Flip( tab )
|
||||
|
||||
local res = {}
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
res[ v ] = k
|
||||
end
|
||||
|
||||
return res
|
||||
|
||||
end
|
||||
|
||||
-- Polyfill for table.move on 32-bit
|
||||
-- Don't forget to remove this when it's no longer necessary
|
||||
if ( !table.move ) then
|
||||
function table.move( sourceTbl, from, to, dest, destTbl )
|
||||
|
||||
if ( !istable( sourceTbl ) ) then error( "bad argument #1 to 'move' (table expected, got " .. type( sourceTbl ) .. ")" ) end
|
||||
if ( !isnumber( from ) ) then error( "bad argument #2 to 'move' (number expected, got " .. type( from ) .. ")" ) end
|
||||
if ( !isnumber( to ) ) then error( "bad argument #3 to 'move' (number expected, got " .. type( to ) .. ")" ) end
|
||||
if ( !isnumber( dest ) ) then error( "bad argument #4 to 'move' (number expected, got " .. type( dest ) .. ")" ) end
|
||||
if ( destTbl != nil ) then
|
||||
if ( !istable( destTbl ) ) then error( "bad argument #5 to 'move' (table expected, got " .. type( destTbl ) .. ")" ) end
|
||||
else
|
||||
destTbl = sourceTbl
|
||||
end
|
||||
|
||||
local buffer = { unpack( sourceTbl, from, to ) }
|
||||
|
||||
dest = math.floor( dest - 1 )
|
||||
for i, v in ipairs( buffer ) do
|
||||
destTbl[ dest + i ] = v
|
||||
end
|
||||
|
||||
return destTbl
|
||||
|
||||
end
|
||||
end
|
||||
420
lua/includes/extensions/util.lua
Normal file
420
lua/includes/extensions/util.lua
Normal file
@@ -0,0 +1,420 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !util ) then return end
|
||||
|
||||
if ( CLIENT ) then
|
||||
include( "util/worldpicker.lua" )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsValidPhysicsObject
|
||||
Params: <ent> <num>
|
||||
Desc: Returns true if physics object is valid, false if not
|
||||
-----------------------------------------------------------]]
|
||||
function util.IsValidPhysicsObject( ent, num )
|
||||
|
||||
-- Make sure the entity is valid
|
||||
if ( !ent or ( !ent:IsValid() and !ent:IsWorld() ) ) then return false end
|
||||
|
||||
-- This is to stop attaching to walking NPCs.
|
||||
-- Although this is possible and `works', it can severly reduce the
|
||||
-- performance of the server.. Plus they don't pay attention to constraints
|
||||
-- anyway - so we're not really losing anything.
|
||||
|
||||
local MoveType = ent:GetMoveType()
|
||||
if ( !ent:IsWorld() and MoveType != MOVETYPE_VPHYSICS and !( ent:GetModel() and ent:GetModel():StartsWith( "*" ) ) ) then return false end
|
||||
|
||||
local Phys = ent:GetPhysicsObjectNum( num )
|
||||
return IsValid( Phys )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPlayerTrace( ply, dir )
|
||||
Desc: Returns a generic trace table for the player
|
||||
(dir is optional, defaults to the player's aim)
|
||||
-----------------------------------------------------------]]
|
||||
function util.GetPlayerTrace( ply, dir )
|
||||
|
||||
dir = dir or ply:GetAimVector()
|
||||
|
||||
local trace = {}
|
||||
|
||||
trace.start = ply:EyePos()
|
||||
trace.endpos = trace.start + ( dir * ( 4096 * 8 ) )
|
||||
trace.filter = ply
|
||||
|
||||
return trace
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: QuickTrace( origin, offset, filter )
|
||||
Desc: Quick trace
|
||||
-----------------------------------------------------------]]
|
||||
function util.QuickTrace( origin, dir, filter )
|
||||
|
||||
local trace = {}
|
||||
|
||||
trace.start = origin
|
||||
trace.endpos = origin + dir
|
||||
trace.filter = filter
|
||||
|
||||
return util.TraceLine( trace )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: tobool( in )
|
||||
Desc: Turn variable into bool
|
||||
-----------------------------------------------------------]]
|
||||
util.tobool = tobool
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LocalToWorld( ent, lpos, bone )
|
||||
Desc: Convert the local position on an entity to world pos
|
||||
-----------------------------------------------------------]]
|
||||
function util.LocalToWorld( ent, lpos, bone )
|
||||
|
||||
bone = bone or 0
|
||||
if ( ent:EntIndex() == 0 ) then
|
||||
return lpos
|
||||
else
|
||||
if ( IsValid( ent:GetPhysicsObjectNum( bone ) ) ) then
|
||||
return ent:GetPhysicsObjectNum( bone ):LocalToWorld( lpos )
|
||||
else
|
||||
return ent:LocalToWorld( lpos )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns year, month, day and hour, minute, second in a formatted string.
|
||||
-----------------------------------------------------------]]
|
||||
function util.DateStamp()
|
||||
|
||||
local t = os.date( '*t' )
|
||||
return t.year .. "-" .. t.month .. "-" .. t.day .. " " .. Format( "%02i-%02i-%02i", t.hour, t.min, t.sec )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convert a string to a certain type
|
||||
-----------------------------------------------------------]]
|
||||
function util.StringToType( str, typename )
|
||||
|
||||
typename = typename:lower()
|
||||
|
||||
if ( typename == "vector" ) then return Vector( str ) end
|
||||
if ( typename == "angle" ) then return Angle( str ) end
|
||||
if ( typename == "float" || typename == "number" ) then return tonumber( str ) end
|
||||
if ( typename == "int" ) then local v = tonumber( str ) return v and math.Round( v ) or nil end
|
||||
if ( typename == "bool" || typename == "boolean" ) then return tobool( str ) end
|
||||
if ( typename == "string" ) then return tostring( str ) end
|
||||
if ( typename == "entity" ) then return Entity( str ) end
|
||||
|
||||
MsgN( "util.StringToType: unknown type \"", typename, "\"!" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Convert a type to a (nice, but still parsable) string
|
||||
--
|
||||
function util.TypeToString( v )
|
||||
|
||||
local iD = TypeID( v )
|
||||
|
||||
if ( iD == TYPE_VECTOR or iD == TYPE_ANGLE ) then
|
||||
return string.format( "%.2f %.2f %.2f", v:Unpack() )
|
||||
end
|
||||
|
||||
if ( iD == TYPE_NUMBER ) then
|
||||
return util.NiceFloat( v )
|
||||
end
|
||||
|
||||
return tostring( v )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Formats a float by stripping off extra 0's and .'s
|
||||
--
|
||||
-- 0.00 -> 0
|
||||
-- 0.10 -> 0.1
|
||||
-- 1.00 -> 1
|
||||
-- 1.49 -> 1.49
|
||||
-- 5.90 -> 5.9
|
||||
--
|
||||
function util.NiceFloat( f )
|
||||
|
||||
local str = string.format( "%f", f )
|
||||
|
||||
str = str:TrimRight( "0" )
|
||||
str = str:TrimRight( "." )
|
||||
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Timer
|
||||
--
|
||||
--
|
||||
local T =
|
||||
{
|
||||
--
|
||||
-- Resets the timer to nothing
|
||||
--
|
||||
Reset = function( self )
|
||||
|
||||
self.endtime = nil
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Starts the timer, call with end time
|
||||
--
|
||||
Start = function( self, time )
|
||||
|
||||
self.endtime = CurTime() + time
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Returns true if the timer has been started
|
||||
--
|
||||
Started = function( self )
|
||||
|
||||
return self.endtime != nil
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Returns true if the time has elapsed
|
||||
--
|
||||
Elapsed = function( self )
|
||||
|
||||
return self.endtime == nil or self.endtime <= CurTime()
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
T.__index = T
|
||||
|
||||
--
|
||||
-- Create a new timer object
|
||||
--
|
||||
function util.Timer( startdelay )
|
||||
|
||||
startdelay = startdelay or 0
|
||||
|
||||
local t = {}
|
||||
setmetatable( t, T )
|
||||
t.endtime = CurTime() + startdelay
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function PopStack( self, num )
|
||||
|
||||
if ( num == nil ) then
|
||||
num = 1
|
||||
elseif ( num < 0 ) then
|
||||
error( string.format( "attempted to pop %d elements in stack, expected >= 0", num ), 3 )
|
||||
else
|
||||
num = math.floor( num )
|
||||
end
|
||||
|
||||
local len = self[ 0 ]
|
||||
|
||||
if ( num > len ) then
|
||||
error( string.format( "attempted to pop %u element%s in stack of length %u", num, num == 1 and "" or "s", len ), 3 )
|
||||
end
|
||||
|
||||
return num, len
|
||||
|
||||
end
|
||||
|
||||
local STACK =
|
||||
{
|
||||
Push = function( self, obj )
|
||||
local len = self[ 0 ] + 1
|
||||
self[ len ] = obj
|
||||
self[ 0 ] = len
|
||||
end,
|
||||
|
||||
Pop = function( self, num )
|
||||
local len
|
||||
num, len = PopStack( self, num )
|
||||
|
||||
if ( num == 0 ) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local newlen = len - num
|
||||
self[ 0 ] = newlen
|
||||
|
||||
newlen = newlen + 1
|
||||
local ret = self[ newlen ]
|
||||
|
||||
-- Pop up to the last element
|
||||
for i = len, newlen, -1 do
|
||||
self[ i ] = nil
|
||||
end
|
||||
|
||||
return ret
|
||||
end,
|
||||
|
||||
PopMulti = function( self, num )
|
||||
local len
|
||||
num, len = PopStack( self, num )
|
||||
|
||||
if ( num == 0 ) then
|
||||
return {}
|
||||
end
|
||||
|
||||
local newlen = len - num
|
||||
self[ 0 ] = newlen
|
||||
|
||||
local ret = {}
|
||||
local retpos = 0
|
||||
|
||||
-- Pop each element and add it to the table
|
||||
-- Iterate in reverse since the stack is internally stored
|
||||
-- with 1 being the bottom element and len being the top
|
||||
-- But the return will have 1 as the top element
|
||||
for i = len, newlen + 1, -1 do
|
||||
retpos = retpos + 1
|
||||
ret[ retpos ] = self[ i ]
|
||||
|
||||
self[ i ] = nil
|
||||
end
|
||||
|
||||
return ret
|
||||
end,
|
||||
|
||||
Top = function( self )
|
||||
local len = self[ 0 ]
|
||||
|
||||
if ( len == 0 ) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return self[ len ]
|
||||
end,
|
||||
|
||||
Size = function( self )
|
||||
return self[ 0 ]
|
||||
end
|
||||
}
|
||||
|
||||
STACK.__index = STACK
|
||||
|
||||
function util.Stack()
|
||||
return setmetatable( { [ 0 ] = 0 }, STACK )
|
||||
end
|
||||
|
||||
-- Helper for the following functions. This is not ideal but we cannot change this because it will break existing addons.
|
||||
local function GetUniqueID( sid )
|
||||
return util.CRC( "gm_" .. sid .. "_gm" )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPData( steamid, name, default )
|
||||
Desc: Gets the persistant data from a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.GetPData( steamid, name, default )
|
||||
|
||||
-- First try looking up using the new key
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( key ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then
|
||||
|
||||
-- Not found? Look using the old key
|
||||
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
||||
val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then return default end
|
||||
|
||||
end
|
||||
|
||||
return val
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetPData( steamid, name, value )
|
||||
Desc: Sets the persistant data of a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.SetPData( steamid, name, value )
|
||||
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( " .. SQLStr( key ) .. ", " .. SQLStr( value ) .. " )" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RemovePData( steamid, name )
|
||||
Desc: Removes the persistant data from a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.RemovePData( steamid, name )
|
||||
|
||||
-- First the old key
|
||||
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) )
|
||||
|
||||
-- Then the new key. util.SteamIDTo64 is not ideal, but nothing we can do about it now
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( key ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsBinaryModuleInstalled( name )
|
||||
Desc: Returns whether a binary module with the given name is present on disk
|
||||
-----------------------------------------------------------]]
|
||||
local suffix = ( { "osx64", "osx", "linux64", "linux", "win64", "win32" } )[
|
||||
( system.IsWindows() and 4 or 0 )
|
||||
+ ( system.IsLinux() and 2 or 0 )
|
||||
+ ( jit.arch == "x86" and 1 or 0 )
|
||||
+ 1
|
||||
]
|
||||
local fmt = "lua/bin/gm" .. ( ( CLIENT and !MENU_DLL ) and "cl" or "sv" ) .. "_%s_%s.dll"
|
||||
function util.IsBinaryModuleInstalled( name )
|
||||
if ( !isstring( name ) ) then
|
||||
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string expected, got " .. type( name ) .. ")" )
|
||||
elseif ( #name == 0 ) then
|
||||
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string cannot be empty)" )
|
||||
end
|
||||
|
||||
if ( file.Exists( string.format( fmt, name, suffix ), "MOD" ) ) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Edge case - on Linux 32-bit x86-64 branch, linux32 is also supported as a suffix
|
||||
if ( jit.versionnum != 20004 and jit.arch == "x86" and system.IsLinux() ) then
|
||||
return file.Exists( string.format( fmt, name, "linux32" ), "MOD" )
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
66
lua/includes/extensions/util/worldpicker.lua
Normal file
66
lua/includes/extensions/util/worldpicker.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--
|
||||
--
|
||||
-- worldpicker is for picking an entity from the game while you have the GUI open.
|
||||
-- Calling util.worldpicker.Start( func ) will hide all GUI and let you pick an entity from
|
||||
-- the game world. Once selected it will call your passed function with the trace.
|
||||
--
|
||||
-- It's used in the icon editor
|
||||
--
|
||||
--
|
||||
|
||||
local bDoing = false
|
||||
local fnAction = nil
|
||||
|
||||
util.worldpicker = {
|
||||
--
|
||||
-- Start world picking
|
||||
--
|
||||
Start = function( func )
|
||||
|
||||
bDoing = true
|
||||
fnAction = func
|
||||
gui.EnableScreenClicker( true )
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Finish world picking - you shouldn't have to call this (called from hook below)
|
||||
--
|
||||
Finish = function( tr )
|
||||
|
||||
bDoing = false
|
||||
fnAction( tr )
|
||||
gui.EnableScreenClicker( false )
|
||||
|
||||
end,
|
||||
|
||||
Active = function() return bDoing end
|
||||
}
|
||||
|
||||
hook.Add( "VGUIMousePressAllowed", "WorldPickerMouseDisable", function( code )
|
||||
|
||||
if ( !bDoing ) then return false end
|
||||
|
||||
local dir = gui.ScreenToVector( input.GetCursorPos() )
|
||||
local tr = util.TraceLine( {
|
||||
start = LocalPlayer():GetShootPos(),
|
||||
endpos = LocalPlayer():GetShootPos() + dir * 32768,
|
||||
filter = LocalPlayer()
|
||||
} )
|
||||
|
||||
util.worldpicker.Finish( tr )
|
||||
|
||||
-- Don't register this click
|
||||
return true
|
||||
|
||||
end )
|
||||
22
lua/includes/extensions/vector.lua
Normal file
22
lua/includes/extensions/vector.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local meta = FindMetaTable( "Vector" )
|
||||
|
||||
-- Nothing in here, still leaving this file here just in case
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Converts Vector To Color - alpha precision lost, must reset
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ToColor( )
|
||||
|
||||
return Color( self.x * 255, self.y * 255, self.z * 255 )
|
||||
|
||||
end
|
||||
55
lua/includes/extensions/weapon.lua
Normal file
55
lua/includes/extensions/weapon.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local meta = FindMetaTable( "Weapon" )
|
||||
local entity = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[key]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity metatable
|
||||
--
|
||||
local val = entity[key]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = entity.GetTable( self )
|
||||
if ( tab != nil ) then
|
||||
local val = tab[ key ]
|
||||
if ( val != nil ) then return val end
|
||||
end
|
||||
|
||||
--
|
||||
-- Legacy: sometimes use self.Owner to get the owner.. so lets carry on supporting that stupidness
|
||||
-- This needs to be retired, just like self.Entity was.
|
||||
--
|
||||
if ( key == "Owner" ) then return entity.GetOwner( self ) end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
125
lua/includes/gmsave.lua
Normal file
125
lua/includes/gmsave.lua
Normal file
@@ -0,0 +1,125 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
gmsave = {}
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
include( "gmsave/entity_filters.lua" )
|
||||
include( "gmsave/player.lua" )
|
||||
|
||||
local g_WavSound = 1
|
||||
|
||||
function gmsave.LoadMap( strMapContents, ply, callback )
|
||||
|
||||
-- TODO: Do this in engine before sending it to this function.
|
||||
|
||||
-- Strip off any crap before the start char..
|
||||
local startchar = string.find( strMapContents, '' )
|
||||
if ( startchar != nil ) then
|
||||
strMapContents = string.sub( strMapContents, startchar )
|
||||
end
|
||||
|
||||
-- Strip off any crap after the end char..
|
||||
strMapContents = strMapContents:reverse()
|
||||
local startchar = string.find( strMapContents, '' )
|
||||
if ( startchar != nil ) then
|
||||
strMapContents = string.sub( strMapContents, startchar )
|
||||
end
|
||||
strMapContents = strMapContents:reverse()
|
||||
|
||||
-- END TODO
|
||||
|
||||
local tab = util.JSONToTable( strMapContents )
|
||||
|
||||
if ( !istable( tab ) ) then
|
||||
-- Error loading save!
|
||||
MsgN( "gm_load: Couldn't decode from json!" )
|
||||
return false
|
||||
end
|
||||
|
||||
-- Existing addons are forcing us to do this
|
||||
-- The issue is that some addons overwrite game.CleanUpMap
|
||||
-- Making the 3rd argument not exist
|
||||
hook.Add( "PostCleanupMap", "GMod_Load_Save", function()
|
||||
hook.Remove( "PostCleanupMap", "GMod_Load_Save" )
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
|
||||
ply:SendLua( "hook.Run( \"OnSpawnMenuClose\" )" )
|
||||
|
||||
g_WavSound = g_WavSound + 1
|
||||
if ( g_WavSound > 4 ) then g_WavSound = 1 end
|
||||
|
||||
ply:SendLua( string.format( "surface.PlaySound( \"garrysmod/save_load%d.wav\" )", g_WavSound ) )
|
||||
|
||||
gmsave.PlayerLoad( ply, tab.Player )
|
||||
|
||||
end
|
||||
|
||||
timer.Simple( 0.1, function()
|
||||
|
||||
DisablePropCreateEffect = true
|
||||
duplicator.RemoveMapCreatedEntities()
|
||||
duplicator.Paste( ply, tab.Entities, tab.Constraints )
|
||||
DisablePropCreateEffect = nil
|
||||
|
||||
if ( IsValid( ply ) ) then
|
||||
gmsave.PlayerLoad( ply, tab.Player )
|
||||
end
|
||||
|
||||
-- Since this save system is inferior to Source's, we gotta make sure this entity is disabled on load of a save
|
||||
-- On maps like Portal's testchmb_a_00.bsp this entity takes away player control and will not restore it
|
||||
-- if the player is not in a very specific place.
|
||||
timer.Simple( 1, function()
|
||||
for id, ent in ipairs( ents.FindByClass( "point_viewcontrol" ) ) do
|
||||
ent:Fire( "Disable" )
|
||||
end
|
||||
end )
|
||||
|
||||
if ( callback ) then callback() end
|
||||
|
||||
end )
|
||||
end )
|
||||
|
||||
game.CleanUpMap( false, nil, function() end )
|
||||
|
||||
end
|
||||
|
||||
function gmsave.SaveMap( ply )
|
||||
|
||||
local Ents = ents.GetAll()
|
||||
|
||||
for k, v in ipairs( Ents ) do
|
||||
|
||||
if ( !gmsave.ShouldSaveEntity( v, v:GetSaveTable() ) || v:IsConstraint() ) then
|
||||
Ents[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- This is to copy the constraints that are applied to the world only (ropes, etc)
|
||||
-- It will not actually save and then try to restore the world entity, as that would cause issues
|
||||
table.insert( Ents, game.GetWorld() )
|
||||
|
||||
local tab = duplicator.CopyEnts( Ents )
|
||||
if ( !tab ) then return end
|
||||
|
||||
tab.Player = gmsave.PlayerSave( ply )
|
||||
|
||||
--
|
||||
-- Try to figure out if any of the models/materials/etc came from some addon
|
||||
--
|
||||
duplicator.FigureOutRequiredAddons( tab )
|
||||
|
||||
return util.TableToJSON( tab )
|
||||
|
||||
end
|
||||
99
lua/includes/gmsave/constraints.lua
Normal file
99
lua/includes/gmsave/constraints.lua
Normal file
@@ -0,0 +1,99 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local function GetPhysicsObjectNum( ent, object )
|
||||
|
||||
for k = 0, ent:GetPhysicsObjectCount() - 1 do
|
||||
|
||||
local obj = ent:GetPhysicsObjectNum( k )
|
||||
if ( obj == object ) then return k end
|
||||
|
||||
end
|
||||
|
||||
return 0
|
||||
|
||||
end
|
||||
|
||||
function gmsave.ConstraintSave( ent )
|
||||
|
||||
local t = {}
|
||||
|
||||
t.EntOne, t.EntTwo = ent:GetConstrainedEntities()
|
||||
local PhysA, PhysB = ent:GetConstrainedPhysObjects()
|
||||
|
||||
t.BoneOne = GetPhysicsObjectNum( t.EntOne, PhysA )
|
||||
t.BoneTwo = GetPhysicsObjectNum( t.EntTwo, PhysB )
|
||||
|
||||
t.EntOne = gmsave.EntityEncode( t.EntOne )
|
||||
t.EntTwo = gmsave.EntityEncode( t.EntTwo )
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Creates a save table from a table of entities
|
||||
--
|
||||
function gmsave.ConstraintSaveList( ents )
|
||||
|
||||
local SavedConstraints = {}
|
||||
|
||||
for k, v in pairs( ents ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
if ( !v:IsConstraint() ) then continue end
|
||||
|
||||
SavedConstraints[ k ] = gmsave.ConstraintSave( v )
|
||||
|
||||
end
|
||||
|
||||
return SavedConstraints
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Creates a single entity from a table
|
||||
--
|
||||
function gmsave.ConstraintLoad( t, ent, ents )
|
||||
|
||||
local EntOne = gmsave.EntityDecode( t.EntOne, ents )
|
||||
local EntTwo = gmsave.EntityDecode( t.EntTwo, ents )
|
||||
|
||||
local PhysOne = EntOne:GetPhysicsObjectNum( t.BoneOne )
|
||||
local PhysTwo = EntTwo:GetPhysicsObjectNum( t.BoneTwo )
|
||||
|
||||
ent:SetPhysConstraintObjects( PhysOne, PhysTwo )
|
||||
ent:SetParent( ent.LoadData.m_pParent )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
gmsave.ApplyValuesToEntity( ent, ent.LoadData, ent.LoadData.lua_variables, ents )
|
||||
ent.LoadData = nil
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Restores multiple entitys from a table
|
||||
--
|
||||
function gmsave.ConstraintsLoadFromTable( tab, ents )
|
||||
|
||||
if ( !tab ) then return end
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
local ent = ents[ k ]
|
||||
if ( !IsValid( ent ) ) then continue end
|
||||
|
||||
gmsave.ConstraintLoad( v, ent, ents )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
89
lua/includes/gmsave/entity_filters.lua
Normal file
89
lua/includes/gmsave/entity_filters.lua
Normal file
@@ -0,0 +1,89 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local ClassInfo = {}
|
||||
|
||||
ClassInfo[ "scene_manager" ] = { ['save'] = false }
|
||||
ClassInfo[ "predicted_viewmodel" ] = { ['save'] = false }
|
||||
ClassInfo[ "player" ] = { ['save'] = false }
|
||||
ClassInfo[ "physgun_beam" ] = { ['save'] = false }
|
||||
ClassInfo[ "worldspawn" ] = { ['save'] = false }
|
||||
ClassInfo[ "player_manager" ] = { ['save'] = false }
|
||||
ClassInfo[ "bodyque" ] = { ['save'] = false }
|
||||
ClassInfo[ "info_player_start" ] = { ['save'] = false }
|
||||
ClassInfo[ "ai_hint" ] = { ['save'] = false }
|
||||
ClassInfo[ "ai_network" ] = { ['save'] = false }
|
||||
ClassInfo[ "light" ] = { ['save'] = false }
|
||||
ClassInfo[ "ai_network" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_tonemap_controller" ] = { ['save'] = false }
|
||||
ClassInfo[ "path_corner" ] = { ['save'] = false }
|
||||
ClassInfo[ "point_spotlight" ] = { ['save'] = false }
|
||||
ClassInfo[ "func_brush" ] = { ['save'] = false }
|
||||
ClassInfo[ "water_lod_control" ] = { ['save'] = false }
|
||||
ClassInfo[ "spotlight_end" ] = { ['save'] = false }
|
||||
ClassInfo[ "beam" ] = { ['save'] = false }
|
||||
ClassInfo[ "lua_run" ] = { ['save'] = false }
|
||||
ClassInfo[ "trigger_multiple" ] = { ['save'] = false }
|
||||
ClassInfo[ "func_button" ] = { ['save'] = false }
|
||||
ClassInfo[ "soundent" ] = { ['save'] = false }
|
||||
ClassInfo[ "sky_camera" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_fog_controller" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_sun" ] = { ['save'] = false }
|
||||
ClassInfo[ "phys_constraintsystem" ] = { ['save'] = false }
|
||||
ClassInfo[ "keyframe_rope" ] = { ['save'] = false }
|
||||
ClassInfo[ "logic_auto" ] = { ['save'] = false }
|
||||
ClassInfo[ "physics_npc_solver" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_sun" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_wind" ] = { ['save'] = false }
|
||||
ClassInfo[ "env_fog_controller" ] = { ['save'] = false }
|
||||
ClassInfo[ "infodecal" ] = { ['save'] = false }
|
||||
ClassInfo[ "info_projecteddecal" ] = { ['save'] = false }
|
||||
ClassInfo[ "info_node" ] = { ['save'] = false }
|
||||
ClassInfo[ "info_map_parameters" ] = { ['save'] = false }
|
||||
ClassInfo[ "info_ladder" ] = { ['save'] = false }
|
||||
ClassInfo[ "path_corner" ] = { ['save'] = false }
|
||||
ClassInfo[ "point_viewcontrol" ] = { ['save'] = false }
|
||||
ClassInfo[ "scene_manager" ] = { ['save'] = false }
|
||||
ClassInfo[ "shadow_control" ] = { ['save'] = false }
|
||||
ClassInfo[ "sky_camera" ] = { ['save'] = false }
|
||||
ClassInfo[ "soundent" ] = { ['save'] = false }
|
||||
|
||||
function gmsave.ShouldSaveEntity( ent, t )
|
||||
|
||||
local info = ClassInfo[ t.classname ]
|
||||
|
||||
--
|
||||
-- Filtered out - we don't want to save these entity types!
|
||||
--
|
||||
if ( info && info.save == false ) then return false end
|
||||
|
||||
--
|
||||
-- Should we save the parent entity?
|
||||
-- If not, don't save this!
|
||||
--
|
||||
local parent = ent:GetParent()
|
||||
if ( IsValid( parent ) ) then
|
||||
if ( !gmsave.ShouldSaveEntity( parent, parent:GetSaveTable() ) ) then return false end
|
||||
end
|
||||
|
||||
--
|
||||
-- If this is a weapon, and it has a valid owner.. don't save it!
|
||||
--
|
||||
if ( ent:IsWeapon() && IsValid( ent:GetOwner() ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
--
|
||||
-- Default action is to save..
|
||||
--
|
||||
return true
|
||||
|
||||
end
|
||||
106
lua/includes/gmsave/physics.lua
Normal file
106
lua/includes/gmsave/physics.lua
Normal file
@@ -0,0 +1,106 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Creates a save table for a single entity
|
||||
--
|
||||
function gmsave.PhysicsSave( ent )
|
||||
|
||||
if ( ent:GetPhysicsObjectCount() == 0 ) then return end
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k = 0, ent:GetPhysicsObjectCount() - 1 do
|
||||
|
||||
local obj = ent:GetPhysicsObjectNum( k )
|
||||
|
||||
tab[ k ] = {}
|
||||
tab[ k ].origin = tostring( obj:GetPos() )
|
||||
tab[ k ].angles = tostring( obj:GetAngles() )
|
||||
tab[ k ].mass = tostring( obj:GetMass() )
|
||||
tab[ k ].material = tostring( obj:GetMaterial() )
|
||||
if ( !obj:IsMotionEnabled() ) then tab[ k ].frozen = 1 end
|
||||
if ( !obj:IsCollisionEnabled() ) then tab[ k ].nocollide = 1 end
|
||||
if ( !obj:IsGravityEnabled() ) then tab[ k ].nogravity = 1 end
|
||||
if ( !obj:IsDragEnabled() ) then tab[ k ].nodrag = 1 end
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Creates a save table from a table of entities
|
||||
--
|
||||
function gmsave.PhysicsSaveList( ents )
|
||||
|
||||
local tabPhys = {}
|
||||
|
||||
for k, v in pairs( ents ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
tabPhys[ v.GMSaveName ] = gmsave.PhysicsSave( v )
|
||||
if ( tabPhys[ v.GMSaveName ] ) then
|
||||
tabPhys[ v.GMSaveName ].entity = v.GMSaveName
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tabPhys
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Creates a single entity from a table
|
||||
--
|
||||
function gmsave.PhysicsLoad( t, ent )
|
||||
|
||||
for k = 0, ent:GetPhysicsObjectCount() - 1 do
|
||||
|
||||
local tab = t[ k ]
|
||||
if ( !tab ) then continue end
|
||||
|
||||
local obj = ent:GetPhysicsObjectNum( k )
|
||||
if ( !IsValid( obj ) ) then continue end
|
||||
|
||||
obj:SetPos( Vector( tab.origin ) )
|
||||
obj:SetAngles( Angle( tab.angles ) )
|
||||
obj:SetMass( tab.mass )
|
||||
obj:SetMaterial( tab.material )
|
||||
|
||||
if ( tab.frozen ) then obj:EnableMotion( false ) end
|
||||
if ( tab.nocollide ) then obj:EnableCollisions( false ) end
|
||||
if ( tab.nogravity ) then obj:EnableGravity( false ) end
|
||||
if ( tab.nodrag ) then obj:EnableDrag( false ) end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Restores multiple entitys from a table
|
||||
--
|
||||
function gmsave.PhysicsLoadFromTable( tab, ents )
|
||||
|
||||
if ( !tab ) then return end
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
local ent = ents[ k ]
|
||||
if ( !IsValid( ent ) ) then continue end
|
||||
|
||||
gmsave.PhysicsLoad( v, ent )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
32
lua/includes/gmsave/player.lua
Normal file
32
lua/includes/gmsave/player.lua
Normal file
@@ -0,0 +1,32 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function gmsave.PlayerSave( ent )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.Origin = ent:GetPos()
|
||||
tab.Angle = ent:GetAimVector():Angle()
|
||||
tab.MoveType = ent:GetMoveType()
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function gmsave.PlayerLoad( ent, tab )
|
||||
|
||||
if ( tab == nil ) then return end
|
||||
|
||||
if ( tab.Origin ) then ent:SetPos( tab.Origin ) end
|
||||
if ( tab.Angle ) then ent:SetEyeAngles( tab.Angle ) end
|
||||
if ( tab.MoveType ) then ent:SetMoveType( tab.MoveType ) end
|
||||
|
||||
end
|
||||
67
lua/includes/gui/icon_progress.lua
Normal file
67
lua/includes/gui/icon_progress.lua
Normal file
@@ -0,0 +1,67 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local g_Progress = nil
|
||||
|
||||
hook.Add( "SpawniconGenerated", "SpawniconGenerated", function( lastmodel, imagename, modelsleft )
|
||||
|
||||
if ( !IsValid( g_Progress ) ) then
|
||||
|
||||
g_Progress = vgui.Create( "DPanel" )
|
||||
g_Progress:SetSize( 64 + 10, 64 + 10 + 20 )
|
||||
g_Progress:SetBackgroundColor( Color( 0, 0, 0, 100 ) )
|
||||
g_Progress:SetDrawOnTop( true )
|
||||
g_Progress:DockPadding( 5, 0, 5, 5 )
|
||||
g_Progress.Think = function()
|
||||
|
||||
if ( SysTime() - g_Progress.LastTouch < 3 ) then return end
|
||||
|
||||
g_Progress:Remove()
|
||||
g_Progress.LastTouch = SysTime()
|
||||
|
||||
end
|
||||
|
||||
local label = g_Progress:Add( "DLabel" )
|
||||
label:Dock( BOTTOM )
|
||||
label:SetText( "remaining" )
|
||||
label:SetTextColor( color_white )
|
||||
label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
label:SetContentAlignment( 5 )
|
||||
label:SetHeight( 14 )
|
||||
label:SetFont( "DefaultSmall" )
|
||||
|
||||
g_Progress.Label = g_Progress:Add( "DLabel" )
|
||||
g_Progress.Label:Dock( BOTTOM )
|
||||
g_Progress.Label:SetTextColor( color_white )
|
||||
g_Progress.Label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
g_Progress.Label:SetContentAlignment( 5 )
|
||||
g_Progress.Label:SetFont( "DermaDefaultBold" )
|
||||
g_Progress.Label:SetHeight( 14 )
|
||||
|
||||
g_Progress.icon = vgui.Create( "DImage", g_Progress )
|
||||
g_Progress.icon:SetSize( 64, 64 )
|
||||
g_Progress.icon:Dock( TOP )
|
||||
|
||||
end
|
||||
|
||||
g_Progress.LastTouch = SysTime()
|
||||
|
||||
imagename = imagename:Replace( "materials\\", "" )
|
||||
imagename = imagename:Replace( "materials/", "" )
|
||||
|
||||
g_Progress.icon:SetImage( imagename )
|
||||
|
||||
g_Progress:AlignRight( 10 )
|
||||
g_Progress:AlignBottom( 10 )
|
||||
|
||||
g_Progress.Label:SetText( modelsleft )
|
||||
|
||||
end )
|
||||
135
lua/includes/init.lua
Normal file
135
lua/includes/init.lua
Normal file
@@ -0,0 +1,135 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Non-Module includes
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include ( "util.lua" ) -- Misc Utilities
|
||||
include ( "util/sql.lua" ) -- Include sql here so it's
|
||||
-- available at loadtime to modules.
|
||||
|
||||
include( "extensions/net.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Shared Modules
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
require ( "baseclass" )
|
||||
require ( "concommand" ) -- Console Commands
|
||||
require ( "saverestore" ) -- Save/Restore
|
||||
require ( "hook" ) -- Gamemode hooks
|
||||
require ( "gamemode" ) -- Gamemode manager
|
||||
require ( "weapons" ) -- SWEP manager
|
||||
require ( "scripted_ents" ) -- Scripted Entities
|
||||
require ( "player_manager" ) -- Player models/class manager
|
||||
require ( "numpad" )
|
||||
require ( "team" )
|
||||
require ( "undo" )
|
||||
require ( "cleanup" )
|
||||
require ( "duplicator" )
|
||||
require ( "constraint" )
|
||||
require ( "construct" )
|
||||
require ( "usermessage" )
|
||||
require ( "list" )
|
||||
require ( "cvars" )
|
||||
require ( "http" )
|
||||
require ( "properties" )
|
||||
require ( "widget" )
|
||||
require ( "cookie" )
|
||||
require ( "utf8" )
|
||||
|
||||
require ( "drive" )
|
||||
include ( "drive/drive_base.lua" )
|
||||
include ( "drive/drive_noclip.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Serverside only modules
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
require( "ai_task" )
|
||||
require( "ai_schedule" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Clientside only modules
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
require ( "draw" ) -- 2D Draw library
|
||||
require ( "markup" ) -- Text markup library
|
||||
require ( "effects" )
|
||||
require ( "halo" )
|
||||
require ( "killicon" )
|
||||
require ( "spawnmenu" )
|
||||
require ( "controlpanel" )
|
||||
require ( "presets" )
|
||||
require ( "menubar" )
|
||||
require ( "matproxy" )
|
||||
|
||||
include( "util/model_database.lua" ) -- Store information on models as they're loaded
|
||||
include( "util/vgui_showlayout.lua" ) -- VGUI Performance Debug
|
||||
include( "util/tooltips.lua" )
|
||||
include( "util/client.lua" )
|
||||
include( "util/javascript_util.lua" )
|
||||
include( "util/workshop_files.lua" )
|
||||
include( "gui/icon_progress.lua" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Shared modules
|
||||
-----------------------------------------------------------]]
|
||||
include( "gmsave.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Extensions
|
||||
|
||||
Load extensions that we specifically need for the menu,
|
||||
to reduce the chances of loading something that might
|
||||
cause errors.
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include ( "extensions/file.lua" )
|
||||
include ( "extensions/angle.lua" )
|
||||
include ( "extensions/debug.lua" )
|
||||
include ( "extensions/entity.lua" )
|
||||
include ( "extensions/ents.lua" )
|
||||
include ( "extensions/math.lua" )
|
||||
include ( "extensions/player.lua" )
|
||||
include ( "extensions/player_auth.lua" )
|
||||
include ( "extensions/string.lua" )
|
||||
include ( "extensions/table.lua" )
|
||||
include ( "extensions/util.lua" )
|
||||
include ( "extensions/vector.lua" )
|
||||
include ( "extensions/game.lua" )
|
||||
include ( "extensions/motionsensor.lua" )
|
||||
include ( "extensions/weapon.lua" )
|
||||
include ( "extensions/coroutine.lua" )
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
include ( "extensions/client/entity.lua" )
|
||||
include ( "extensions/client/globals.lua" )
|
||||
include ( "extensions/client/panel.lua" )
|
||||
include ( "extensions/client/player.lua" )
|
||||
include ( "extensions/client/render.lua" )
|
||||
|
||||
require ( "search" )
|
||||
|
||||
end
|
||||
|
||||
57
lua/includes/init_menu.lua
Normal file
57
lua/includes/init_menu.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Non-Module includes
|
||||
-----------------------------------------------------------]]
|
||||
include( "util.lua" )
|
||||
include( "util/sql.lua" ) -- Include sql here so it's available at loadtime to modules.
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Modules
|
||||
-----------------------------------------------------------]]
|
||||
require( "concommand" )
|
||||
require( "list" )
|
||||
require( "hook" )
|
||||
require( "draw" )
|
||||
require( "http" )
|
||||
require( "cvars" )
|
||||
require( "cookie" )
|
||||
require( "baseclass" )
|
||||
require( "utf8" )
|
||||
require( "markup" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Extensions
|
||||
|
||||
Load extensions that we specifically need for the menu,
|
||||
to reduce the chances of loading something that might
|
||||
cause errors.
|
||||
-----------------------------------------------------------]]
|
||||
include( "extensions/string.lua" )
|
||||
include( "extensions/table.lua" )
|
||||
include( "extensions/math.lua" )
|
||||
include( "extensions/client/panel.lua" )
|
||||
include( "extensions/util.lua" )
|
||||
include( "extensions/file.lua" )
|
||||
include( "extensions/debug.lua" )
|
||||
include( "extensions/client/render.lua" )
|
||||
include( "extensions/client/globals.lua" )
|
||||
|
||||
include( "util/vgui_showlayout.lua" )
|
||||
include( "util/workshop_files.lua" )
|
||||
include( "util/javascript_util.lua" )
|
||||
include( "util/tooltips.lua" )
|
||||
|
||||
require( "notification" )
|
||||
|
||||
include( "menu/derma_icon_browser.lua" )
|
||||
19
lua/includes/menu.lua
Normal file
19
lua/includes/menu.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--=============================================================================--
|
||||
-- ___ ___ _ _ _ __ _ ___ ___ __ __
|
||||
-- |_ _|| __| / \ | \_/ | / _| / \ | o \ o \\ V /
|
||||
-- | | | _| | o || \_/ | ( |_n| o || / / \ /
|
||||
-- |_| |___||_n_||_| |_| \__/|_n_||_|\\_|\\ |_| 2007
|
||||
--
|
||||
--=============================================================================--
|
||||
|
||||
include( "menu/menu.lua" )
|
||||
108
lua/includes/modules/ai_schedule.lua
Normal file
108
lua/includes/modules/ai_schedule.lua
Normal file
@@ -0,0 +1,108 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Serverside only.
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local tostring = tostring
|
||||
local table = table
|
||||
local ai_task = ai_task
|
||||
|
||||
module( "ai_schedule" )
|
||||
|
||||
-- Define the Schedule object
|
||||
|
||||
local Schedule = {}
|
||||
Schedule.__index = Schedule
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Init
|
||||
Sets the object up. Called automatically from ai_schedule.new.
|
||||
-----------------------------------------------------------]]
|
||||
function Schedule:Init( _debugname_ )
|
||||
|
||||
self.DebugName = tostring( _debugname_ )
|
||||
self.Tasks = {}
|
||||
self.TaskCount = 0
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Adds an engine task to the schedule
|
||||
|
||||
schd:EngTask( "TASK_TARGET_PLAYER", 0 )
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function Schedule:EngTask( _taskname_, _taskdata_ )
|
||||
|
||||
local NewTask = ai_task.New()
|
||||
NewTask:InitEngine( _taskname_, _taskdata_ )
|
||||
self.TaskCount = table.insert( self.Tasks, NewTask )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Adds Lua NPC task to the schedule
|
||||
|
||||
schdChase:AddTask( "LookForPlayer", "AnyDataYouWant" )
|
||||
|
||||
will call the functions
|
||||
|
||||
NPC:TaskStart_LookForPlayer( "AnyDataYouWant" ) - once on start
|
||||
NPC:Task_LookForPlayer( "AnyDataYouWant" ) - every think until TaskComplete
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function Schedule:AddTask( _functionname_, _data_ )
|
||||
|
||||
local NewTask = ai_task.New()
|
||||
NewTask:InitFunctionName( "TaskStart_" .. _functionname_, "Task_" .. _functionname_, _data_ )
|
||||
self.TaskCount = table.insert( self.Tasks, NewTask )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
The same as above but you get to specify the exact
|
||||
function name to call
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function Schedule:AddTaskEx( _start, _run, _data_ )
|
||||
|
||||
local NewTask = ai_task.New()
|
||||
NewTask:InitFunctionName( _start, _run, _data_ )
|
||||
self.TaskCount = table.insert( self.Tasks, NewTask )
|
||||
|
||||
end
|
||||
|
||||
function Schedule:NumTasks()
|
||||
return self.TaskCount
|
||||
end
|
||||
|
||||
function Schedule:GetTask( num )
|
||||
return self.Tasks[ num ]
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Create a new empty task (this is ai_schedule.New )
|
||||
-----------------------------------------------------------]]
|
||||
function New( debugname )
|
||||
|
||||
local pNewSchedule = {}
|
||||
setmetatable( pNewSchedule, Schedule )
|
||||
|
||||
pNewSchedule:Init( debugname )
|
||||
|
||||
return pNewSchedule
|
||||
|
||||
end
|
||||
133
lua/includes/modules/ai_task.lua
Normal file
133
lua/includes/modules/ai_task.lua
Normal file
@@ -0,0 +1,133 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Serverside only.
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
local setmetatable = setmetatable
|
||||
--local table = table
|
||||
local ai = ai
|
||||
|
||||
module( "ai_task" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
ENUMs for which kind of task it is.
|
||||
-----------------------------------------------------------]]
|
||||
local TYPE_ENGINE = 1
|
||||
local TYPE_FNAME = 2
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Keep track of created tasks
|
||||
UNDONE: There's no need for this right now.
|
||||
-----------------------------------------------------------]]
|
||||
--local Task_Index = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Task metatable
|
||||
-----------------------------------------------------------]]
|
||||
local Task = {}
|
||||
Task.__index = Task
|
||||
|
||||
function Task:Init()
|
||||
self.Type = nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Creates an engine based task
|
||||
-----------------------------------------------------------]]
|
||||
function Task:InitEngine( _taskname_, _taskdata_ )
|
||||
|
||||
self.TaskName = _taskname_
|
||||
self.TaskID = nil
|
||||
self.TaskData = _taskdata_
|
||||
self.Type = TYPE_ENGINE
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Creates an engine based task
|
||||
-----------------------------------------------------------]]
|
||||
function Task:InitFunctionName( _start, _end, _taskdata_ )
|
||||
self.StartFunctionName = _start
|
||||
self.FunctionName = _end
|
||||
self.TaskData = _taskdata_
|
||||
self.Type = TYPE_FNAME
|
||||
end
|
||||
|
||||
function Task:IsEngineType()
|
||||
return ( self.Type == TYPE_ENGINE )
|
||||
end
|
||||
|
||||
function Task:IsFNameType()
|
||||
return ( self.Type == TYPE_FNAME )
|
||||
end
|
||||
|
||||
function Task:Start( npc )
|
||||
|
||||
if ( self:IsFNameType() ) then self:Start_FName( npc ) return end
|
||||
|
||||
if ( self:IsEngineType() ) then
|
||||
|
||||
if ( !self.TaskID ) then self.TaskID = ai.GetTaskID( self.TaskName ) end
|
||||
|
||||
npc:StartEngineTask( self.TaskID, self.TaskData )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Start_FName (called from Task:Start)
|
||||
-----------------------------------------------------------]]
|
||||
function Task:Start_FName( npc )
|
||||
|
||||
if ( !self.StartFunctionName ) then return end
|
||||
--if ( !npc[ self.StartFunctionName ] ) then return end
|
||||
|
||||
-- Run the start function. Safely.
|
||||
npc[ self.StartFunctionName ]( npc, self.TaskData )
|
||||
|
||||
end
|
||||
|
||||
function Task:Run( npc )
|
||||
|
||||
if ( self:IsFNameType() ) then self:Run_FName( npc ) return end
|
||||
|
||||
if ( self:IsEngineType() ) then
|
||||
npc:RunEngineTask( self.TaskID, self.TaskData )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Task:Run_FName( npc )
|
||||
|
||||
if ( !self.FunctionName ) then return end
|
||||
--if (!npc[ self.StartFunctionName ]) then return end
|
||||
|
||||
-- Run the start function. Safely.
|
||||
npc[ self.FunctionName ]( npc, self.TaskData )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Create a new empty task (this is ai_task.New )
|
||||
-----------------------------------------------------------]]
|
||||
function New()
|
||||
|
||||
local pNewTask = {}
|
||||
setmetatable( pNewTask, Task )
|
||||
|
||||
pNewTask:Init()
|
||||
|
||||
--table.insert( Task_Index, pNewTask )
|
||||
|
||||
return pNewTask
|
||||
|
||||
end
|
||||
75
lua/includes/modules/ai_vj_schedule.lua
Normal file
75
lua/includes/modules/ai_vj_schedule.lua
Normal file
@@ -0,0 +1,75 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
/*--------------------------------------------------
|
||||
=============== VJ AI Schedule Module ===============
|
||||
*** Copyright (c) 2012-2023 by DrVrej, All rights reserved. ***
|
||||
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
|
||||
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
|
||||
INFO: This is mostly Garry's code, except I improved and organized.
|
||||
NOTES: This is server side only!
|
||||
--------------------------------------------------*/
|
||||
if CLIENT then return end
|
||||
|
||||
print("VJ Base A.I. module initialized!")
|
||||
|
||||
local setmetatable = setmetatable
|
||||
local tostring = tostring
|
||||
local table = table
|
||||
|
||||
require("ai_vj_task")
|
||||
local ai_vj_task = ai_vj_task
|
||||
module("ai_vj_schedule")
|
||||
|
||||
local Schedule = {}
|
||||
Schedule.__index = Schedule
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:Init(_debugname_)
|
||||
self.DebugName = tostring(_debugname_)
|
||||
self.Tasks = {}
|
||||
self.TaskCount = 0
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:EngTask(_taskname_,_taskdata_)
|
||||
local NewTask = ai_vj_task.New()
|
||||
NewTask:InitEngine(_taskname_,_taskdata_)
|
||||
table.insert(self.Tasks,NewTask)
|
||||
self.TaskCount = self.TaskCount + 1
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:AddTask(_functionname_,_data_)
|
||||
local NewTask = ai_vj_task.New()
|
||||
NewTask:InitFunctionName("TaskStart_".._functionname_,"Task_".._functionname_,_data_)
|
||||
table.insert(self.Tasks,NewTask)
|
||||
//print(self.TaskCount.." AddTask has ran!")
|
||||
self.TaskCount = self.TaskCount + 1 -- Or else it will make an error saying NumTasks is a nil value
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:AddTaskEx(_start,_run,_data_)
|
||||
local NewTask = ai_vj_task.New()
|
||||
NewTask:InitFunctionName(_start, _run, _data_)
|
||||
table.insert(self.Tasks,NewTask)
|
||||
self.TaskCount = self.TaskCount + 2 -- Or else it will make an error saying NumTasks is a nil value
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:NumTasks()
|
||||
return self.TaskCount
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Schedule:GetTask(num)
|
||||
return self.Tasks[num]
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function New(debugname)
|
||||
local pNewSchedule = {}
|
||||
setmetatable(pNewSchedule,Schedule)
|
||||
pNewSchedule:Init(debugname)
|
||||
return pNewSchedule
|
||||
end
|
||||
243
lua/includes/modules/ai_vj_task.lua
Normal file
243
lua/includes/modules/ai_vj_task.lua
Normal file
@@ -0,0 +1,243 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
/*--------------------------------------------------
|
||||
=============== VJ AI Task Module ===============
|
||||
*** Copyright (c) 2012-2023 by DrVrej, All rights reserved. ***
|
||||
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
|
||||
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
|
||||
INFO: This is mostly Garry's code, except I improved and organized.
|
||||
NOTES: This is server side only!
|
||||
NOTES: A lot of the fix is from: https://github.com/garrynewman/garrysmod/pull/524
|
||||
--------------------------------------------------*/
|
||||
if CLIENT then return end
|
||||
|
||||
local setmetatable = setmetatable
|
||||
|
||||
local TaskList = {
|
||||
["TASK_INVALID"] = 0,
|
||||
["TASK_RESET_ACTIVITY"] = 1,
|
||||
["TASK_WAIT"] = 2,
|
||||
["TASK_ANNOUNCE_ATTACK"] = 3,
|
||||
["TASK_WAIT_FACE_ENEMY"] = 4,
|
||||
["TASK_WAIT_FACE_ENEMY_RANDOM"] = 5,
|
||||
["TASK_WAIT_PVS"] = 6,
|
||||
["TASK_SUGGEST_STATE"] = 7,
|
||||
["TASK_TARGET_PLAYER"] = 8,
|
||||
["TASK_SCRIPT_WALK_TO_TARGET"] = 9,
|
||||
["TASK_SCRIPT_RUN_TO_TARGET"] = 10,
|
||||
["TASK_SCRIPT_CUSTOM_MOVE_TO_TARGET"] = 11,
|
||||
["TASK_MOVE_TO_TARGET_RANGE"] = 12,
|
||||
["TASK_MOVE_TO_GOAL_RANGE"] = 13,
|
||||
["TASK_MOVE_AWAY_PATH"] = 14,
|
||||
["TASK_GET_PATH_AWAY_FROM_BEST_SOUND"] = 15,
|
||||
["TASK_SET_GOAL"] = 16,
|
||||
["TASK_GET_PATH_TO_GOAL"] = 17,
|
||||
["TASK_GET_PATH_TO_ENEMY"] = 18,
|
||||
["TASK_GET_PATH_TO_ENEMY_LKP"] = 19,
|
||||
["TASK_GET_CHASE_PATH_TO_ENEMY"] = 20,
|
||||
["TASK_GET_PATH_TO_ENEMY_LKP_LOS"] = 21,
|
||||
["TASK_GET_PATH_TO_ENEMY_CORPSE"] = 22,
|
||||
["TASK_GET_PATH_TO_PLAYER"] = 23,
|
||||
["TASK_GET_PATH_TO_ENEMY_LOS"] = 24,
|
||||
["TASK_GET_FLANK_RADIUS_PATH_TO_ENEMY_LOS"] = 25,
|
||||
["TASK_GET_FLANK_ARC_PATH_TO_ENEMY_LOS"] = 26,
|
||||
["TASK_GET_PATH_TO_RANGE_ENEMY_LKP_LOS"] = 27,
|
||||
["TASK_GET_PATH_TO_TARGET"] = 28,
|
||||
["TASK_GET_PATH_TO_TARGET_WEAPON"] = 29,
|
||||
["TASK_CREATE_PENDING_WEAPON"] = 30,
|
||||
["TASK_GET_PATH_TO_HINTNODE"] = 31,
|
||||
["TASK_STORE_LASTPOSITION"] = 32,
|
||||
["TASK_CLEAR_LASTPOSITION"] = 33,
|
||||
["TASK_STORE_POSITION_IN_SAVEPOSITION"] = 34,
|
||||
["TASK_STORE_BESTSOUND_IN_SAVEPOSITION"] = 35,
|
||||
["TASK_STORE_BESTSOUND_REACTORIGIN_IN_SAVEPOSITION"] = 36,
|
||||
["TASK_REACT_TO_COMBAT_SOUND"] = 37,
|
||||
["TASK_STORE_ENEMY_POSITION_IN_SAVEPOSITION"] = 38,
|
||||
["TASK_GET_PATH_TO_COMMAND_GOAL"] = 39,
|
||||
["TASK_MARK_COMMAND_GOAL_POS"] = 40,
|
||||
["TASK_CLEAR_COMMAND_GOAL"] = 41,
|
||||
["TASK_GET_PATH_TO_LASTPOSITION"] = 42,
|
||||
["TASK_GET_PATH_TO_SAVEPOSITION"] = 43,
|
||||
["TASK_GET_PATH_TO_SAVEPOSITION_LOS"] = 44,
|
||||
["TASK_GET_PATH_TO_RANDOM_NODE"] = 45,
|
||||
["TASK_GET_PATH_TO_BESTSOUND"] = 46,
|
||||
["TASK_GET_PATH_TO_BESTSCENT"] = 47,
|
||||
["TASK_RUN_PATH"] = 48,
|
||||
["TASK_WALK_PATH"] = 49,
|
||||
["TASK_WALK_PATH_TIMED"] = 50,
|
||||
["TASK_WALK_PATH_WITHIN_DIST"] = 51,
|
||||
["TASK_WALK_PATH_FOR_UNITS"] = 52,
|
||||
["TASK_RUN_PATH_FLEE"] = 53,
|
||||
["TASK_RUN_PATH_TIMED"] = 54,
|
||||
["TASK_RUN_PATH_FOR_UNITS"] = 55,
|
||||
["TASK_RUN_PATH_WITHIN_DIST"] = 56,
|
||||
["TASK_STRAFE_PATH"] = 57,
|
||||
["TASK_CLEAR_MOVE_WAIT"] = 58,
|
||||
["TASK_SMALL_FLINCH"] = 59,
|
||||
["TASK_BIG_FLINCH"] = 60,
|
||||
["TASK_DEFER_DODGE"] = 61,
|
||||
["TASK_FACE_IDEAL"] = 62,
|
||||
["TASK_FACE_REASONABLE"] = 63,
|
||||
["TASK_FACE_PATH"] = 64,
|
||||
["TASK_FACE_PLAYER"] = 65,
|
||||
["TASK_FACE_ENEMY"] = 66,
|
||||
["TASK_FACE_HINTNODE"] = 67,
|
||||
["TASK_PLAY_HINT_ACTIVITY"] = 68,
|
||||
["TASK_FACE_TARGET"] = 69,
|
||||
["TASK_FACE_LASTPOSITION"] = 70,
|
||||
["TASK_FACE_SAVEPOSITION"] = 71,
|
||||
["TASK_FACE_AWAY_FROM_SAVEPOSITION"] = 72,
|
||||
["TASK_SET_IDEAL_YAW_TO_CURRENT"] = 73,
|
||||
["TASK_RANGE_ATTACK1"] = 74,
|
||||
["TASK_RANGE_ATTACK2"] = 75,
|
||||
["TASK_MELEE_ATTACK1"] = 76,
|
||||
["TASK_MELEE_ATTACK2"] = 77,
|
||||
["TASK_RELOAD"] = 78,
|
||||
["TASK_SPECIAL_ATTACK1"] = 79,
|
||||
["TASK_SPECIAL_ATTACK2"] = 80,
|
||||
["TASK_FIND_HINTNODE"] = 81,
|
||||
["TASK_FIND_LOCK_HINTNODE"] = 82,
|
||||
["TASK_CLEAR_HINTNODE"] = 83,
|
||||
["TASK_LOCK_HINTNODE"] = 84,
|
||||
["TASK_SOUND_ANGRY"] = 85,
|
||||
["TASK_SOUND_DEATH"] = 86,
|
||||
["TASK_SOUND_IDLE"] = 87,
|
||||
["TASK_SOUND_WAKE"] = 88,
|
||||
["TASK_SOUND_PAIN"] = 89,
|
||||
["TASK_SOUND_DIE"] = 90,
|
||||
["TASK_SPEAK_SENTENCE"] = 91,
|
||||
["TASK_WAIT_FOR_SPEAK_FINISH"] = 92,
|
||||
["TASK_SET_ACTIVITY"] = 93,
|
||||
["TASK_RANDOMIZE_FRAMERATE"] = 94,
|
||||
["TASK_SET_SCHEDULE"] = 95,
|
||||
["TASK_SET_FAIL_SCHEDULE"] = 96,
|
||||
["TASK_SET_TOLERANCE_DISTANCE"] = 97,
|
||||
["TASK_SET_ROUTE_SEARCH_TIME"] = 98,
|
||||
["TASK_CLEAR_FAIL_SCHEDULE"] = 99,
|
||||
["TASK_PLAY_SEQUENCE"] = 100,
|
||||
["TASK_PLAY_PRIVATE_SEQUENCE"] = 101,
|
||||
["TASK_PLAY_PRIVATE_SEQUENCE_FACE_ENEMY"] = 102,
|
||||
["TASK_PLAY_SEQUENCE_FACE_ENEMY"] = 103,
|
||||
["TASK_PLAY_SEQUENCE_FACE_TARGET"] = 104,
|
||||
["TASK_FIND_COVER_FROM_BEST_SOUND"] = 105,
|
||||
["TASK_FIND_COVER_FROM_ENEMY"] = 106,
|
||||
["TASK_FIND_LATERAL_COVER_FROM_ENEMY"] = 107,
|
||||
["TASK_FIND_BACKAWAY_FROM_SAVEPOSITION"] = 108,
|
||||
["TASK_FIND_NODE_COVER_FROM_ENEMY"] = 109,
|
||||
["TASK_FIND_NEAR_NODE_COVER_FROM_ENEMY"] = 110,
|
||||
["TASK_FIND_FAR_NODE_COVER_FROM_ENEMY"] = 111,
|
||||
["TASK_FIND_COVER_FROM_ORIGIN"] = 112,
|
||||
["TASK_DIE"] = 113,
|
||||
["TASK_WAIT_FOR_SCRIPT"] = 114,
|
||||
["TASK_PUSH_SCRIPT_ARRIVAL_ACTIVITY"] = 115,
|
||||
["TASK_PLAY_SCRIPT"] = 116,
|
||||
["TASK_PLAY_SCRIPT_POST_IDLE"] = 117,
|
||||
["TASK_ENABLE_SCRIPT"] = 118,
|
||||
["TASK_PLANT_ON_SCRIPT"] = 119,
|
||||
["TASK_FACE_SCRIPT"] = 120,
|
||||
["TASK_PLAY_SCENE"] = 121,
|
||||
["TASK_WAIT_RANDOM"] = 122,
|
||||
["TASK_WAIT_INDEFINITE"] = 123,
|
||||
["TASK_STOP_MOVING"] = 124,
|
||||
["TASK_TURN_LEFT"] = 125,
|
||||
["TASK_TURN_RIGHT"] = 126,
|
||||
["TASK_REMEMBER"] = 127,
|
||||
["TASK_FORGET"] = 128,
|
||||
["TASK_WAIT_FOR_MOVEMENT"] = 129,
|
||||
["TASK_WAIT_FOR_MOVEMENT_STEP"] = 130,
|
||||
["TASK_WAIT_UNTIL_NO_DANGER_SOUND"] = 131,
|
||||
["TASK_WEAPON_FIND"] = 132,
|
||||
["TASK_WEAPON_PICKUP"] = 133,
|
||||
["TASK_WEAPON_RUN_PATH"] = 134,
|
||||
["TASK_WEAPON_CREATE"] = 135,
|
||||
["TASK_ITEM_PICKUP"] = 136,
|
||||
["TASK_ITEM_RUN_PATH"] = 137,
|
||||
["TASK_USE_SMALL_HULL"] = 138,
|
||||
["TASK_FALL_TO_GROUND"] = 139,
|
||||
["TASK_WANDER"] = 140,
|
||||
["TASK_FREEZE"] = 141,
|
||||
["TASK_GATHER_CONDITIONS"] = 142,
|
||||
["TASK_IGNORE_OLD_ENEMIES"] = 143,
|
||||
["TASK_DEBUG_BREAK"] = 144,
|
||||
["TASK_ADD_HEALTH"] = 145,
|
||||
["TASK_ADD_GESTURE_WAIT"] = 146,
|
||||
["TASK_ADD_GESTURE"] = 147,
|
||||
["TASK_GET_PATH_TO_INTERACTION_PARTNER"] = 148,
|
||||
["TASK_PRE_SCRIPT"] = 149,
|
||||
}
|
||||
|
||||
GetTaskList = function(name) return TaskList[name] or TaskList[0] end
|
||||
local GetTaskID = GetTaskList
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
module("ai_vj_task")
|
||||
|
||||
local TYPE_ENGINE = 1
|
||||
local TYPE_FNAME = 2
|
||||
local Task = {}
|
||||
Task.__index = Task
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:Init()
|
||||
self.Type = nil
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:InitEngine(_taskname_, _taskdata_)
|
||||
self.TaskName = _taskname_
|
||||
self.TaskID = nil
|
||||
self.TaskData = _taskdata_
|
||||
self.Type = TYPE_ENGINE
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:InitFunctionName(_start, _end, _taskdata_)
|
||||
self.StartFunctionName = _start
|
||||
self.FunctionName = _end
|
||||
self.TaskData = _taskdata_
|
||||
self.Type = TYPE_FNAME
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:IsEngineType()
|
||||
return self.Type == TYPE_ENGINE
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:IsFNameType()
|
||||
return self.Type == TYPE_FNAME
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:Start(npc)
|
||||
if (self:IsFNameType()) then self:Start_FName(npc) return end
|
||||
if (self:IsEngineType()) then
|
||||
if (!self.TaskID) then self.TaskID = GetTaskID(self.TaskName) end
|
||||
npc:StartEngineTask(self.TaskID,self.TaskData or 0)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:Start_FName(npc)
|
||||
if (!self.StartFunctionName) then return end
|
||||
npc[self.StartFunctionName](npc, self.TaskData)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:Run(npc)
|
||||
if (self:IsFNameType()) then self:Run_FName(npc) return end
|
||||
if (self:IsEngineType()) then
|
||||
npc:RunEngineTask(self.TaskID, self.TaskData or 0)
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function Task:Run_FName(npc)
|
||||
if (!self.FunctionName) then return end
|
||||
npc[self.FunctionName](npc,self.TaskData)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
function New()
|
||||
local pNewTask = {}
|
||||
setmetatable(pNewTask, Task)
|
||||
pNewTask:Init()
|
||||
return pNewTask
|
||||
end
|
||||
68
lua/includes/modules/baseclass.lua
Normal file
68
lua/includes/modules/baseclass.lua
Normal file
@@ -0,0 +1,68 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- The baseclass module uses upvalues to give the impression of inheritence.
|
||||
--
|
||||
-- At the top of your class file add
|
||||
--
|
||||
-- DEFINE_BASECLASS( "base_class_name" )
|
||||
--
|
||||
-- Now the local variable BaseClass will be available.
|
||||
-- ( in engine DEFINE_BASECLASS is replaced with "local BaseClass = baseclass.Get" )
|
||||
--
|
||||
-- Baseclasses are added using baseclass.Set - this is done automatically for:
|
||||
--
|
||||
-- > widgets
|
||||
-- > panels
|
||||
-- > drive modes
|
||||
-- > entities
|
||||
-- > weapons
|
||||
--
|
||||
-- Classes don't have to be created in any particular order. The system is
|
||||
-- designed to work with whatever order the classes are defined.
|
||||
--
|
||||
-- The only caveat is that classnames must be unique.
|
||||
-- eg Creating a panel and widget with the same name will cause problems.
|
||||
--
|
||||
|
||||
module( "baseclass", package.seeall )
|
||||
|
||||
local BaseClassTable = {}
|
||||
|
||||
function Get( name )
|
||||
|
||||
if ( ENT ) then ENT.Base = name end
|
||||
if ( SWEP ) then SWEP.Base = name end
|
||||
|
||||
BaseClassTable[name] = BaseClassTable[name] or {}
|
||||
|
||||
return BaseClassTable[name]
|
||||
|
||||
end
|
||||
|
||||
function Set( name, tab )
|
||||
|
||||
if ( !BaseClassTable[name] ) then
|
||||
|
||||
BaseClassTable[name] = tab
|
||||
|
||||
else
|
||||
|
||||
table.Merge( BaseClassTable[name], tab )
|
||||
setmetatable( BaseClassTable[name], getmetatable(tab) )
|
||||
|
||||
end
|
||||
|
||||
BaseClassTable[name].ThisClass = name
|
||||
|
||||
end
|
||||
251
lua/includes/modules/cleanup.lua
Normal file
251
lua/includes/modules/cleanup.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "cleanup", package.seeall )
|
||||
|
||||
local cleanup_types = {}
|
||||
|
||||
local function IsType( type )
|
||||
|
||||
for key, val in pairs( cleanup_types ) do
|
||||
|
||||
if ( val == type ) then return true end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function Register( type )
|
||||
|
||||
if ( type == "all" ) then return end
|
||||
|
||||
for key, val in pairs( cleanup_types ) do
|
||||
|
||||
if val == type then return end
|
||||
|
||||
end
|
||||
|
||||
table.insert( cleanup_types, type )
|
||||
|
||||
end
|
||||
|
||||
function GetTable()
|
||||
return cleanup_types
|
||||
end
|
||||
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
local cleanup_list = {}
|
||||
|
||||
function GetList()
|
||||
return cleanup_list
|
||||
end
|
||||
|
||||
local function Save( save )
|
||||
|
||||
saverestore.WriteTable( cleanup_list, save )
|
||||
|
||||
end
|
||||
|
||||
local function Restore( restore )
|
||||
|
||||
cleanup_list = saverestore.ReadTable( restore )
|
||||
|
||||
end
|
||||
|
||||
saverestore.AddSaveHook( "CleanupTable", Save )
|
||||
saverestore.AddRestoreHook( "CleanupTable", Restore )
|
||||
|
||||
function Add( pl, type, ent )
|
||||
|
||||
if ( !ent ) then return end
|
||||
|
||||
if ( !IsType( type ) ) then return end
|
||||
|
||||
local id = pl:UniqueID()
|
||||
|
||||
cleanup_list[ id ] = cleanup_list[ id ] or {}
|
||||
cleanup_list[ id ][ type ] = cleanup_list[ id ][ type ] or {}
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
table.insert( cleanup_list[ id ][ type ], ent )
|
||||
|
||||
end
|
||||
|
||||
function ReplaceEntity( from, to )
|
||||
|
||||
local ActionTaken = false
|
||||
|
||||
for _, PlayerTable in pairs( cleanup_list ) do
|
||||
for _, TypeTable in pairs( PlayerTable ) do
|
||||
for key, ent in pairs( TypeTable ) do
|
||||
|
||||
if ( ent == from ) then
|
||||
TypeTable[ key ] = to
|
||||
ActionTaken = true
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ActionTaken
|
||||
|
||||
end
|
||||
|
||||
|
||||
function CC_Cleanup( pl, command, args )
|
||||
|
||||
if ( !IsValid( pl ) ) then return end
|
||||
|
||||
local id = pl:UniqueID()
|
||||
|
||||
if ( !cleanup_list[ id ] ) then return end
|
||||
|
||||
if ( !args[ 1 ] ) then
|
||||
|
||||
local count = 0
|
||||
|
||||
for key, val in pairs( cleanup_list[ id ] ) do
|
||||
|
||||
for _, ent in pairs( val ) do
|
||||
|
||||
if ( IsValid( ent ) ) then ent:Remove() end
|
||||
count = count + 1
|
||||
|
||||
end
|
||||
|
||||
table.Empty( val )
|
||||
|
||||
end
|
||||
|
||||
-- Send tooltip command to client
|
||||
if ( count > 0 ) then
|
||||
pl:SendLua( "hook.Run('OnCleanup','all')" )
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( !IsType( args[1] ) ) then return end
|
||||
if ( !cleanup_list[id][ args[1] ] ) then return end
|
||||
|
||||
for key, ent in pairs( cleanup_list[id][ args[1] ] ) do
|
||||
|
||||
if ( IsValid( ent ) ) then ent:Remove() end
|
||||
|
||||
end
|
||||
|
||||
table.Empty( cleanup_list[id][ args[1] ] )
|
||||
|
||||
-- Send tooltip command to client
|
||||
pl:SendLua( string.format( "hook.Run('OnCleanup',%q)", args[1] ) )
|
||||
|
||||
end
|
||||
|
||||
function CC_AdminCleanup( pl, command, args )
|
||||
|
||||
if ( IsValid( pl ) && !pl:IsAdmin() ) then return end
|
||||
|
||||
if ( !args[ 1 ] ) then
|
||||
|
||||
for key, ply in pairs( cleanup_list ) do
|
||||
|
||||
for _, type in pairs( ply ) do
|
||||
|
||||
for __, ent in pairs( type ) do
|
||||
|
||||
if ( IsValid( ent ) ) then ent:Remove() end
|
||||
|
||||
end
|
||||
|
||||
table.Empty( type )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
game.CleanUpMap( false, nil, function()
|
||||
-- Send tooltip command to client
|
||||
if ( IsValid( pl ) ) then pl:SendLua( "hook.Run('OnCleanup','all')" ) end
|
||||
end )
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
if ( !IsType( args[ 1 ] ) ) then return end
|
||||
|
||||
for key, ply in pairs( cleanup_list ) do
|
||||
|
||||
if ( ply[ args[ 1 ] ] != nil ) then
|
||||
|
||||
for id, ent in pairs( ply[ args[ 1 ] ] ) do
|
||||
|
||||
if ( IsValid( ent ) ) then ent:Remove() end
|
||||
|
||||
end
|
||||
|
||||
table.Empty( ply[ args[ 1 ] ] )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Send tooltip command to client
|
||||
if ( IsValid( pl ) ) then pl:SendLua( string.format( "hook.Run('OnCleanup',%q)", args[1] ) ) end
|
||||
|
||||
end
|
||||
|
||||
concommand.Add( "gmod_cleanup", CC_Cleanup, nil, "", { FCVAR_DONTRECORD } )
|
||||
concommand.Add( "gmod_admin_cleanup", CC_AdminCleanup, nil, "", { FCVAR_DONTRECORD } )
|
||||
|
||||
else
|
||||
|
||||
function UpdateUI()
|
||||
|
||||
local cleanup_types_s = {}
|
||||
for id, val in pairs( cleanup_types ) do
|
||||
cleanup_types_s[ language.GetPhrase( "Cleanup_" .. val ) ] = val
|
||||
end
|
||||
|
||||
local Panel = controlpanel.Get( "User_Cleanup" )
|
||||
if ( IsValid( Panel ) ) then
|
||||
Panel:Clear()
|
||||
Panel:AddControl( "Header", { Description = "#spawnmenu.utilities.cleanup.help" } )
|
||||
Panel:Button( "#CleanupAll", "gmod_cleanup" )
|
||||
|
||||
for key, val in SortedPairs( cleanup_types_s ) do
|
||||
Panel:Button( key, "gmod_cleanup", val )
|
||||
end
|
||||
end
|
||||
|
||||
local AdminPanel = controlpanel.Get( "Admin_Cleanup" )
|
||||
if ( IsValid( AdminPanel ) ) then
|
||||
AdminPanel:Clear()
|
||||
AdminPanel:AddControl( "Header", { Description = "#spawnmenu.utilities.cleanup.help" } )
|
||||
AdminPanel:Button( "#CleanupAll", "gmod_admin_cleanup" )
|
||||
|
||||
for key, val in SortedPairs( cleanup_types_s ) do
|
||||
AdminPanel:Button( key, "gmod_admin_cleanup", val )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PostReloadToolsMenu", "BuildCleanupUI", UpdateUI )
|
||||
|
||||
end
|
||||
85
lua/includes/modules/concommand.lua
Normal file
85
lua/includes/modules/concommand.lua
Normal file
@@ -0,0 +1,85 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local AddConsoleCommand = AddConsoleCommand
|
||||
local string = string
|
||||
local Msg = Msg
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand
|
||||
Desc: A module to take care of the registration and calling
|
||||
of Lua console commands.
|
||||
-----------------------------------------------------------]]
|
||||
module( "concommand" )
|
||||
|
||||
local CommandList = {}
|
||||
local CompleteList = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand.GetTable( )
|
||||
Desc: Returns the table of console commands and auto complete
|
||||
-----------------------------------------------------------]]
|
||||
function GetTable()
|
||||
return CommandList, CompleteList
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand.Add( name, func, completefunc )
|
||||
Desc: Register a new console command
|
||||
-----------------------------------------------------------]]
|
||||
function Add( name, func, completefunc, help, flags )
|
||||
local LowerName = string.lower( name )
|
||||
CommandList[ LowerName ] = func
|
||||
CompleteList[ LowerName ] = completefunc
|
||||
AddConsoleCommand( name, help, flags )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand.Remove( name )
|
||||
Desc: Removes a console command
|
||||
-----------------------------------------------------------]]
|
||||
function Remove( name )
|
||||
local LowerName = string.lower( name )
|
||||
CommandList[ LowerName ] = nil
|
||||
CompleteList[ LowerName ] = nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand.Run( )
|
||||
Desc: Called by the engine when an unknown console command is run
|
||||
-----------------------------------------------------------]]
|
||||
function Run( player, command, arguments, argumentsStr )
|
||||
|
||||
local LowerCommand = string.lower( command )
|
||||
|
||||
if ( CommandList[ LowerCommand ] != nil ) then
|
||||
CommandList[ LowerCommand ]( player, command, arguments, argumentsStr )
|
||||
return true
|
||||
end
|
||||
|
||||
Msg( "Unknown command: " .. command .. "\n" )
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: concommand.AutoComplete( )
|
||||
Desc: Returns a table for the autocompletion
|
||||
-----------------------------------------------------------]]
|
||||
function AutoComplete( command, argumentsStr, arguments )
|
||||
|
||||
local LowerCommand = string.lower( command )
|
||||
|
||||
if ( CompleteList[ LowerCommand ] != nil ) then
|
||||
return CompleteList[ LowerCommand ]( command, argumentsStr, arguments )
|
||||
end
|
||||
|
||||
end
|
||||
1678
lua/includes/modules/constraint.lua
Normal file
1678
lua/includes/modules/constraint.lua
Normal file
File diff suppressed because it is too large
Load Diff
163
lua/includes/modules/construct.lua
Normal file
163
lua/includes/modules/construct.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local ents = ents
|
||||
local SERVER = SERVER
|
||||
local duplicator = duplicator
|
||||
local numpad = numpad
|
||||
local Msg = Msg
|
||||
local IsValid = IsValid
|
||||
|
||||
module( "construct" )
|
||||
|
||||
if SERVER then
|
||||
|
||||
function SetPhysProp( Player, Entity, BoneID, Bone, Data )
|
||||
|
||||
if ( !IsValid( Bone ) ) then
|
||||
|
||||
Bone = Entity:GetPhysicsObjectNum( BoneID )
|
||||
if ( !IsValid( Bone ) ) then
|
||||
Msg( "SetPhysProp: Error applying attributes to invalid physics object!\n" )
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( Data.GravityToggle != nil ) then Bone:EnableGravity( Data.GravityToggle ) end
|
||||
if ( Data.Material != nil ) then Bone:SetMaterial( Data.Material ) end
|
||||
|
||||
-- todo: Rename/Implement
|
||||
--[[
|
||||
if ( Data.motionb != nil ) then Bone:EnableMotion( Data.motionb ) end
|
||||
if ( Data.mass != nil ) then Bone:SetMass( Data.mass ) end
|
||||
if ( Data.dragb != nil ) then Bone:EnableDrag( Data.dragb ) end
|
||||
if ( Data.drag != nil ) then Bone:SetDragCoefficient( Data.drag ) end
|
||||
if ( Data.buoyancy != nil ) then Bone:SetBuoyancyRatio( Data.buoyancy ) end
|
||||
if ( Data.rotdamping != nil ) then Bone:SetDamping( PhysBone:GetSpeedDamping(), Data.rotdamping ) end
|
||||
if ( Data.speeddamping != nil ) then Bone:SetDamping( Data.speeddamping, PhysBone:GetRotDamping() ) end
|
||||
--]]
|
||||
|
||||
-- HACK HACK
|
||||
-- If we don't do this the prop will be motion enabled and will
|
||||
-- slide through the world with no gravity.
|
||||
if ( !Bone:IsMoveable() ) then
|
||||
|
||||
Bone:EnableMotion( true )
|
||||
Bone:EnableMotion( false )
|
||||
|
||||
end
|
||||
|
||||
duplicator.StoreBoneModifier( Entity, BoneID, "physprops", Data )
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterBoneModifier( "physprops", SetPhysProp )
|
||||
|
||||
|
||||
local function MagnetOff( pl, magnet )
|
||||
|
||||
if ( !IsValid( magnet ) ) then return false end
|
||||
if ( magnet:GetTable().toggle != 0 ) then return true end
|
||||
|
||||
magnet:Fire( "TurnOff", "" , 0 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function MagnetOn( pl, magnet )
|
||||
|
||||
if ( !IsValid( magnet ) ) then return false end
|
||||
|
||||
if ( magnet:GetTable().toggle != 0 ) then
|
||||
|
||||
magnet:GetTable().toggle_state = !magnet:GetTable().toggle_state
|
||||
|
||||
if ( magnet:GetTable().toggle_state ) then
|
||||
magnet:Fire( "TurnOn", "" , 0 )
|
||||
else
|
||||
magnet:Fire( "TurnOff", "" , 0 )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
magnet:Fire( "TurnOn", "" , 0 )
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
numpad.Register( "MagnetOff", MagnetOff )
|
||||
numpad.Register( "MagnetOn", MagnetOn )
|
||||
|
||||
function Magnet( pl, pos, angle, model, material, key, maxobjects, strength, nopull, allowrot, alwayson, toggle, Vel, aVel, frozen )
|
||||
|
||||
local magnet = ents.Create( "phys_magnet" )
|
||||
magnet:SetPos( pos )
|
||||
magnet:SetAngles( angle )
|
||||
magnet:SetModel( model )
|
||||
if ( material ) then magnet:SetMaterial( material ) end
|
||||
|
||||
local spawnflags = 4
|
||||
if ( nopull && nopull > 0 ) then spawnflags = spawnflags - 4 end -- no pull required: remove the suck flag
|
||||
if ( allowrot && allowrot > 0 ) then spawnflags = spawnflags + 8 end
|
||||
|
||||
if ( maxobjects ) then magnet:SetKeyValue( "maxobjects", maxobjects ) end
|
||||
if ( strength ) then magnet:SetKeyValue( "forcelimit", strength ) end
|
||||
magnet:SetKeyValue( "overridescript", "surfaceprop,metal")
|
||||
magnet:SetKeyValue( "massScale", 0 )
|
||||
|
||||
magnet:Activate()
|
||||
magnet:Spawn()
|
||||
|
||||
if ( IsValid( magnet:GetPhysicsObject() ) ) then
|
||||
local Phys = magnet:GetPhysicsObject()
|
||||
if ( Vel ) then Phys:SetVelocity( Vel ) end
|
||||
if ( aVel ) then Phys:AddAngleVelocity( aVel ) end
|
||||
Phys:EnableMotion( frozen != true )
|
||||
end
|
||||
|
||||
if ( alwayson && alwayson > 0 ) then
|
||||
magnet:Input( "TurnOn", nil, nil, nil )
|
||||
else
|
||||
magnet:Input( "TurnOff", nil, nil, nil )
|
||||
end
|
||||
|
||||
local mtable = {
|
||||
Model = model,
|
||||
material = material,
|
||||
key = key,
|
||||
maxobjects = maxobjects,
|
||||
strength = strength,
|
||||
nopull = nopull,
|
||||
allowrot = allowrot,
|
||||
alwayson = alwayson,
|
||||
toggle = toggle
|
||||
}
|
||||
|
||||
magnet:SetTable( mtable )
|
||||
|
||||
if ( key ) then
|
||||
numpad.OnDown( pl, key, "MagnetOn", magnet )
|
||||
numpad.OnUp( pl, key, "MagnetOff", magnet )
|
||||
end
|
||||
|
||||
return magnet
|
||||
|
||||
end
|
||||
|
||||
duplicator.RegisterEntityClass( "phys_magnet", Magnet, "Pos", "Ang", "Model", "material", "key", "maxobjects", "strength", "nopull", "allowrot", "alwayson", "toggle", "Vel", "aVel", "frozen" )
|
||||
|
||||
end
|
||||
57
lua/includes/modules/controlpanel.lua
Normal file
57
lua/includes/modules/controlpanel.lua
Normal file
@@ -0,0 +1,57 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local ControlPanels = {}
|
||||
|
||||
module( "controlpanel", package.seeall )
|
||||
|
||||
-- A hack for a very annoying race condition where spawnmenu_reload deletes the controlpanels on the next frame
|
||||
-- But some panels are updated "this" frame after spawnmenu reloaded
|
||||
local function ShouldReCreate( pnl )
|
||||
if ( !IsValid( pnl ) || pnl:IsMarkedForDeletion() ) then return true end
|
||||
|
||||
local p = pnl
|
||||
-- Can't use IsValid because it's false for marked for deletion panels
|
||||
while ( IsValid( p ) && p:GetParent() != nil ) do
|
||||
if ( p:GetParent():IsMarkedForDeletion() ) then return true end
|
||||
p = p:GetParent()
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function Get( name )
|
||||
|
||||
if ( ShouldReCreate( ControlPanels[ name ] ) ) then
|
||||
local cp = vgui.Create( "ControlPanel" )
|
||||
if ( !cp ) then
|
||||
|
||||
debug.Trace()
|
||||
Error( "controlpanel.Get() - Error creating a ControlPanel!\nYou're calling this function too early! Call it in a hook!\n" )
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
cp:SetVisible( false )
|
||||
cp.Name = name
|
||||
ControlPanels[ name ] = cp
|
||||
|
||||
end
|
||||
|
||||
return ControlPanels[ name ]
|
||||
|
||||
end
|
||||
|
||||
function Clear()
|
||||
|
||||
ControlPanels = {}
|
||||
|
||||
end
|
||||
143
lua/includes/modules/cookie.lua
Normal file
143
lua/includes/modules/cookie.lua
Normal file
@@ -0,0 +1,143 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( !sql.TableExists( "cookies" ) ) then
|
||||
|
||||
sql.Query( "CREATE TABLE IF NOT EXISTS cookies ( key TEXT NOT NULL PRIMARY KEY, value TEXT );" )
|
||||
|
||||
end
|
||||
|
||||
module( "cookie", package.seeall )
|
||||
|
||||
local CachedEntries = {}
|
||||
local BufferedWrites = {}
|
||||
local BufferedDeletes = {}
|
||||
|
||||
local function GetCache( key )
|
||||
|
||||
if ( BufferedDeletes[ key ] ) then return nil end
|
||||
|
||||
local entry = CachedEntries[ key ]
|
||||
|
||||
if ( entry == nil || SysTime() > entry[ 1 ] ) then
|
||||
local name = SQLStr( key )
|
||||
local val = sql.QueryValue( "SELECT value FROM cookies WHERE key = " .. name )
|
||||
|
||||
if !val then
|
||||
return false
|
||||
end
|
||||
|
||||
CachedEntries[ key ] = { SysTime() + 30, val }
|
||||
end
|
||||
|
||||
return CachedEntries[ key ][ 2 ]
|
||||
|
||||
end
|
||||
|
||||
local function FlushCache()
|
||||
|
||||
CachedEntries = {}
|
||||
BufferedWrites = {}
|
||||
BufferedDeletes = {}
|
||||
|
||||
end
|
||||
|
||||
local function CommitToSQLite()
|
||||
|
||||
sql.Begin()
|
||||
|
||||
for k, v in pairs( BufferedWrites ) do
|
||||
sql.Query( "INSERT OR REPLACE INTO cookies ( key, value ) VALUES ( " .. SQLStr( k ) .. ", " .. SQLStr( v ) .. " )" )
|
||||
end
|
||||
|
||||
for k, v in pairs( BufferedDeletes ) do
|
||||
sql.Query( "DELETE FROM cookies WHERE key = " .. SQLStr( k ) )
|
||||
end
|
||||
|
||||
BufferedWrites = {}
|
||||
BufferedDeletes = {}
|
||||
|
||||
sql.Commit()
|
||||
|
||||
end
|
||||
|
||||
local function ScheduleCommit()
|
||||
|
||||
timer.Create( "Cookie_CommitToSQLite", 0.1, 1, CommitToSQLite )
|
||||
|
||||
end
|
||||
|
||||
local function SetCache( key, value )
|
||||
|
||||
if ( value == nil ) then return Delete( key ) end
|
||||
|
||||
if CachedEntries[ key ] then
|
||||
CachedEntries[ key ][ 1 ] = SysTime() + 30
|
||||
CachedEntries[ key ][ 2 ] = value
|
||||
else
|
||||
CachedEntries[ key ] = { SysTime() + 30, value }
|
||||
end
|
||||
|
||||
BufferedWrites[ key ] = value
|
||||
|
||||
ScheduleCommit()
|
||||
|
||||
end
|
||||
|
||||
-- Get a String Value
|
||||
function GetString( name, default )
|
||||
|
||||
local val = GetCache( name )
|
||||
if ( !val ) then return default end
|
||||
|
||||
return val
|
||||
|
||||
end
|
||||
|
||||
-- Get a Number Value
|
||||
function GetNumber( name, default )
|
||||
|
||||
local val = GetCache( name )
|
||||
if ( !val ) then return default end
|
||||
|
||||
return tonumber( val )
|
||||
|
||||
end
|
||||
|
||||
-- Delete a Value
|
||||
function Delete( name )
|
||||
|
||||
CachedEntries[ name ] = nil
|
||||
BufferedWrites[ name ] = nil
|
||||
BufferedDeletes[ name ] = true
|
||||
|
||||
ScheduleCommit()
|
||||
|
||||
end
|
||||
|
||||
-- Set a Value
|
||||
function Set( name, value )
|
||||
|
||||
SetCache( name, value )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "ShutDown", "SaveCookiesOnShutdown", CommitToSQLite )
|
||||
|
||||
if ( !CLIENT_DLL ) then return end
|
||||
|
||||
concommand.Add( "lua_cookieclear", function( ply, command, arguments )
|
||||
|
||||
sql.Query( "DELETE FROM cookies" )
|
||||
FlushCache()
|
||||
|
||||
end )
|
||||
|
||||
157
lua/includes/modules/cvars.lua
Normal file
157
lua/includes/modules/cvars.lua
Normal file
@@ -0,0 +1,157 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local table = table
|
||||
local type = type
|
||||
local istable = istable
|
||||
local isstring = isstring
|
||||
local assert = assert
|
||||
local format = string.format
|
||||
local GetConVar = GetConVar
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: cvar
|
||||
Desc: Callbacks when cvars change
|
||||
-----------------------------------------------------------]]
|
||||
module( "cvars" )
|
||||
|
||||
local ConVars = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetConVarCallbacks
|
||||
Desc: Returns a table of the given ConVars callbacks
|
||||
-----------------------------------------------------------]]
|
||||
function GetConVarCallbacks( name, createIfNotFound )
|
||||
|
||||
local tab = ConVars[ name ]
|
||||
if ( createIfNotFound and !tab ) then
|
||||
tab = {}
|
||||
ConVars[ name ] = tab
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: OnConVarChanged
|
||||
Desc: Called by the engine
|
||||
-----------------------------------------------------------]]
|
||||
function OnConVarChanged( name, old, new )
|
||||
|
||||
local tab = GetConVarCallbacks( name )
|
||||
if ( !tab ) then return end
|
||||
|
||||
for i = 1, #tab do
|
||||
local callback = tab[ i ]
|
||||
if ( istable( callback ) ) then
|
||||
callback[ 1 ]( name, old, new )
|
||||
else
|
||||
callback( name, old, new )
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AddChangeCallback
|
||||
Desc: Adds a callback to be called when convar changes
|
||||
-----------------------------------------------------------]]
|
||||
function AddChangeCallback( name, func, identifier )
|
||||
|
||||
if ( identifier ) then
|
||||
assert( isstring( identifier ), format( "bad argument #%i (string expected, got %s)", 3, type( identifier ) ) )
|
||||
end
|
||||
|
||||
local tab = GetConVarCallbacks( name, true )
|
||||
|
||||
if ( !identifier ) then
|
||||
table.insert( tab, func )
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1, #tab do
|
||||
local callback = tab[ i ]
|
||||
if ( istable( callback ) and callback[ 2 ] == identifier ) then
|
||||
callback[ 1 ] = func
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( tab, { func, identifier } )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RemoveChangeCallback
|
||||
Desc: Removes callback with identifier
|
||||
-----------------------------------------------------------]]
|
||||
function RemoveChangeCallback( name, identifier )
|
||||
|
||||
if ( identifier ) then
|
||||
assert( isstring( identifier ), format( "bad argument #%i (string expected, got %s)", 2, type( identifier ) ) )
|
||||
end
|
||||
|
||||
local tab = GetConVarCallbacks( name, true )
|
||||
for i = 1, #tab do
|
||||
local callback = tab[ i ]
|
||||
if ( istable( callback ) and callback[ 2 ] == identifier ) then
|
||||
table.remove( tab, i )
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: String
|
||||
Desc: Retrieves console variable as a string
|
||||
-----------------------------------------------------------]]
|
||||
function String( name, default )
|
||||
|
||||
local convar = GetConVar( name )
|
||||
if ( convar ~= nil ) then
|
||||
return convar:GetString()
|
||||
end
|
||||
|
||||
return default
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Number
|
||||
Desc: Retrieves console variable as a number
|
||||
-----------------------------------------------------------]]
|
||||
function Number( name, default )
|
||||
|
||||
local convar = GetConVar( name )
|
||||
if ( convar ~= nil ) then
|
||||
return convar:GetFloat()
|
||||
end
|
||||
|
||||
return default
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Bool
|
||||
Desc: Retrieves console variable as a boolean
|
||||
-----------------------------------------------------------]]
|
||||
function Bool( name, default )
|
||||
|
||||
local convar = GetConVar( name )
|
||||
if ( convar ~= nil ) then
|
||||
return convar:GetBool()
|
||||
end
|
||||
|
||||
return default
|
||||
|
||||
end
|
||||
324
lua/includes/modules/draw.lua
Normal file
324
lua/includes/modules/draw.lua
Normal file
@@ -0,0 +1,324 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local string = string
|
||||
local surface = surface
|
||||
local math = math
|
||||
local Color = Color
|
||||
local tostring = tostring
|
||||
local color_white = color_white
|
||||
|
||||
module( "draw" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Constants used for text alignment.
|
||||
These must be the same values as in the markup module.
|
||||
-----------------------------------------------------------]]
|
||||
TEXT_ALIGN_LEFT = 0
|
||||
TEXT_ALIGN_CENTER = 1
|
||||
TEXT_ALIGN_RIGHT = 2
|
||||
TEXT_ALIGN_TOP = 3
|
||||
TEXT_ALIGN_BOTTOM = 4
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Textures we use to get shit done
|
||||
-----------------------------------------------------------]]
|
||||
local tex_corner8 = surface.GetTextureID( "gui/corner8" )
|
||||
local tex_corner16 = surface.GetTextureID( "gui/corner16" )
|
||||
local tex_corner32 = surface.GetTextureID( "gui/corner32" )
|
||||
local tex_corner64 = surface.GetTextureID( "gui/corner64" )
|
||||
local tex_corner512 = surface.GetTextureID( "gui/corner512" )
|
||||
local tex_white = surface.GetTextureID( "vgui/white" )
|
||||
|
||||
local CachedFontHeights = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetFontHeight( font )
|
||||
Desc: Returns the height of a single line
|
||||
-----------------------------------------------------------]]
|
||||
function GetFontHeight( font )
|
||||
|
||||
if ( CachedFontHeights[ font ] != nil ) then
|
||||
return CachedFontHeights[ font ]
|
||||
end
|
||||
|
||||
surface.SetFont( font )
|
||||
local w, h = surface.GetTextSize( "W" )
|
||||
CachedFontHeights[ font ] = h
|
||||
|
||||
return h
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SimpleText(text, font, x, y, colour)
|
||||
Desc: Simple "draw text at position function"
|
||||
color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
function SimpleText( text, font, x, y, colour, xalign, yalign )
|
||||
|
||||
text = tostring( text )
|
||||
font = font or "DermaDefault"
|
||||
x = x or 0
|
||||
y = y or 0
|
||||
xalign = xalign or TEXT_ALIGN_LEFT
|
||||
yalign = yalign or TEXT_ALIGN_TOP
|
||||
|
||||
surface.SetFont( font )
|
||||
local w, h = surface.GetTextSize( text )
|
||||
|
||||
if ( xalign == TEXT_ALIGN_CENTER ) then
|
||||
x = x - w / 2
|
||||
elseif ( xalign == TEXT_ALIGN_RIGHT ) then
|
||||
x = x - w
|
||||
end
|
||||
|
||||
if ( yalign == TEXT_ALIGN_CENTER ) then
|
||||
y = y - h / 2
|
||||
elseif ( yalign == TEXT_ALIGN_BOTTOM ) then
|
||||
y = y - h
|
||||
end
|
||||
|
||||
surface.SetTextPos( math.ceil( x ), math.ceil( y ) )
|
||||
|
||||
if ( colour != nil ) then
|
||||
surface.SetTextColor( colour.r, colour.g, colour.b, colour.a )
|
||||
else
|
||||
surface.SetTextColor( 255, 255, 255, 255 )
|
||||
end
|
||||
|
||||
surface.DrawText( text )
|
||||
|
||||
return w, h
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SimpleTextOutlined( text, font, x, y, colour, xalign, yalign, outlinewidth, outlinecolour )
|
||||
Desc: Simple draw text at position, but this will expand newlines and tabs.
|
||||
color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
function SimpleTextOutlined(text, font, x, y, colour, xalign, yalign, outlinewidth, outlinecolour)
|
||||
|
||||
local steps = ( outlinewidth * 2 ) / 3
|
||||
if ( steps < 1 ) then steps = 1 end
|
||||
|
||||
for _x = -outlinewidth, outlinewidth, steps do
|
||||
for _y = -outlinewidth, outlinewidth, steps do
|
||||
SimpleText( text, font, x + _x, y + _y, outlinecolour, xalign, yalign )
|
||||
end
|
||||
end
|
||||
|
||||
return SimpleText( text, font, x, y, colour, xalign, yalign )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DrawText(text, font, x, y, colour, align )
|
||||
Desc: Simple draw text at position, but this will expand newlines and tabs.
|
||||
color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
local gmatch = string.gmatch
|
||||
local find = string.find
|
||||
local ceil = math.ceil
|
||||
local GetTextSize = surface.GetTextSize
|
||||
local max = math.max
|
||||
function DrawText( text, font, x, y, colour, xalign )
|
||||
|
||||
if ( font == nil ) then font = "DermaDefault" end
|
||||
if ( text != nil ) then text = tostring( text ) end
|
||||
if ( x == nil ) then x = 0 end
|
||||
if ( y == nil ) then y = 0 end
|
||||
|
||||
local curX = x
|
||||
local curY = y
|
||||
local curString = ""
|
||||
|
||||
surface.SetFont( font )
|
||||
local sizeX, lineHeight = GetTextSize( "\n" )
|
||||
local tabWidth = 50
|
||||
|
||||
for str in gmatch( text, "[^\n]*" ) do
|
||||
if #str > 0 then
|
||||
if find( str, "\t" ) then -- there's tabs, some more calculations required
|
||||
for tabs, str2 in gmatch( str, "(\t*)([^\t]*)" ) do
|
||||
curX = ceil( ( curX + tabWidth * max( #tabs - 1, 0 ) ) / tabWidth ) * tabWidth
|
||||
|
||||
if #str2 > 0 then
|
||||
SimpleText( str2, font, curX, curY, colour, xalign )
|
||||
|
||||
local w, _ = GetTextSize( str2 )
|
||||
curX = curX + w
|
||||
end
|
||||
end
|
||||
else -- there's no tabs, this is easy
|
||||
SimpleText( str, font, curX, curY, colour, xalign )
|
||||
end
|
||||
else
|
||||
curX = x
|
||||
curY = curY + ( lineHeight / 2 )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RoundedBox( bordersize, x, y, w, h, color )
|
||||
Desc: Draws a rounded box - ideally bordersize will be 8 or 16
|
||||
Usage: color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
function RoundedBox( bordersize, x, y, w, h, color )
|
||||
|
||||
return RoundedBoxEx( bordersize, x, y, w, h, color, true, true, true, true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RoundedBox( bordersize, x, y, w, h, color )
|
||||
Desc: Draws a rounded box - ideally bordersize will be 8 or 16
|
||||
Usage: color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
function RoundedBoxEx( bordersize, x, y, w, h, color, tl, tr, bl, br )
|
||||
|
||||
surface.SetDrawColor( color.r, color.g, color.b, color.a )
|
||||
|
||||
-- Do not waste performance if they don't want rounded corners
|
||||
if ( bordersize <= 0 ) then
|
||||
surface.DrawRect( x, y, w, h )
|
||||
return
|
||||
end
|
||||
|
||||
x = math.Round( x )
|
||||
y = math.Round( y )
|
||||
w = math.Round( w )
|
||||
h = math.Round( h )
|
||||
bordersize = math.min( math.Round( bordersize ), math.floor( w / 2 ), math.floor( h / 2 ) )
|
||||
|
||||
-- Draw as much of the rect as we can without textures
|
||||
surface.DrawRect( x + bordersize, y, w - bordersize * 2, h )
|
||||
surface.DrawRect( x, y + bordersize, bordersize, h - bordersize * 2 )
|
||||
surface.DrawRect( x + w - bordersize, y + bordersize, bordersize, h - bordersize * 2 )
|
||||
|
||||
local tex = tex_corner8
|
||||
if ( bordersize > 8 ) then tex = tex_corner16 end
|
||||
if ( bordersize > 16 ) then tex = tex_corner32 end
|
||||
if ( bordersize > 32 ) then tex = tex_corner64 end
|
||||
if ( bordersize > 64 ) then tex = tex_corner512 end
|
||||
|
||||
surface.SetTexture( tex )
|
||||
|
||||
if ( tl ) then
|
||||
surface.DrawTexturedRectUV( x, y, bordersize, bordersize, 0, 0, 1, 1 )
|
||||
else
|
||||
surface.DrawRect( x, y, bordersize, bordersize )
|
||||
end
|
||||
|
||||
if ( tr ) then
|
||||
surface.DrawTexturedRectUV( x + w - bordersize, y, bordersize, bordersize, 1, 0, 0, 1 )
|
||||
else
|
||||
surface.DrawRect( x + w - bordersize, y, bordersize, bordersize )
|
||||
end
|
||||
|
||||
if ( bl ) then
|
||||
surface.DrawTexturedRectUV( x, y + h -bordersize, bordersize, bordersize, 0, 1, 1, 0 )
|
||||
else
|
||||
surface.DrawRect( x, y + h - bordersize, bordersize, bordersize )
|
||||
end
|
||||
|
||||
if ( br ) then
|
||||
surface.DrawTexturedRectUV( x + w - bordersize, y + h - bordersize, bordersize, bordersize, 1, 1, 0, 0 )
|
||||
else
|
||||
surface.DrawRect( x + w - bordersize, y + h - bordersize, bordersize, bordersize )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: WordBox( bordersize, x, y, font, color, font, color, fontcolor, xalign, yalign )
|
||||
Desc: Draws a rounded box - ideally bordersize will be 8 or 16
|
||||
Usage: color is a table with r/g/b/a elements
|
||||
-----------------------------------------------------------]]
|
||||
function WordBox( bordersize, x, y, text, font, color, fontcolor, xalign, yalign )
|
||||
|
||||
surface.SetFont( font )
|
||||
local w, h = surface.GetTextSize( text )
|
||||
|
||||
if ( xalign == TEXT_ALIGN_CENTER ) then
|
||||
x = x - ( bordersize + w / 2 )
|
||||
elseif ( xalign == TEXT_ALIGN_RIGHT ) then
|
||||
x = x - ( bordersize * 2 + w )
|
||||
end
|
||||
|
||||
if ( yalign == TEXT_ALIGN_CENTER ) then
|
||||
y = y - ( bordersize + h / 2 )
|
||||
elseif ( yalign == TEXT_ALIGN_BOTTOM ) then
|
||||
y = y - ( bordersize * 2 + h )
|
||||
end
|
||||
|
||||
RoundedBox( bordersize, x, y, w+bordersize * 2, h+bordersize * 2, color )
|
||||
|
||||
surface.SetTextColor( fontcolor.r, fontcolor.g, fontcolor.b, fontcolor.a )
|
||||
surface.SetTextPos( x + bordersize, y + bordersize )
|
||||
surface.DrawText( text )
|
||||
|
||||
return w + bordersize * 2, h + bordersize * 2
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Text( table )
|
||||
Desc: Draws text from a table
|
||||
-----------------------------------------------------------]]
|
||||
function Text( tab )
|
||||
|
||||
return SimpleText( tab.text, tab.font, tab.pos[ 1 ], tab.pos[ 2 ], tab.color, tab.xalign, tab.yalign )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TextShadow( table )
|
||||
Desc: Draws text from a table
|
||||
-----------------------------------------------------------]]
|
||||
function TextShadow( tab, distance, alpha )
|
||||
|
||||
alpha = alpha or 200
|
||||
|
||||
local color = tab.color
|
||||
local pos = tab.pos
|
||||
tab.color = Color( 0, 0, 0, alpha )
|
||||
tab.pos = { pos[ 1 ] + distance, pos[ 2 ] + distance }
|
||||
|
||||
Text( tab )
|
||||
|
||||
tab.color = color
|
||||
tab.pos = pos
|
||||
|
||||
return Text( tab )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TexturedQuad( table )
|
||||
Desc: pawrapper
|
||||
-----------------------------------------------------------]]
|
||||
function TexturedQuad( tab )
|
||||
|
||||
local color = tab.color or color_white
|
||||
|
||||
surface.SetTexture( tab.texture )
|
||||
surface.SetDrawColor( color.r, color.g, color.b, color.a )
|
||||
surface.DrawTexturedRect( tab.x, tab.y, tab.w, tab.h )
|
||||
|
||||
end
|
||||
|
||||
function NoTexture()
|
||||
surface.SetTexture( tex_white )
|
||||
end
|
||||
251
lua/includes/modules/drive.lua
Normal file
251
lua/includes/modules/drive.lua
Normal file
@@ -0,0 +1,251 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local IsValid = IsValid
|
||||
local setmetatable = setmetatable
|
||||
local SERVER = SERVER
|
||||
local util = util
|
||||
local ErrorNoHalt = ErrorNoHalt
|
||||
local baseclass = baseclass
|
||||
local LocalPlayer = LocalPlayer
|
||||
|
||||
module( "drive" )
|
||||
|
||||
local Type = {}
|
||||
|
||||
function Register( name, table, base )
|
||||
|
||||
Type[ name ] = table
|
||||
|
||||
--
|
||||
-- If we have a base method then hook
|
||||
-- it up in the meta table
|
||||
--
|
||||
if ( base ) then
|
||||
Type[ base ] = Type[ base ] or baseclass.Get( base )
|
||||
setmetatable( Type[ name ], { __index = Type[ base ] } )
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
util.AddNetworkString( name )
|
||||
end
|
||||
|
||||
--
|
||||
-- drive methods cooperate with the baseclass system
|
||||
-- /lua/includes/modules/baseclass.lua
|
||||
--
|
||||
baseclass.Set( name, Type[ name ] )
|
||||
|
||||
end
|
||||
|
||||
function PlayerStartDriving( ply, ent, mode )
|
||||
|
||||
local method = Type[mode]
|
||||
if ( !method ) then ErrorNoHalt( "Unknown drive type " .. ( mode ) .. "!\n" ) return end
|
||||
|
||||
local id = util.NetworkStringToID( mode )
|
||||
|
||||
ply:SetDrivingEntity( ent, id )
|
||||
|
||||
end
|
||||
|
||||
function PlayerStopDriving( ply )
|
||||
|
||||
ply:SetDrivingEntity( nil )
|
||||
|
||||
end
|
||||
|
||||
function GetMethod( ply )
|
||||
|
||||
--
|
||||
-- Not driving, return immediately
|
||||
--
|
||||
if ( !ply:IsDrivingEntity() ) then return end
|
||||
|
||||
local ent = ply:GetDrivingEntity()
|
||||
local modeid = ply:GetDrivingMode()
|
||||
|
||||
--
|
||||
-- Entity is invalid or mode isn't set - return out
|
||||
--
|
||||
if ( !IsValid( ent ) || modeid == 0 ) then return end
|
||||
|
||||
--
|
||||
-- Have we already got a drive method? If so then reuse.
|
||||
--
|
||||
local method = ply.m_CurrentDriverMethod
|
||||
if ( method && method.Entity == ent && method.ModeID == modeid ) then return method end
|
||||
|
||||
--
|
||||
-- No method - lets create one. Get the string from the modeid.
|
||||
--
|
||||
local modename = util.NetworkIDToString( modeid )
|
||||
if ( !modename ) then return end
|
||||
|
||||
--
|
||||
-- Get that type. Fail if we don't have the type.
|
||||
--
|
||||
local type = Type[ modename ]
|
||||
if ( !type ) then return end
|
||||
|
||||
local method = {}
|
||||
method.Entity = ent
|
||||
method.Player = ply
|
||||
method.ModeID = modeid
|
||||
|
||||
setmetatable( method, { __index = type } )
|
||||
|
||||
ply.m_CurrentDriverMethod = method
|
||||
|
||||
method:Init()
|
||||
return method
|
||||
|
||||
end
|
||||
|
||||
function DestroyMethod( pl )
|
||||
|
||||
if ( !IsValid( pl ) ) then return end
|
||||
|
||||
pl.m_CurrentDriverMethod = nil
|
||||
|
||||
end
|
||||
--
|
||||
-- Called when the player first
|
||||
-- starts driving this entity
|
||||
--
|
||||
function Start( ply, ent )
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
-- Set this to the ent's view entity
|
||||
ply:SetViewEntity( ent )
|
||||
|
||||
-- Save the player's eye angles
|
||||
ply.m_PreDriveEyeAngles = ply:EyeAngles()
|
||||
ply.m_PreDriveObserveMode = ply:GetObserverMode()
|
||||
|
||||
-- Lock the player's eye angles to our angles
|
||||
local ang = ent:GetAngles()
|
||||
ply:SetEyeAngles( ang )
|
||||
|
||||
-- Hide the controlling player's world model
|
||||
ply:DrawWorldModel( false )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Clientside, the client creates the cmd (usercommand)
|
||||
-- from their input device (mouse, keyboard) and then
|
||||
-- it's sent to the server. Restrict view angles here :)
|
||||
--
|
||||
function CreateMove( cmd )
|
||||
|
||||
local method = GetMethod( LocalPlayer() )
|
||||
if ( !method ) then return end
|
||||
|
||||
method:SetupControls( cmd )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Optionally alter the view
|
||||
--
|
||||
function CalcView( ply, view )
|
||||
|
||||
local method = GetMethod( ply )
|
||||
if ( !method ) then return end
|
||||
|
||||
method:CalcView( view )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- The user command is received by the server and then
|
||||
-- converted into a move. This is also run clientside
|
||||
-- when in multiplayer, for prediction to work.
|
||||
--
|
||||
function StartMove( ply, mv, cmd )
|
||||
|
||||
local method = GetMethod( ply )
|
||||
if ( !method ) then return end
|
||||
|
||||
method:StartMove( mv, cmd )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- The move is executed here.
|
||||
--
|
||||
function Move( ply, mv )
|
||||
|
||||
local method = GetMethod( ply )
|
||||
if ( !method ) then return end
|
||||
|
||||
method:Move( mv )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- The move is finished. Copy mv back into the target.
|
||||
--
|
||||
function FinishMove( ply, mv )
|
||||
|
||||
local method = GetMethod( ply )
|
||||
if ( !method ) then return end
|
||||
|
||||
method:FinishMove( mv )
|
||||
|
||||
if ( method.StopDriving ) then
|
||||
PlayerStopDriving( ply )
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Player has stopped driving the entity
|
||||
--
|
||||
function End( ply, ent )
|
||||
|
||||
--
|
||||
-- If the player is valid then set the view entity to nil
|
||||
--
|
||||
if ( SERVER && IsValid( ply ) ) then
|
||||
|
||||
if ( ply.m_PreDriveEyeAngles != nil ) then
|
||||
ply:SetEyeAngles( ply.m_PreDriveEyeAngles )
|
||||
ply.m_PreDriveEyeAngles = nil
|
||||
end
|
||||
|
||||
if ( ply.m_PreDriveObserveMode != nil ) then
|
||||
ply:SetObserverMode( ply.m_PreDriveObserveMode )
|
||||
ply.m_PreDriveObserveMode = nil
|
||||
end
|
||||
|
||||
ply:SetViewEntity( nil )
|
||||
|
||||
-- Show the controlling player's world model
|
||||
ply:DrawWorldModel( true )
|
||||
|
||||
end
|
||||
|
||||
DestroyMethod( ply )
|
||||
|
||||
end
|
||||
|
||||
1034
lua/includes/modules/duplicator.lua
Normal file
1034
lua/includes/modules/duplicator.lua
Normal file
File diff suppressed because it is too large
Load Diff
87
lua/includes/modules/effects.lua
Normal file
87
lua/includes/modules/effects.lua
Normal file
@@ -0,0 +1,87 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local ents = ents
|
||||
local pairs = pairs
|
||||
local ipairs = ipairs
|
||||
local string = string
|
||||
local table = table
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: effects
|
||||
Desc: Engine effects hooking
|
||||
-----------------------------------------------------------]]
|
||||
module( "effects" )
|
||||
|
||||
local EffectList = {}
|
||||
|
||||
function Register( t, name )
|
||||
|
||||
name = string.lower( name )
|
||||
|
||||
local old = EffectList[ name ]
|
||||
|
||||
EffectList[ name ] = t
|
||||
|
||||
--
|
||||
-- If we're reloading this entity class
|
||||
-- then refresh all the existing entities.
|
||||
--
|
||||
if ( old != nil ) then
|
||||
|
||||
--
|
||||
-- For each entity using this class
|
||||
--
|
||||
for _, entity in ipairs( ents.FindByClass( name ) ) do
|
||||
|
||||
--
|
||||
-- Replace the contents with this entity table
|
||||
--
|
||||
table.Merge( entity, t )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Create( name, retval )
|
||||
|
||||
name = string.lower( name )
|
||||
|
||||
--Msg( "Create.. ".. name .. "\n" )
|
||||
|
||||
if ( EffectList[ name ] == nil ) then return nil end
|
||||
|
||||
local NewEffect = retval or {}
|
||||
|
||||
for k, v in pairs( EffectList[ name ] ) do
|
||||
|
||||
NewEffect[ k ] = v
|
||||
|
||||
end
|
||||
|
||||
table.Merge( NewEffect, EffectList[ "base" ] )
|
||||
|
||||
return NewEffect
|
||||
|
||||
end
|
||||
|
||||
function GetList()
|
||||
|
||||
local result = {}
|
||||
|
||||
for k, v in pairs( EffectList ) do
|
||||
table.insert( result, v )
|
||||
end
|
||||
|
||||
return result
|
||||
|
||||
end
|
||||
93
lua/includes/modules/gamemode.lua
Normal file
93
lua/includes/modules/gamemode.lua
Normal file
@@ -0,0 +1,93 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local gmod = gmod
|
||||
local Msg = Msg
|
||||
local hook = hook
|
||||
local table = table
|
||||
local baseclass = baseclass
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: gamemode
|
||||
Desc: A module to manage gamemodes
|
||||
-----------------------------------------------------------]]
|
||||
module( "gamemode" )
|
||||
|
||||
local GameList = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RegisterGamemode( table, string )
|
||||
Desc: Used to register your gamemode with the engine
|
||||
-----------------------------------------------------------]]
|
||||
function Register( t, name, derived )
|
||||
|
||||
local CurrentGM = gmod.GetGamemode()
|
||||
|
||||
if ( CurrentGM ) then
|
||||
|
||||
if ( CurrentGM.FolderName == name ) then
|
||||
table.Merge( CurrentGM, t )
|
||||
Call( "OnReloaded" );
|
||||
end
|
||||
|
||||
if ( CurrentGM.BaseClass && CurrentGM.BaseClass.FolderName == name ) then
|
||||
table.Merge( CurrentGM.BaseClass, t )
|
||||
Call( "OnReloaded" );
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- This gives the illusion of inheritence
|
||||
if ( name != "base" ) then
|
||||
|
||||
local basetable = Get( derived )
|
||||
if ( basetable ) then
|
||||
t = table.Inherit( t, basetable )
|
||||
else
|
||||
Msg( "Warning: Couldn't find derived gamemode (", derived, ")\n" )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
GameList[ name ] = t
|
||||
|
||||
--
|
||||
-- Using baseclass for gamemodes kind of sucks, because
|
||||
-- the base gamemode is called "base" - and they have to all be unique.
|
||||
-- so here we prefix the gamemode name with "gamemode_" - and when using
|
||||
-- DEFINE_BASECLASS you're expected to do the same.
|
||||
--
|
||||
baseclass.Set( "gamemode_" .. name, t )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Get( string )
|
||||
Desc: Get a gamemode by name.
|
||||
-----------------------------------------------------------]]
|
||||
function Get( name )
|
||||
return GameList[ name ]
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Call( name, args )
|
||||
Desc: Calls a gamemode function
|
||||
-----------------------------------------------------------]]
|
||||
function Call( name, ... )
|
||||
|
||||
local CurrentGM = gmod.GetGamemode()
|
||||
|
||||
-- If the gamemode function doesn't exist just return false
|
||||
if ( CurrentGM && CurrentGM[name] == nil ) then return false end
|
||||
|
||||
return hook.Call( name, CurrentGM, ... )
|
||||
|
||||
end
|
||||
169
lua/includes/modules/halo.lua
Normal file
169
lua/includes/modules/halo.lua
Normal file
@@ -0,0 +1,169 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "halo", package.seeall )
|
||||
|
||||
local mat_Copy = Material( "pp/copy" )
|
||||
local mat_Add = Material( "pp/add" )
|
||||
local mat_Sub = Material( "pp/sub" )
|
||||
local rt_Store = render.GetScreenEffectTexture( 0 )
|
||||
local rt_Blur = render.GetScreenEffectTexture( 1 )
|
||||
|
||||
local List = {}
|
||||
local RenderEnt = NULL
|
||||
|
||||
function Add( entities, color, blurx, blury, passes, add, ignorez )
|
||||
|
||||
if ( table.IsEmpty( entities ) ) then return end
|
||||
if ( add == nil ) then add = true end
|
||||
if ( ignorez == nil ) then ignorez = false end
|
||||
|
||||
local t =
|
||||
{
|
||||
Ents = entities,
|
||||
Color = color,
|
||||
BlurX = blurx or 2,
|
||||
BlurY = blury or 2,
|
||||
DrawPasses = passes or 1,
|
||||
Additive = add,
|
||||
IgnoreZ = ignorez
|
||||
}
|
||||
|
||||
table.insert( List, t )
|
||||
|
||||
end
|
||||
|
||||
function RenderedEntity()
|
||||
return RenderEnt
|
||||
end
|
||||
|
||||
function Render( entry )
|
||||
|
||||
local rt_Scene = render.GetRenderTarget()
|
||||
|
||||
|
||||
-- Store a copy of the original scene
|
||||
render.CopyRenderTargetToTexture( rt_Store )
|
||||
|
||||
|
||||
-- Clear our scene so that additive/subtractive rendering with it will work later
|
||||
if ( entry.Additive ) then
|
||||
render.Clear( 0, 0, 0, 255, false, true )
|
||||
else
|
||||
render.Clear( 255, 255, 255, 255, false, true )
|
||||
end
|
||||
|
||||
|
||||
-- Render colored props to the scene and set their pixels high
|
||||
cam.Start3D()
|
||||
render.SetStencilEnable( true )
|
||||
render.SuppressEngineLighting( true )
|
||||
cam.IgnoreZ( entry.IgnoreZ )
|
||||
|
||||
render.SetStencilWriteMask( 1 )
|
||||
render.SetStencilTestMask( 1 )
|
||||
render.SetStencilReferenceValue( 1 )
|
||||
|
||||
render.SetStencilCompareFunction( STENCIL_ALWAYS )
|
||||
render.SetStencilPassOperation( STENCIL_REPLACE )
|
||||
render.SetStencilFailOperation( STENCIL_KEEP )
|
||||
render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||
|
||||
for k, v in pairs( entry.Ents ) do
|
||||
|
||||
if ( !IsValid( v ) or v:GetNoDraw() ) then continue end
|
||||
|
||||
RenderEnt = v
|
||||
|
||||
v:DrawModel()
|
||||
|
||||
end
|
||||
|
||||
RenderEnt = NULL
|
||||
|
||||
render.SetStencilCompareFunction( STENCIL_EQUAL )
|
||||
render.SetStencilPassOperation( STENCIL_KEEP )
|
||||
-- render.SetStencilFailOperation( STENCIL_KEEP )
|
||||
-- render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||
|
||||
cam.Start2D()
|
||||
surface.SetDrawColor( entry.Color )
|
||||
surface.DrawRect( 0, 0, ScrW(), ScrH() )
|
||||
cam.End2D()
|
||||
|
||||
cam.IgnoreZ( false )
|
||||
render.SuppressEngineLighting( false )
|
||||
render.SetStencilEnable( false )
|
||||
cam.End3D()
|
||||
|
||||
|
||||
-- Store a blurred version of the colored props in an RT
|
||||
render.CopyRenderTargetToTexture( rt_Blur )
|
||||
render.BlurRenderTarget( rt_Blur, entry.BlurX, entry.BlurY, 1 )
|
||||
|
||||
|
||||
-- Restore the original scene
|
||||
render.SetRenderTarget( rt_Scene )
|
||||
mat_Copy:SetTexture( "$basetexture", rt_Store )
|
||||
mat_Copy:SetString( "$color", "1 1 1" )
|
||||
mat_Copy:SetString( "$alpha", "1" )
|
||||
render.SetMaterial( mat_Copy )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
|
||||
-- Draw back our blured colored props additively/subtractively, ignoring the high bits
|
||||
render.SetStencilEnable( true )
|
||||
|
||||
render.SetStencilCompareFunction( STENCIL_NOTEQUAL )
|
||||
-- render.SetStencilPassOperation( STENCIL_KEEP )
|
||||
-- render.SetStencilFailOperation( STENCIL_KEEP )
|
||||
-- render.SetStencilZFailOperation( STENCIL_KEEP )
|
||||
|
||||
if ( entry.Additive ) then
|
||||
|
||||
mat_Add:SetTexture( "$basetexture", rt_Blur )
|
||||
render.SetMaterial( mat_Add )
|
||||
|
||||
else
|
||||
|
||||
mat_Sub:SetTexture( "$basetexture", rt_Blur )
|
||||
render.SetMaterial( mat_Sub )
|
||||
|
||||
end
|
||||
|
||||
for i = 0, entry.DrawPasses do
|
||||
|
||||
render.DrawScreenQuad()
|
||||
|
||||
end
|
||||
|
||||
render.SetStencilEnable( false )
|
||||
|
||||
|
||||
-- Return original values
|
||||
render.SetStencilTestMask( 0 )
|
||||
render.SetStencilWriteMask( 0 )
|
||||
render.SetStencilReferenceValue( 0 )
|
||||
end
|
||||
|
||||
hook.Add( "PostDrawEffects", "RenderHalos", function()
|
||||
|
||||
hook.Run( "PreDrawHalos" )
|
||||
|
||||
if ( #List == 0 ) then return end
|
||||
|
||||
for k, v in ipairs( List ) do
|
||||
Render( v )
|
||||
end
|
||||
|
||||
List = {}
|
||||
|
||||
end )
|
||||
286
lua/includes/modules/hook.lua
Normal file
286
lua/includes/modules/hook.lua
Normal file
@@ -0,0 +1,286 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local gmod = gmod
|
||||
local pairs = pairs
|
||||
local setmetatable = setmetatable
|
||||
local isstring = isstring
|
||||
local isnumber = isnumber
|
||||
local isbool = isbool
|
||||
local isfunction = isfunction
|
||||
local insert = table.insert
|
||||
local IsValid = IsValid
|
||||
local type = type
|
||||
local ErrorNoHaltWithStack = ErrorNoHaltWithStack
|
||||
|
||||
-- I just do this so glua-lint doesn't rage at me
|
||||
do
|
||||
_G.HOOK_MONITOR_HIGH = -2
|
||||
_G.HOOK_HIGH = -1
|
||||
_G.HOOK_NORMAL = 0
|
||||
_G.HOOK_LOW = 1
|
||||
_G.HOOK_MONITOR_LOW = 2
|
||||
end
|
||||
|
||||
local HOOK_MONITOR_HIGH = HOOK_MONITOR_HIGH
|
||||
local HOOK_HIGH = HOOK_HIGH
|
||||
local HOOK_NORMAL = HOOK_NORMAL
|
||||
local HOOK_LOW = HOOK_LOW
|
||||
local HOOK_MONITOR_LOW = HOOK_MONITOR_LOW
|
||||
|
||||
module("hook")
|
||||
|
||||
local events = {}
|
||||
|
||||
local function find_hook(event, name)
|
||||
for i = 1, event.n, 4 do
|
||||
local _name = event[i]
|
||||
if _name and _name == name then
|
||||
return i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
we are making a new event table so we don't mess up anything
|
||||
when adding/removing hooks while hook.Call is running, this is how it works:
|
||||
|
||||
1- When (adding/removing a hook)/(editing a hook priority), we create a new event table to avoid messing up hook.Call call order if it's running,
|
||||
and the old event table will be shadowed and can only be accessed from hook.Call if it's running
|
||||
2- We make old event table have __index method to make sure if any hook got removed/edited we (stop it from running)/(run the new function)
|
||||
]]
|
||||
local function copy_event(event, event_name)
|
||||
local new_event = {}
|
||||
do
|
||||
for i = 1, event.n do
|
||||
local v = event[i]
|
||||
if v then
|
||||
insert(new_event, v)
|
||||
end
|
||||
end
|
||||
new_event.n = #new_event
|
||||
end
|
||||
|
||||
-- we use proxies here just to make __index work
|
||||
-- https://stackoverflow.com/a/3122136
|
||||
local proxy = {}
|
||||
do
|
||||
for i = 1, event.n do
|
||||
proxy[i] = event[i]
|
||||
event[i] = nil
|
||||
end
|
||||
proxy.n = event.n
|
||||
event.n = nil
|
||||
end
|
||||
|
||||
setmetatable(event, {
|
||||
__index = function(_, key)
|
||||
-- make event.n work
|
||||
if isstring(key) then
|
||||
return proxy[key]
|
||||
end
|
||||
|
||||
local name = proxy[key - 1]
|
||||
if not name then return end
|
||||
|
||||
local parent = events[event_name]
|
||||
|
||||
-- if hook got removed then don't run it
|
||||
local pos = find_hook(parent, name)
|
||||
if not pos then return end
|
||||
|
||||
-- if hook priority changed then it should be treated as a new hook, don't run it
|
||||
if parent[pos + 3 --[[priority]]] ~= proxy[key + 2 --[[priority]]] then return end
|
||||
|
||||
return parent[pos + 1]
|
||||
end
|
||||
})
|
||||
|
||||
return new_event
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Add
|
||||
Args: string hookName, any identifier, function func
|
||||
Desc: Add a hook to listen to the specified event.
|
||||
-----------------------------------------------------------]]
|
||||
function Add(event_name, name, func, priority)
|
||||
if not isstring(event_name) then ErrorNoHaltWithStack("bad argument #1 to 'Add' (string expected, got " .. type(event_name) .. ")") return end
|
||||
if not isfunction(func) then ErrorNoHaltWithStack("bad argument #3 to 'Add' (function expected, got " .. type(func) .. ")") return end
|
||||
|
||||
local notValid = name == nil or isnumber(name) or isbool(name) or isfunction(name) or not name.IsValid or not IsValid(name)
|
||||
if not isstring(name) and notValid then ErrorNoHaltWithStack("bad argument #2 to 'Add' (string expected, got " .. type(name) .. ")") return end
|
||||
|
||||
local real_func = func
|
||||
if not isstring(name) then
|
||||
func = function(...)
|
||||
local isvalid = name.IsValid
|
||||
if isvalid and isvalid(name) then
|
||||
return real_func(name, ...)
|
||||
end
|
||||
|
||||
Remove(event_name, name)
|
||||
end
|
||||
end
|
||||
|
||||
if not isnumber(priority) then
|
||||
priority = HOOK_NORMAL
|
||||
elseif priority < HOOK_MONITOR_HIGH then
|
||||
priority = HOOK_MONITOR_HIGH
|
||||
elseif priority > HOOK_MONITOR_LOW then
|
||||
priority = HOOK_MONITOR_LOW
|
||||
end
|
||||
|
||||
-- disallow returning in monitor hooks
|
||||
if priority == HOOK_MONITOR_HIGH or priority == HOOK_MONITOR_LOW then
|
||||
local _func = func
|
||||
func = function(...)
|
||||
_func(...)
|
||||
end
|
||||
end
|
||||
|
||||
local event = events[event_name]
|
||||
if not event then
|
||||
event = {
|
||||
n = 0,
|
||||
}
|
||||
events[event_name] = event
|
||||
end
|
||||
|
||||
local pos
|
||||
if event then
|
||||
local _pos = find_hook(event, name)
|
||||
-- if hook exists and priority changed then remove the old one because it has to be treated as a new hook
|
||||
if _pos and event[_pos + 3] ~= priority then
|
||||
Remove(event_name, name)
|
||||
else
|
||||
-- just update the hook here because nothing changed but the function
|
||||
pos = _pos
|
||||
end
|
||||
end
|
||||
|
||||
event = events[event_name]
|
||||
|
||||
if pos then
|
||||
event[pos + 1] = func
|
||||
event[pos + 2] = real_func
|
||||
return
|
||||
end
|
||||
|
||||
if priority == HOOK_MONITOR_LOW then
|
||||
local n = event.n
|
||||
event[n + 1] = name
|
||||
event[n + 2] = func
|
||||
event[n + 3] = real_func
|
||||
event[n + 4] = priority
|
||||
else
|
||||
local event_pos = 4
|
||||
for i = 4, event.n, 4 do
|
||||
local _priority = event[i]
|
||||
if priority < _priority then
|
||||
if i < event_pos then
|
||||
event_pos = i
|
||||
end
|
||||
elseif priority >= _priority then
|
||||
event_pos = i + 4
|
||||
end
|
||||
end
|
||||
insert(event, event_pos - 3, name)
|
||||
insert(event, event_pos - 2, func)
|
||||
insert(event, event_pos - 1, real_func)
|
||||
insert(event, event_pos, priority)
|
||||
end
|
||||
|
||||
event.n = event.n + 4
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Remove
|
||||
Args: string hookName, identifier
|
||||
Desc: Removes the hook with the given indentifier.
|
||||
-----------------------------------------------------------]]
|
||||
function Remove(event_name, name)
|
||||
local event = events[event_name]
|
||||
if not event then return end
|
||||
|
||||
local pos = find_hook(event, name)
|
||||
if pos then
|
||||
event[pos] = nil --[[name]]
|
||||
event[pos + 1] = nil --[[func]]
|
||||
event[pos + 2] = nil --[[real_func]]
|
||||
event[pos + 3] = nil --[[priority]]
|
||||
end
|
||||
|
||||
events[event_name] = copy_event(event, event_name)
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTable
|
||||
Desc: Returns a table of all hooks.
|
||||
-----------------------------------------------------------]]
|
||||
function GetTable()
|
||||
local new_events = {}
|
||||
|
||||
for event_name, event in pairs(events) do
|
||||
local hooks = {}
|
||||
for i = 1, event.n, 4 do
|
||||
local name = event[i]
|
||||
if name then
|
||||
hooks[name] = event[i + 2] --[[real_func]]
|
||||
end
|
||||
end
|
||||
new_events[event_name] = hooks
|
||||
end
|
||||
|
||||
return new_events
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Call
|
||||
Args: string hookName, table gamemodeTable, vararg args
|
||||
Desc: Calls hooks associated with the hook name.
|
||||
-----------------------------------------------------------]]
|
||||
function Call(event_name, gm, ...)
|
||||
local event = events[event_name]
|
||||
if event then
|
||||
local i, n = 2, event.n
|
||||
::loop::
|
||||
local func = event[i]
|
||||
if func then
|
||||
local a, b, c, d, e, f = func(...)
|
||||
if a ~= nil then
|
||||
return a, b, c, d, e, f
|
||||
end
|
||||
end
|
||||
i = i + 4
|
||||
if i <= n then
|
||||
goto loop
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Call the gamemode function
|
||||
--
|
||||
if not gm then return end
|
||||
|
||||
local GamemodeFunction = gm[event_name]
|
||||
if not GamemodeFunction then return end
|
||||
|
||||
return GamemodeFunction(gm, ...)
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Run
|
||||
Args: string hookName, vararg args
|
||||
Desc: Calls hooks associated with the hook name.
|
||||
-----------------------------------------------------------]]
|
||||
function Run(name, ...)
|
||||
return Call(name, gmod and gmod.GetGamemode() or nil, ...)
|
||||
end
|
||||
117
lua/includes/modules/http.lua
Normal file
117
lua/includes/modules/http.lua
Normal file
@@ -0,0 +1,117 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local HTTP = HTTP
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
HTTP Module. Interaction with HTTP.
|
||||
-----------------------------------------------------------]]
|
||||
module( "http" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Get the contents of a webpage.
|
||||
|
||||
Callback should be
|
||||
|
||||
function callback( (args optional), contents, size )
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function Fetch( url, onsuccess, onfailure, header )
|
||||
|
||||
local request = {
|
||||
url = url,
|
||||
method = "get",
|
||||
headers = header or {},
|
||||
|
||||
success = function( code, body, headers )
|
||||
|
||||
if ( !onsuccess ) then return end
|
||||
|
||||
onsuccess( body, body:len(), headers, code )
|
||||
|
||||
end,
|
||||
|
||||
failed = function( err )
|
||||
|
||||
if ( !onfailure ) then return end
|
||||
|
||||
onfailure( err )
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
local success = HTTP( request )
|
||||
if ( !success && onfailure ) then onfailure( "HTTP failed" ) end
|
||||
|
||||
end
|
||||
|
||||
function Post( url, params, onsuccess, onfailure, header )
|
||||
|
||||
local request = {
|
||||
url = url,
|
||||
method = "post",
|
||||
parameters = params,
|
||||
headers = header or {},
|
||||
|
||||
success = function( code, body, headers )
|
||||
|
||||
if ( !onsuccess ) then return end
|
||||
|
||||
onsuccess( body, body:len(), headers, code )
|
||||
|
||||
end,
|
||||
|
||||
failed = function( err )
|
||||
|
||||
if ( !onfailure ) then return end
|
||||
|
||||
onfailure( err )
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
local success = HTTP( request )
|
||||
if ( !success && onfailure ) then onfailure( "HTTP failed" ) end
|
||||
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
Or use HTTP( table )
|
||||
|
||||
local request = {
|
||||
url = "http://pastebin.com/raw.php?i=3jsf50nL",
|
||||
method = "post",
|
||||
|
||||
parameters = {
|
||||
id = "548",
|
||||
country = "England"
|
||||
}
|
||||
|
||||
success = function( code, body, headers )
|
||||
|
||||
Msg( "Request Successful\n" )
|
||||
Msg( "Code: ", code, "\n" )
|
||||
Msg( "Body Length:\n", body:len(), "\n" )
|
||||
Msg( "Body:\n", body, "\n" )
|
||||
PrintTable( headers )
|
||||
|
||||
end,
|
||||
|
||||
failed = function( reason )
|
||||
Msg( "Request failed: ", reason, "\n" )
|
||||
end
|
||||
}
|
||||
|
||||
HTTP( request )
|
||||
|
||||
--]]
|
||||
215
lua/includes/modules/killicon.lua
Normal file
215
lua/includes/modules/killicon.lua
Normal file
@@ -0,0 +1,215 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Globals that we need
|
||||
local surface = surface
|
||||
local Msg = Msg
|
||||
local Color = Color
|
||||
local Material = Material
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: killicon
|
||||
Desc: Stores and serves killicons for deathnotice
|
||||
-----------------------------------------------------------]]
|
||||
module( "killicon" )
|
||||
|
||||
local Icons = {}
|
||||
local TYPE_FONT = 0
|
||||
local TYPE_MATERIAL = 1
|
||||
local TYPE_MATERIAL_UV = 2
|
||||
|
||||
function AddFont( name, font, character, color, heightScale )
|
||||
|
||||
Icons[name] = {
|
||||
type = TYPE_FONT,
|
||||
font = font,
|
||||
character = character,
|
||||
color = color or Color( 255, 80, 0 ),
|
||||
|
||||
-- Correct certain icons
|
||||
heightScale = heightScale
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function Add( name, material, color )
|
||||
|
||||
Icons[name] = {
|
||||
type = TYPE_MATERIAL,
|
||||
material = Material( material ),
|
||||
color = color or Color( 255, 255, 255 )
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function AddTexCoord( name, material, color, x, y, w, h )
|
||||
|
||||
Icons[name] = {
|
||||
type = TYPE_MATERIAL_UV,
|
||||
material = Material( material ),
|
||||
color = color,
|
||||
tex_x = x,
|
||||
tex_y = y,
|
||||
tex_w = w,
|
||||
tex_h = h
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function AddAlias( name, alias )
|
||||
|
||||
Icons[name] = Icons[alias]
|
||||
|
||||
end
|
||||
|
||||
function Exists( name )
|
||||
|
||||
return Icons[name] != nil
|
||||
|
||||
end
|
||||
|
||||
function GetSize( name, dontEqualizeHeight )
|
||||
|
||||
if ( !Icons[name] ) then
|
||||
Msg( "Warning: killicon not found '" .. name .. "'\n" )
|
||||
Icons[name] = Icons["default"]
|
||||
end
|
||||
|
||||
local t = Icons[name]
|
||||
|
||||
-- Check the cache
|
||||
if ( t.size ) then
|
||||
|
||||
-- Maintain the old behavior
|
||||
if ( !dontEqualizeHeight ) then return t.size.adj_w, t.size.adj_h end
|
||||
|
||||
return t.size.w, t.size.h
|
||||
end
|
||||
|
||||
local w, h = 0, 0
|
||||
|
||||
if ( t.type == TYPE_FONT ) then
|
||||
|
||||
surface.SetFont( t.font )
|
||||
w, h = surface.GetTextSize( t.character )
|
||||
|
||||
if ( t.heightScale ) then h = h * t.heightScale end
|
||||
|
||||
elseif ( t.type == TYPE_MATERIAL ) then
|
||||
|
||||
w, h = t.material:Width(), t.material:Height()
|
||||
|
||||
elseif ( t.type == TYPE_MATERIAL_UV ) then
|
||||
|
||||
w = t.tex_w
|
||||
h = t.tex_h
|
||||
|
||||
end
|
||||
|
||||
t.size = {}
|
||||
t.size.w = w or 32
|
||||
t.size.h = h or 32
|
||||
|
||||
-- Height adjusted behavior
|
||||
if ( t.type == TYPE_FONT ) then
|
||||
t.size.adj_w, t.size.adj_h = surface.GetTextSize( t.character )
|
||||
-- BUG: This is not same height as the texture icons, and we cannot change it beacuse backwards compability
|
||||
else
|
||||
surface.SetFont( "HL2MPTypeDeath" )
|
||||
local _, fh = surface.GetTextSize( "0" )
|
||||
fh = fh * 0.75 -- Fudge it slightly
|
||||
|
||||
-- Resize, maintaining aspect ratio
|
||||
t.size.adj_w = w * ( fh / h )
|
||||
t.size.adj_h = fh
|
||||
end
|
||||
|
||||
-- Maintain the old behavior
|
||||
if ( !dontEqualizeHeight ) then return t.size.adj_w, t.size.adj_h end
|
||||
|
||||
return w, h
|
||||
|
||||
end
|
||||
|
||||
local function DrawInternal( x, y, name, alpha, noCorrections, dontEqualizeHeight )
|
||||
|
||||
alpha = alpha or 255
|
||||
|
||||
if ( !Icons[name] ) then
|
||||
Msg( "Warning: killicon not found '" .. name .. "'\n" )
|
||||
Icons[name] = Icons["default"]
|
||||
end
|
||||
|
||||
local t = Icons[name]
|
||||
|
||||
local w, h = GetSize( name, dontEqualizeHeight )
|
||||
|
||||
if ( !noCorrections ) then x = x - w * 0.5 end
|
||||
|
||||
if ( t.type == TYPE_FONT ) then
|
||||
|
||||
-- HACK: Default font killicons are anchored to the top, so correct for it
|
||||
if ( noCorrections && !dontEqualizeHeight ) then
|
||||
local _, h2 = GetSize( name, !dontEqualizeHeight )
|
||||
y = y + ( h - h2 ) / 2
|
||||
end
|
||||
|
||||
if ( !noCorrections ) then y = y - h * 0.1 end
|
||||
|
||||
surface.SetTextPos( x, y )
|
||||
surface.SetFont( t.font )
|
||||
surface.SetTextColor( t.color.r, t.color.g, t.color.b, alpha )
|
||||
surface.DrawText( t.character )
|
||||
|
||||
end
|
||||
|
||||
if ( t.type == TYPE_MATERIAL ) then
|
||||
|
||||
if ( !noCorrections ) then y = y - h * 0.3 end
|
||||
|
||||
surface.SetMaterial( t.material )
|
||||
surface.SetDrawColor( t.color.r, t.color.g, t.color.b, alpha )
|
||||
surface.DrawTexturedRect( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
if ( t.type == TYPE_MATERIAL_UV ) then
|
||||
|
||||
if ( !noCorrections ) then y = y - h * 0.3 end
|
||||
|
||||
local tw = t.material:Width()
|
||||
local th = t.material:Height()
|
||||
surface.SetMaterial( t.material )
|
||||
surface.SetDrawColor( t.color.r, t.color.g, t.color.b, alpha )
|
||||
surface.DrawTexturedRectUV( x, y, w, h, t.tex_x / tw, t.tex_y / th, ( t.tex_x + t.tex_w ) / tw, ( t.tex_y + t.tex_h ) / th )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Old function with weird vertical adjustments
|
||||
function Draw( x, y, name, alpha )
|
||||
|
||||
DrawInternal( x, y, name, alpha )
|
||||
|
||||
end
|
||||
|
||||
-- The new function that doesn't have the weird vertical adjustments
|
||||
function Render( x, y, name, alpha, dontEqualizeHeight )
|
||||
|
||||
DrawInternal( x, y, name, alpha, true, dontEqualizeHeight )
|
||||
|
||||
end
|
||||
|
||||
local Color_Icon = Color( 255, 80, 0, 255 )
|
||||
|
||||
Add( "default", "HUD/killicons/default", Color_Icon )
|
||||
AddAlias( "suicide", "default" )
|
||||
76
lua/includes/modules/list.lua
Normal file
76
lua/includes/modules/list.lua
Normal file
@@ -0,0 +1,76 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local table = table
|
||||
local pairs = pairs
|
||||
|
||||
module( "list" )
|
||||
|
||||
|
||||
local Lists = {}
|
||||
|
||||
function Get( listid )
|
||||
|
||||
return table.Copy( GetForEdit( listid ) )
|
||||
|
||||
end
|
||||
|
||||
function GetForEdit( listid, nocreate )
|
||||
|
||||
local list = Lists[ listid ]
|
||||
|
||||
if ( !nocreate && list == nil ) then
|
||||
list = {}
|
||||
Lists[ listid ] = list
|
||||
end
|
||||
|
||||
return list
|
||||
|
||||
end
|
||||
|
||||
function GetTable()
|
||||
|
||||
return table.GetKeys( Lists )
|
||||
|
||||
end
|
||||
|
||||
function Set( listid, key, value )
|
||||
|
||||
GetForEdit( listid )[ key ] = value
|
||||
|
||||
end
|
||||
|
||||
function Add( listid, value )
|
||||
|
||||
return table.insert( GetForEdit( listid ), value )
|
||||
|
||||
end
|
||||
|
||||
function Contains( listid, value )
|
||||
|
||||
local list = Lists[ listid ]
|
||||
if ( list == nil ) then return false end
|
||||
|
||||
for k, v in pairs( list ) do
|
||||
if ( v == value ) then return true end
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function HasEntry( listid, key )
|
||||
|
||||
local list = Lists[ listid ]
|
||||
|
||||
return list != nil && list[ key ] != nil
|
||||
|
||||
end
|
||||
568
lua/includes/modules/markup.lua
Normal file
568
lua/includes/modules/markup.lua
Normal file
@@ -0,0 +1,568 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local string = string
|
||||
local table = table
|
||||
local surface = surface
|
||||
local tostring = tostring
|
||||
local ipairs = ipairs
|
||||
local setmetatable = setmetatable
|
||||
local tonumber = tonumber
|
||||
local math = math
|
||||
local utf8 = utf8
|
||||
local _Color = Color
|
||||
|
||||
local MarkupObject = {}
|
||||
MarkupObject.__index = MarkupObject
|
||||
debug.getregistry().MarkupObject = MarkupObject
|
||||
|
||||
module("markup")
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Constants used for text alignment.
|
||||
These must be the same values as in the draw module.
|
||||
-----------------------------------------------------------]]
|
||||
TEXT_ALIGN_LEFT = 0
|
||||
TEXT_ALIGN_CENTER = 1
|
||||
TEXT_ALIGN_RIGHT = 2
|
||||
TEXT_ALIGN_TOP = 3
|
||||
TEXT_ALIGN_BOTTOM = 4
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Color(Color(r, g, b, a))
|
||||
Desc: Convenience function which converts a Color object into a string
|
||||
which can be used in the <color=r,g,b,a></color> tag
|
||||
|
||||
e.g. Color(255, 0, 0, 150) -> 255,0,0,150
|
||||
Color(255, 0, 0) -> 255,0,0
|
||||
Color(255, 0, 0, 255) -> 255,0,0
|
||||
|
||||
Usage: markup.Color(Color(r, g, b, a))
|
||||
-----------------------------------------------------------]]
|
||||
function Color( col )
|
||||
return
|
||||
col.r .. "," ..
|
||||
col.g .. "," ..
|
||||
col.b ..
|
||||
-- If the alpha value is 255, we don't need to include it in the <color> tag, so just omit it:
|
||||
( col.a == 255 and "" or ( "," .. col.a ) )
|
||||
end
|
||||
|
||||
local Color = _Color
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Temporary information used when building text frames.
|
||||
-----------------------------------------------------------]]
|
||||
local colour_stack = { Color( 255, 255, 255 ) }
|
||||
local font_stack = { "DermaDefault" }
|
||||
local blocks = {}
|
||||
|
||||
local colourmap = {
|
||||
|
||||
-- it's all black and white
|
||||
["black"] = Color( 0, 0, 0 ),
|
||||
["white"] = Color( 255, 255, 255 ),
|
||||
|
||||
-- it's greys
|
||||
["dkgrey"] = Color( 64, 64, 64 ),
|
||||
["grey"] = Color( 128, 128, 128 ),
|
||||
["ltgrey"] = Color( 192, 192, 192 ),
|
||||
|
||||
-- account for speeling mistakes
|
||||
["dkgray"] = Color( 64, 64, 64 ),
|
||||
["gray"] = Color( 128, 128, 128 ),
|
||||
["ltgray"] = Color( 192, 192, 192 ),
|
||||
|
||||
-- normal colours
|
||||
["red"] = Color( 255, 0, 0 ),
|
||||
["green"] = Color( 0, 255, 0 ),
|
||||
["blue"] = Color( 0, 0, 255 ),
|
||||
["yellow"] = Color( 255, 255, 0 ),
|
||||
["purple"] = Color( 255, 0, 255 ),
|
||||
["cyan"] = Color( 0, 255, 255 ),
|
||||
["turq"] = Color( 0, 255, 255 ),
|
||||
|
||||
-- dark variations
|
||||
["dkred"] = Color( 128, 0, 0 ),
|
||||
["dkgreen"] = Color( 0, 128, 0 ),
|
||||
["dkblue"] = Color( 0, 0, 128 ),
|
||||
["dkyellow"] = Color( 128, 128, 0 ),
|
||||
["dkpurple"] = Color( 128, 0, 128 ),
|
||||
["dkcyan"] = Color( 0, 128, 128 ),
|
||||
["dkturq"] = Color( 0, 128, 128 ),
|
||||
|
||||
-- light variations
|
||||
["ltred"] = Color( 255, 128, 128 ),
|
||||
["ltgreen"] = Color( 128, 255, 128 ),
|
||||
["ltblue"] = Color( 128, 128, 255 ),
|
||||
["ltyellow"] = Color( 255, 255, 128 ),
|
||||
["ltpurple"] = Color( 255, 128, 255 ),
|
||||
["ltcyan"] = Color( 128, 255, 255 ),
|
||||
["ltturq"] = Color( 128, 255, 255 ),
|
||||
|
||||
}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: colourMatch(c)
|
||||
Desc: Match a colour name to an rgb value.
|
||||
Usage: ** INTERNAL ** Do not use!
|
||||
-----------------------------------------------------------]]
|
||||
local function colourMatch( c )
|
||||
return colourmap[ string.lower( c ) ]
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ExtractParams(p1,p2,p3)
|
||||
Desc: This function is used to extract the tag information.
|
||||
Usage: ** INTERNAL ** Do not use!
|
||||
-----------------------------------------------------------]]
|
||||
local function ExtractParams( p1, p2, p3 )
|
||||
|
||||
if ( string.sub( p1, 1, 1 ) == "/" ) then
|
||||
|
||||
local tag = string.sub( p1, 2 )
|
||||
|
||||
if ( tag == "color" or tag == "colour" ) then
|
||||
table.remove( colour_stack )
|
||||
elseif ( tag == "font" or tag == "face" ) then
|
||||
table.remove( font_stack )
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if ( p1 == "color" or p1 == "colour" ) then
|
||||
|
||||
local rgba = colourMatch( p2 )
|
||||
|
||||
if ( rgba == nil ) then
|
||||
rgba = Color( 255, 255, 255, 255 )
|
||||
local x = { "r", "g", "b", "a" }
|
||||
local n = 1
|
||||
for k, v in string.gmatch( p2, "(%d+),?" ) do
|
||||
rgba[ x[ n ] ] = tonumber( k )
|
||||
n = n + 1
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( colour_stack, rgba )
|
||||
|
||||
elseif ( p1 == "font" or p1 == "face" ) then
|
||||
|
||||
table.insert( font_stack, tostring( p2 ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CheckTextOrTag(p)
|
||||
Desc: This function places data in the "blocks" table
|
||||
depending of if p is a tag, or some text
|
||||
Usage: ** INTERNAL ** Do not use!
|
||||
-----------------------------------------------------------]]
|
||||
local function CheckTextOrTag( p )
|
||||
if ( p == "" ) then return end
|
||||
if ( p == nil ) then return end
|
||||
|
||||
if ( string.sub( p, 1, 1 ) == "<" ) then
|
||||
string.gsub( p, "<([/%a]*)=?([^>]*)", ExtractParams )
|
||||
else
|
||||
|
||||
local text_block = {}
|
||||
text_block.text = p
|
||||
text_block.colour = colour_stack[ #colour_stack ]
|
||||
text_block.font = font_stack[ #font_stack ]
|
||||
table.insert( blocks, text_block )
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ProcessMatches(p1,p2,p3)
|
||||
Desc: CheckTextOrTag for 3 parameters. Called by string.gsub
|
||||
Usage: ** INTERNAL ** Do not use!
|
||||
-----------------------------------------------------------]]
|
||||
local function ProcessMatches( p1, p2, p3 )
|
||||
if ( p1 ) then CheckTextOrTag( p1 ) end
|
||||
if ( p2 ) then CheckTextOrTag( p2 ) end
|
||||
if ( p3 ) then CheckTextOrTag( p3 ) end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MarkupObject:GetWidth()
|
||||
Desc: Returns the width of a markup block
|
||||
Usage: ml:GetWidth()
|
||||
-----------------------------------------------------------]]
|
||||
function MarkupObject:GetWidth()
|
||||
return self.totalWidth
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MarkupObject:GetMaxWidth()
|
||||
Desc: Returns the maximum width of a markup block
|
||||
Usage: ml:GetMaxWidth()
|
||||
-----------------------------------------------------------]]
|
||||
function MarkupObject:GetMaxWidth()
|
||||
return self.maxWidth or self.totalWidth
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MarkupObject:GetHeight()
|
||||
Desc: Returns the height of a markup block
|
||||
Usage: ml:GetHeight()
|
||||
-----------------------------------------------------------]]
|
||||
function MarkupObject:GetHeight()
|
||||
return self.totalHeight
|
||||
end
|
||||
|
||||
function MarkupObject:Size()
|
||||
return self.totalWidth, self.totalHeight
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MarkupObject:Draw(xOffset, yOffset, halign, valign, alphaoverride)
|
||||
Desc: Draw the markup text to the screen as position xOffset, yOffset.
|
||||
Halign and Valign can be used to align the text relative to its offset.
|
||||
Alphaoverride can be used to override the alpha value of the text-colour.
|
||||
textAlign can be used to align the actual text inside of its bounds.
|
||||
Usage: MarkupObject:Draw(100, 100)
|
||||
-----------------------------------------------------------]]
|
||||
function MarkupObject:Draw( xOffset, yOffset, halign, valign, alphaoverride, textAlign )
|
||||
for i, blk in ipairs( self.blocks ) do
|
||||
local y = yOffset + ( blk.height - blk.thisY ) + blk.offset.y
|
||||
local x = xOffset
|
||||
|
||||
if ( halign == TEXT_ALIGN_CENTER ) then x = x - ( self.totalWidth / 2 )
|
||||
elseif ( halign == TEXT_ALIGN_RIGHT ) then x = x - self.totalWidth
|
||||
end
|
||||
|
||||
x = x + blk.offset.x
|
||||
|
||||
if ( valign == TEXT_ALIGN_CENTER ) then y = y - ( self.totalHeight / 2 )
|
||||
elseif ( valign == TEXT_ALIGN_BOTTOM ) then y = y - self.totalHeight
|
||||
end
|
||||
|
||||
local alpha = blk.colour.a
|
||||
if ( alphaoverride ) then alpha = alphaoverride end
|
||||
|
||||
surface.SetFont( blk.font )
|
||||
surface.SetTextColor( blk.colour.r, blk.colour.g, blk.colour.b, alpha )
|
||||
|
||||
surface.SetTextPos( x, y )
|
||||
if ( textAlign ~= TEXT_ALIGN_LEFT ) then
|
||||
local lineWidth = self.lineWidths[ blk.offset.y ]
|
||||
if ( lineWidth ) then
|
||||
if ( textAlign == TEXT_ALIGN_CENTER ) then
|
||||
surface.SetTextPos( x + ( ( self.totalWidth - lineWidth ) / 2 ), y )
|
||||
elseif ( textAlign == TEXT_ALIGN_RIGHT ) then
|
||||
surface.SetTextPos( x + ( self.totalWidth - lineWidth ), y )
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
surface.DrawText( blk.text )
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Escape(str)
|
||||
Desc: Converts a string to its escaped, markup-safe equivalent
|
||||
Usage: markup.Escape("<font=Default>The font will remain unchanged & these < > & symbols will also appear normally</font>")
|
||||
-----------------------------------------------------------]]
|
||||
local escapeEntities, unescapeEntities = {
|
||||
["&"] = "&",
|
||||
["<"] = "<",
|
||||
[">"] = ">"
|
||||
}, {
|
||||
["&"] = "&",
|
||||
["<"] = "<",
|
||||
[">"] = ">"
|
||||
}
|
||||
function Escape( str )
|
||||
return ( string.gsub( tostring( str ), "[&<>]", escapeEntities ) )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Parse(ml, maxwidth)
|
||||
Desc: Parses the pseudo-html markup language, and creates a
|
||||
MarkupObject, which can be used to the draw the
|
||||
text to the screen. Valid tags are: font and colour.
|
||||
\n and \t are also available to move to the next line,
|
||||
or insert a tab character.
|
||||
Maxwidth can be used to make the text wrap to a specific
|
||||
width and allows for text alignment (e.g. centering) inside
|
||||
the bounds.
|
||||
Usage: markup.Parse("<font=Default>changed font</font>\n<colour=255,0,255,255>changed colour</colour>")
|
||||
-----------------------------------------------------------]]
|
||||
function Parse( ml, maxwidth )
|
||||
|
||||
ml = utf8.force( ml ) -- Ensure we have valid UTF-8 data
|
||||
|
||||
colour_stack = { Color( 255, 255, 255 ) }
|
||||
font_stack = { "DermaDefault" }
|
||||
blocks = {}
|
||||
|
||||
if ( !string.find( ml, "<" ) ) then
|
||||
ml = ml .. "<nop>"
|
||||
end
|
||||
|
||||
string.gsub( ml, "([^<>]*)(<[^>]+.)([^<>]*)", ProcessMatches )
|
||||
|
||||
local xOffset = 0
|
||||
local yOffset = 0
|
||||
local xSize = 0
|
||||
local xMax = 0
|
||||
local thisMaxY = 0
|
||||
local new_block_list = {}
|
||||
local ymaxes = {}
|
||||
local lineWidths = {}
|
||||
|
||||
local lineHeight = 0
|
||||
for i, blk in ipairs( blocks ) do
|
||||
|
||||
surface.SetFont( blk.font )
|
||||
|
||||
blk.text = string.gsub( blk.text, "(&.-;)", unescapeEntities )
|
||||
|
||||
local thisY = 0
|
||||
local curString = ""
|
||||
for j, c in utf8.codes( blk.text ) do
|
||||
|
||||
local ch = utf8.char( c )
|
||||
|
||||
if ( ch == "\n" ) then
|
||||
|
||||
if ( thisY == 0 ) then
|
||||
thisY = lineHeight
|
||||
thisMaxY = lineHeight
|
||||
else
|
||||
lineHeight = thisY
|
||||
end
|
||||
|
||||
if ( string.len( curString ) > 0 ) then
|
||||
local x1 = surface.GetTextSize( curString )
|
||||
|
||||
local new_block = {
|
||||
text = curString,
|
||||
font = blk.font,
|
||||
colour = blk.colour,
|
||||
thisY = thisY,
|
||||
thisX = x1,
|
||||
offset = {
|
||||
x = xOffset,
|
||||
y = yOffset
|
||||
}
|
||||
}
|
||||
table.insert( new_block_list, new_block )
|
||||
if ( xOffset + x1 > xMax ) then
|
||||
xMax = xOffset + x1
|
||||
end
|
||||
end
|
||||
|
||||
xOffset = 0
|
||||
xSize = 0
|
||||
yOffset = yOffset + thisMaxY
|
||||
thisY = 0
|
||||
curString = ""
|
||||
thisMaxY = 0
|
||||
|
||||
elseif ( ch == "\t" ) then
|
||||
|
||||
if ( string.len( curString ) > 0 ) then
|
||||
local x1 = surface.GetTextSize( curString )
|
||||
|
||||
local new_block = {
|
||||
text = curString,
|
||||
font = blk.font,
|
||||
colour = blk.colour,
|
||||
thisY = thisY,
|
||||
thisX = x1,
|
||||
offset = {
|
||||
x = xOffset,
|
||||
y = yOffset
|
||||
}
|
||||
}
|
||||
table.insert( new_block_list, new_block )
|
||||
if ( xOffset + x1 > xMax ) then
|
||||
xMax = xOffset + x1
|
||||
end
|
||||
end
|
||||
|
||||
curString = ""
|
||||
|
||||
local xOldSize = xSize
|
||||
xSize = 0
|
||||
local xOldOffset = xOffset
|
||||
xOffset = math.ceil( ( xOffset + xOldSize ) / 50 ) * 50
|
||||
|
||||
if ( xOffset == xOldOffset ) then
|
||||
xOffset = xOffset + 50
|
||||
|
||||
if ( maxwidth and xOffset > maxwidth ) then
|
||||
-- Needs a new line
|
||||
if ( thisY == 0 ) then
|
||||
thisY = lineHeight
|
||||
thisMaxY = lineHeight
|
||||
else
|
||||
lineHeight = thisY
|
||||
end
|
||||
xOffset = 0
|
||||
yOffset = yOffset + thisMaxY
|
||||
thisY = 0
|
||||
thisMaxY = 0
|
||||
end
|
||||
end
|
||||
else
|
||||
local x, y = surface.GetTextSize( ch )
|
||||
|
||||
if ( x == nil ) then return end
|
||||
|
||||
if ( maxwidth and maxwidth > x ) then
|
||||
if ( xOffset + xSize + x >= maxwidth ) then
|
||||
|
||||
-- need to: find the previous space in the curString
|
||||
-- if we can't find one, take off the last character
|
||||
-- and insert as a new block, incrementing the y etc
|
||||
|
||||
local lastSpacePos = string.len( curString )
|
||||
for k = 1,string.len( curString ) do
|
||||
local chspace = string.sub( curString, k, k )
|
||||
if ( chspace == " " ) then
|
||||
lastSpacePos = k
|
||||
end
|
||||
end
|
||||
|
||||
local previous_block = new_block_list[ #new_block_list ]
|
||||
local wrap = lastSpacePos == string.len( curString ) && lastSpacePos > 0
|
||||
if ( previous_block and previous_block.text:match(" $") and wrap and surface.GetTextSize( blk.text ) < maxwidth ) then
|
||||
-- If the block was preceded by a space, wrap the block onto the next line first, as we can probably fit it there
|
||||
local trimmed, trimCharNum = previous_block.text:gsub(" +$", "")
|
||||
if ( trimCharNum > 0 ) then
|
||||
previous_block.text = trimmed
|
||||
previous_block.thisX = surface.GetTextSize( previous_block.text )
|
||||
end
|
||||
else
|
||||
if ( wrap ) then
|
||||
-- If the block takes up multiple lines (and has no spaces), split it up
|
||||
local sequenceStartPos = utf8.offset( curString, 0, lastSpacePos )
|
||||
ch = string.match( curString, utf8.charpattern, sequenceStartPos ) .. ch
|
||||
j = utf8.offset( curString, 1, sequenceStartPos )
|
||||
curString = string.sub( curString, 1, sequenceStartPos - 1 )
|
||||
else
|
||||
-- Otherwise, strip the trailing space and start a new line
|
||||
ch = string.sub( curString, lastSpacePos + 1 ) .. ch
|
||||
j = lastSpacePos + 1
|
||||
curString = string.sub( curString, 1, math.max( lastSpacePos - 1, 0 ) )
|
||||
end
|
||||
|
||||
local m = 1
|
||||
while string.sub( ch, m, m ) == " " do
|
||||
m = m + 1
|
||||
end
|
||||
ch = string.sub( ch, m )
|
||||
|
||||
local x1,y1 = surface.GetTextSize( curString )
|
||||
|
||||
if ( y1 > thisMaxY ) then
|
||||
thisMaxY = y1
|
||||
ymaxes[ yOffset ] = thisMaxY
|
||||
lineHeight = y1
|
||||
end
|
||||
|
||||
local new_block = {
|
||||
text = curString,
|
||||
font = blk.font,
|
||||
colour = blk.colour,
|
||||
thisY = thisY,
|
||||
thisX = x1,
|
||||
offset = {
|
||||
x = xOffset,
|
||||
y = yOffset
|
||||
}
|
||||
}
|
||||
table.insert( new_block_list, new_block )
|
||||
|
||||
if ( xOffset + x1 > xMax ) then
|
||||
xMax = xOffset + x1
|
||||
end
|
||||
|
||||
curString = ""
|
||||
end
|
||||
|
||||
xOffset = 0
|
||||
xSize = 0
|
||||
x, y = surface.GetTextSize( ch )
|
||||
yOffset = yOffset + thisMaxY
|
||||
thisY = 0
|
||||
thisMaxY = 0
|
||||
end
|
||||
end
|
||||
|
||||
curString = curString .. ch
|
||||
|
||||
thisY = y
|
||||
xSize = xSize + x
|
||||
|
||||
if ( y > thisMaxY ) then
|
||||
thisMaxY = y
|
||||
ymaxes[ yOffset ] = thisMaxY
|
||||
lineHeight = y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ( string.len( curString ) > 0 ) then
|
||||
|
||||
local x1 = surface.GetTextSize( curString )
|
||||
|
||||
local new_block = {
|
||||
text = curString,
|
||||
font = blk.font,
|
||||
colour = blk.colour,
|
||||
thisY = thisY,
|
||||
thisX = x1,
|
||||
offset = {
|
||||
x = xOffset,
|
||||
y = yOffset
|
||||
}
|
||||
}
|
||||
table.insert( new_block_list, new_block )
|
||||
|
||||
lineHeight = thisY
|
||||
|
||||
if ( xOffset + x1 > xMax ) then
|
||||
xMax = xOffset + x1
|
||||
end
|
||||
xOffset = xOffset + x1
|
||||
end
|
||||
xSize = 0
|
||||
end
|
||||
|
||||
local totalHeight = 0
|
||||
for i, blk in ipairs( new_block_list ) do
|
||||
blk.height = ymaxes[ blk.offset.y ]
|
||||
|
||||
if ( blk.offset.y + blk.height > totalHeight ) then
|
||||
totalHeight = blk.offset.y + blk.height
|
||||
end
|
||||
|
||||
lineWidths[ blk.offset.y ] = math.max( lineWidths[ blk.offset.y ] or 0, blk.offset.x + blk.thisX )
|
||||
end
|
||||
|
||||
return setmetatable( {
|
||||
totalHeight = totalHeight,
|
||||
totalWidth = xMax,
|
||||
maxWidth = maxwidth,
|
||||
lineWidths = lineWidths,
|
||||
blocks = new_block_list
|
||||
}, MarkupObject )
|
||||
end
|
||||
88
lua/includes/modules/matproxy.lua
Normal file
88
lua/includes/modules/matproxy.lua
Normal file
@@ -0,0 +1,88 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
module( "matproxy", package.seeall )
|
||||
|
||||
ProxyList = {}
|
||||
ActiveList = {}
|
||||
|
||||
--
|
||||
-- Called by engine, returns true if we're overriding a proxy
|
||||
--
|
||||
function ShouldOverrideProxy( name )
|
||||
|
||||
return ProxyList[ name ] != nil
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called to add a new proxy (see lua/matproxy/ for examples)
|
||||
--
|
||||
function Add( tbl )
|
||||
|
||||
if ( !tbl.name ) then return end
|
||||
if ( !tbl.bind ) then return end
|
||||
|
||||
local bReloading = ProxyList[ tbl.name ] != nil
|
||||
|
||||
ProxyList[ tbl.name ] = tbl
|
||||
|
||||
--
|
||||
-- If we're reloading then reload all the active entries that use this proxy
|
||||
--
|
||||
if ( bReloading ) then
|
||||
|
||||
for k, v in pairs( ActiveList ) do
|
||||
|
||||
if ( tbl.name != v.name ) then continue end
|
||||
|
||||
Msg( "Reloading: ", v.Material, "\n" )
|
||||
Init( tbl.name, k, v.Material, v.Values )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the engine from OnBind
|
||||
--
|
||||
function Call( name, mat, ent )
|
||||
|
||||
local proxy = ActiveList[ name ]
|
||||
if ( !proxy ) then return end
|
||||
if ( !proxy.bind ) then return end
|
||||
|
||||
proxy:bind( mat, ent )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the engine from OnBind
|
||||
--
|
||||
function Init( name, uname, mat, values )
|
||||
|
||||
local proxy = ProxyList[ name ]
|
||||
if ( !proxy ) then return end
|
||||
|
||||
ActiveList[ uname ] = table.Copy( proxy )
|
||||
local active_proxy = ActiveList[ uname ]
|
||||
if ( !active_proxy.init ) then return end
|
||||
|
||||
active_proxy:init( mat, values )
|
||||
|
||||
-- Store these incase we reload
|
||||
active_proxy.Values = values
|
||||
active_proxy.Material = mat
|
||||
|
||||
end
|
||||
49
lua/includes/modules/menubar.lua
Normal file
49
lua/includes/modules/menubar.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
menubar = {}
|
||||
|
||||
function menubar.Init()
|
||||
|
||||
menubar.Control = vgui.Create( "DMenuBar" )
|
||||
menubar.Control:Dock( TOP )
|
||||
menubar.Control:SetVisible( false )
|
||||
|
||||
hook.Run( "PopulateMenuBar", menubar.Control )
|
||||
|
||||
end
|
||||
|
||||
function menubar.ParentTo( pnl )
|
||||
|
||||
// I don't like this
|
||||
if ( !IsValid( menubar.Control ) ) then
|
||||
menubar.Init()
|
||||
end
|
||||
|
||||
menubar.Control:SetParent( pnl )
|
||||
menubar.Control:MoveToBack()
|
||||
menubar.Control:SetHeight( 30 )
|
||||
menubar.Control:SetVisible( true )
|
||||
|
||||
end
|
||||
|
||||
function menubar.IsParent( pnl )
|
||||
|
||||
return menubar.Control:GetParent() == pnl
|
||||
|
||||
end
|
||||
|
||||
|
||||
hook.Add( "OnGamemodeLoaded", "CreateMenuBar", function()
|
||||
|
||||
menubar.Init()
|
||||
|
||||
end )
|
||||
13
lua/includes/modules/momo.lua
Normal file
13
lua/includes/modules/momo.lua
Normal file
@@ -0,0 +1,13 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
print("MOMO MODULE DEPRECATED!")
|
||||
163
lua/includes/modules/niknaks.lua
Normal file
163
lua/includes/modules/niknaks.lua
Normal file
@@ -0,0 +1,163 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- Copyright © 2022-2072, Nak, https://steamcommunity.com/id/Nak2/
|
||||
-- All Rights Reserved. Not allowed to be reuploaded.
|
||||
|
||||
AddCSLuaFile()
|
||||
-- Make sure to use the newest version of NikNaks.
|
||||
local version = 0.36
|
||||
if NikNaks and NikNaks.Version > version then return end
|
||||
|
||||
local file_Find, MsgC, unpack, rawget = file.Find, MsgC, unpack, rawget
|
||||
|
||||
NikNaks = {}
|
||||
NikNaks.net = {}
|
||||
NikNaks.Version = version
|
||||
NikNaks.Authors = "Nak"
|
||||
MsgN("Loading NikNaks: " .. NikNaks.Version)
|
||||
NikNaks.__metatables = {}
|
||||
|
||||
do
|
||||
---A simply Msg function for NikNaks
|
||||
function NikNaks.Msg( ... )
|
||||
local a = {...}
|
||||
if #a < 1 then return end
|
||||
MsgC(NikNaks.REALM_COLOR,"[NN] ", unpack(a), "\n")
|
||||
end
|
||||
end
|
||||
|
||||
---Auto includes, runs and AddCSLuaFile files using their prefix.
|
||||
function NikNaks.AutoInclude( str )
|
||||
local path = str
|
||||
if string.find(str,"/") then
|
||||
path = string.GetFileFromFilename(str)
|
||||
end
|
||||
local _type
|
||||
if path ~= "shared.lua" then
|
||||
_type = string.sub(path,0,3)
|
||||
else
|
||||
_type = "sh_"
|
||||
end
|
||||
if SERVER then
|
||||
if _type == "cl_" or _type == "sh_" then
|
||||
AddCSLuaFile(str)
|
||||
end
|
||||
if _type ~= "cl_" then
|
||||
return include(str)
|
||||
end
|
||||
elseif _type ~= "sv_" then
|
||||
return pcall(include, str)
|
||||
end
|
||||
end
|
||||
|
||||
---Autp includes, runs and AddCSLuaFile a folder by the files prefix.
|
||||
function NikNaks.AutoIncludeFolder( str )
|
||||
for _,fil in ipairs(file_Find(str .. "/*.lua","LUA")) do
|
||||
NikNaks.AutoInclude(str .. "/" .. fil)
|
||||
end
|
||||
end
|
||||
|
||||
-- A simple scope-script
|
||||
do
|
||||
local g = _G
|
||||
local envs = {}
|
||||
local env = {}
|
||||
local getfenv, setfenv, source = getfenv, setfenv, jit.util.funcinfo( NikNaks.AutoInclude )["source"]
|
||||
local NikNaks = NikNaks
|
||||
local function createEnv( tab, source )
|
||||
local t = {}
|
||||
setmetatable(t, { __index = function(k, v)
|
||||
return rawget(NikNaks, v) or tab[v]
|
||||
end,
|
||||
__newindex = function( t, k, v)
|
||||
rawset( _G, k, v )
|
||||
end})
|
||||
envs[ tab ] = t
|
||||
return t
|
||||
end
|
||||
|
||||
-- Patches any tables with names that share _G
|
||||
--NikNaks._source = source:lower():match("addons/(.-)/")
|
||||
NikNaks._source = "niknak"
|
||||
local function using()
|
||||
local _env = getfenv( 2 )
|
||||
if _env ~= _GEnv then -- Make sure it isn't our env
|
||||
-- Create new env and apply it
|
||||
setfenv(2, envs[_env] or createEnv( _env, NikNaks._source ))
|
||||
else
|
||||
-- Ignore for now.
|
||||
-- error("Can't apply enviroment to self")
|
||||
end
|
||||
end
|
||||
|
||||
setmetatable(NikNaks,{
|
||||
__call = function( _, ...) return using( ... ) end
|
||||
})
|
||||
end
|
||||
|
||||
--[[
|
||||
For safty reasons, we're won't use AutoInclude or AutoIncludeFolder. These should be hardcoded.
|
||||
]]
|
||||
|
||||
--- @class BSPObject
|
||||
local meta = {}
|
||||
meta.__index = meta
|
||||
meta.__tostring = function( self ) return string.format( "BSP Map [ %s ]", self._mapfile ) end
|
||||
meta.MetaName = "BSP"
|
||||
NikNaks.__metatables["BSP"] = meta
|
||||
NikNaks._Source = "niknak"
|
||||
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_enums.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_util_extended.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_file_extended.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_timedelta.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_datetime.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_color_extended.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_model_extended.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bitbuffer.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_module.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_entities.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_faces.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_leafs.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_brushes.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_pvspas.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_bsp_staticprops.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_pathfind_module.lua")
|
||||
NikNaks.AutoInclude("niknaks/modules/sh_ain_module.lua")
|
||||
|
||||
NikNaks.AutoInclude("niknaks/framework/sh_localbsp.lua")
|
||||
NikNaks.AutoInclude("niknaks/framework/sh_epath.lua")
|
||||
|
||||
-- Patch table to ref _G
|
||||
do
|
||||
local g = _G
|
||||
for key, val in pairs( NikNaks ) do
|
||||
if not istable( val ) then continue end
|
||||
if not _G[key] then continue end
|
||||
--if not NikNaks._source:find("niknak") then continue end
|
||||
setmetatable(val, { __index = function(k, v)
|
||||
return rawget(k, v) or g[key][v]
|
||||
end})
|
||||
end
|
||||
end
|
||||
|
||||
-- Post Init. This is a safety option, as using traces and other functions before InitPostEntity can cause crash.
|
||||
if _NIKNAKS_POSTENTITY then
|
||||
NikNaks.PostInit = true
|
||||
timer.Simple(1, NikNaks._LoadPathOptions )
|
||||
else
|
||||
hook.Add("NikNaks._LoadPathOptions", "wait", function()
|
||||
NikNaks.PostInit = true
|
||||
NikNaks._LoadPathOptions()
|
||||
hook.Remove("NikNaks._LoadPathOptions", "wait")
|
||||
end)
|
||||
end
|
||||
-- return NikNaks -- Doesn't work for require :C
|
||||
304
lua/includes/modules/notification.lua
Normal file
304
lua/includes/modules/notification.lua
Normal file
@@ -0,0 +1,304 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
surface.CreateFont( "GModNotify", {
|
||||
font = "Arial",
|
||||
size = 21,
|
||||
weight = 0
|
||||
} )
|
||||
|
||||
NOTIFY_GENERIC = 0
|
||||
NOTIFY_ERROR = 1
|
||||
NOTIFY_UNDO = 2
|
||||
NOTIFY_HINT = 3
|
||||
NOTIFY_CLEANUP = 4
|
||||
|
||||
module( "notification", package.seeall )
|
||||
|
||||
local NoticeMaterial = {}
|
||||
|
||||
NoticeMaterial[ NOTIFY_GENERIC ] = Material( "vgui/notices/generic" )
|
||||
NoticeMaterial[ NOTIFY_ERROR ] = Material( "vgui/notices/error" )
|
||||
NoticeMaterial[ NOTIFY_UNDO ] = Material( "vgui/notices/undo" )
|
||||
NoticeMaterial[ NOTIFY_HINT ] = Material( "vgui/notices/hint" )
|
||||
NoticeMaterial[ NOTIFY_CLEANUP ] = Material( "vgui/notices/cleanup" )
|
||||
|
||||
local Notices = {}
|
||||
|
||||
function AddProgress( uid, text, frac )
|
||||
|
||||
if ( IsValid( Notices[ uid ] ) ) then
|
||||
|
||||
Notices[ uid ].StartTime = SysTime()
|
||||
Notices[ uid ].Length = -1
|
||||
Notices[ uid ]:SetText( text )
|
||||
Notices[ uid ]:SetProgress( frac )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
local parent = nil
|
||||
if ( GetOverlayPanel ) then parent = GetOverlayPanel() end
|
||||
|
||||
local Panel = vgui.Create( "NoticePanel", parent )
|
||||
Panel.StartTime = SysTime()
|
||||
Panel.Length = -1
|
||||
Panel.VelX = -5
|
||||
Panel.VelY = 0
|
||||
Panel.fx = ScrW() + 200
|
||||
Panel.fy = ScrH()
|
||||
Panel:SetAlpha( 255 )
|
||||
Panel:SetText( text )
|
||||
Panel:SetPos( Panel.fx, Panel.fy )
|
||||
Panel:SetProgress( frac )
|
||||
|
||||
Notices[ uid ] = Panel
|
||||
|
||||
end
|
||||
|
||||
function Kill( uid )
|
||||
|
||||
if ( !IsValid( Notices[ uid ] ) ) then return end
|
||||
|
||||
Notices[ uid ].StartTime = SysTime()
|
||||
Notices[ uid ].Length = 0.8
|
||||
|
||||
end
|
||||
|
||||
function AddLegacy( text, type, length )
|
||||
|
||||
local parent = nil
|
||||
if ( GetOverlayPanel ) then parent = GetOverlayPanel() end
|
||||
|
||||
local Panel = vgui.Create( "NoticePanel", parent )
|
||||
Panel.StartTime = SysTime()
|
||||
Panel.Length = math.max( length, 0 )
|
||||
Panel.VelX = -5
|
||||
Panel.VelY = 0
|
||||
Panel.fx = ScrW() + 200
|
||||
Panel.fy = ScrH()
|
||||
Panel:SetAlpha( 255 )
|
||||
Panel:SetText( text )
|
||||
Panel:SetLegacyType( type )
|
||||
Panel:SetPos( Panel.fx, Panel.fy )
|
||||
|
||||
table.insert( Notices, Panel )
|
||||
|
||||
end
|
||||
|
||||
-- This is ugly because it's ripped straight from the old notice system
|
||||
local function UpdateNotice( pnl, total_h )
|
||||
|
||||
local x = pnl.fx
|
||||
local y = pnl.fy
|
||||
|
||||
local w = pnl:GetWide() + 16
|
||||
local h = pnl:GetTall() + 4
|
||||
|
||||
local ideal_y = ScrH() - 150 - h - total_h
|
||||
local ideal_x = ScrW() - w - 20
|
||||
|
||||
local timeleft = pnl.StartTime - ( SysTime() - pnl.Length )
|
||||
if ( pnl.Length < 0 ) then timeleft = 1 end
|
||||
|
||||
-- Cartoon style about to go thing
|
||||
if ( timeleft < 0.7 ) then
|
||||
ideal_x = ideal_x - 50
|
||||
end
|
||||
|
||||
-- Gone!
|
||||
if ( timeleft < 0.2 ) then
|
||||
ideal_x = ideal_x + w * 2
|
||||
end
|
||||
|
||||
local spd = RealFrameTime() * 15
|
||||
|
||||
y = y + pnl.VelY * spd
|
||||
x = x + pnl.VelX * spd
|
||||
|
||||
local dist = ideal_y - y
|
||||
pnl.VelY = pnl.VelY + dist * spd * 1
|
||||
if ( math.abs( dist ) < 2 && math.abs( pnl.VelY ) < 0.1 ) then pnl.VelY = 0 end
|
||||
dist = ideal_x - x
|
||||
pnl.VelX = pnl.VelX + dist * spd * 1
|
||||
if ( math.abs( dist ) < 2 && math.abs( pnl.VelX ) < 0.1 ) then pnl.VelX = 0 end
|
||||
|
||||
-- Friction.. kind of FPS independant.
|
||||
pnl.VelX = pnl.VelX * ( 0.95 - RealFrameTime() * 8 )
|
||||
pnl.VelY = pnl.VelY * ( 0.95 - RealFrameTime() * 8 )
|
||||
|
||||
pnl.fx = x
|
||||
pnl.fy = y
|
||||
|
||||
-- If the panel is too high up (out of screen), do not update its position. This lags a lot when there are lot of panels outside of the screen
|
||||
if ( ideal_y > -ScrH() ) then
|
||||
pnl:SetPos( pnl.fx, pnl.fy )
|
||||
end
|
||||
|
||||
return total_h + h
|
||||
|
||||
end
|
||||
|
||||
local function Update()
|
||||
|
||||
if ( !Notices ) then return end
|
||||
|
||||
local h = 0
|
||||
for key, pnl in pairs( Notices ) do
|
||||
|
||||
h = UpdateNotice( pnl, h )
|
||||
|
||||
end
|
||||
|
||||
for k, Panel in pairs( Notices ) do
|
||||
|
||||
if ( !IsValid( Panel ) || Panel:KillSelf() ) then Notices[ k ] = nil end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Think", "NotificationThink", Update )
|
||||
|
||||
local PANEL = {}
|
||||
|
||||
function PANEL:Init()
|
||||
|
||||
self:DockPadding( 3, 3, 3, 3 )
|
||||
|
||||
self.Label = vgui.Create( "DLabel", self )
|
||||
self.Label:Dock( FILL )
|
||||
self.Label:SetFont( "GModNotify" )
|
||||
self.Label:SetTextColor( color_white )
|
||||
self.Label:SetExpensiveShadow( 1, Color( 0, 0, 0, 200 ) )
|
||||
self.Label:SetContentAlignment( 5 )
|
||||
|
||||
self:SetBackgroundColor( Color( 20, 20, 20, 255 * 0.6 ) )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetText( txt )
|
||||
|
||||
self.Label:SetText( txt )
|
||||
self:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SizeToContents()
|
||||
|
||||
self.Label:SizeToContents()
|
||||
|
||||
local width, tall = self.Label:GetSize()
|
||||
|
||||
tall = math.max( tall, 32 ) + 6
|
||||
width = width + 20
|
||||
|
||||
if ( IsValid( self.Image ) ) then
|
||||
width = width + 32 + 8
|
||||
|
||||
local x = ( tall - 36 ) / 2
|
||||
self.Image:DockMargin( 0, x, 0, x )
|
||||
end
|
||||
|
||||
if ( self.Progress ) then
|
||||
tall = tall + 10
|
||||
self.Label:DockMargin( 0, 0, 0, 10 )
|
||||
end
|
||||
|
||||
self:SetSize( width, tall )
|
||||
|
||||
self:InvalidateLayout()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetLegacyType( t )
|
||||
|
||||
self.Image = vgui.Create( "DImageButton", self )
|
||||
self.Image:SetMaterial( NoticeMaterial[ t ] )
|
||||
self.Image:SetSize( 32, 32 )
|
||||
self.Image:Dock( LEFT )
|
||||
self.Image:DockMargin( 0, 0, 8, 0 )
|
||||
self.Image.DoClick = function()
|
||||
self.StartTime = 0
|
||||
end
|
||||
|
||||
self:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:Paint( w, h )
|
||||
|
||||
local shouldDraw = !( LocalPlayer && IsValid( LocalPlayer() ) && IsValid( LocalPlayer():GetActiveWeapon() ) && LocalPlayer():GetActiveWeapon():GetClass() == "gmod_camera" )
|
||||
|
||||
if ( IsValid( self.Label ) ) then self.Label:SetVisible( shouldDraw ) end
|
||||
if ( IsValid( self.Image ) ) then self.Image:SetVisible( shouldDraw ) end
|
||||
|
||||
if ( !shouldDraw ) then return end
|
||||
|
||||
self.BaseClass.Paint( self, w, h )
|
||||
|
||||
if ( !self.Progress ) then return end
|
||||
|
||||
local boxX, boxY = 10, self:GetTall() - 13
|
||||
local boxW, boxH = self:GetWide() - 20, 5
|
||||
local boxInnerW = boxW - 2
|
||||
|
||||
surface.SetDrawColor( 0, 100, 0, 150 )
|
||||
surface.DrawRect( boxX, boxY, boxW, boxH )
|
||||
|
||||
surface.SetDrawColor( 0, 50, 0, 255 )
|
||||
surface.DrawRect( boxX + 1, boxY + 1, boxW - 2, boxH - 2 )
|
||||
|
||||
local w = math.ceil( boxInnerW * 0.25 )
|
||||
local x = math.fmod( math.floor( SysTime() * 200 ), boxInnerW + w ) - w
|
||||
|
||||
if ( self.ProgressFrac ) then
|
||||
x = 0
|
||||
w = math.ceil( boxInnerW * self.ProgressFrac )
|
||||
end
|
||||
|
||||
if ( x + w > boxInnerW ) then w = math.ceil( boxInnerW - x ) end
|
||||
if ( x < 0 ) then
|
||||
w = w + x
|
||||
x = 0
|
||||
end
|
||||
|
||||
surface.SetDrawColor( 0, 255, 0, 255 )
|
||||
surface.DrawRect( boxX + 1 + x, boxY + 1, w, boxH - 2 )
|
||||
|
||||
end
|
||||
|
||||
function PANEL:SetProgress( frac )
|
||||
|
||||
self.Progress = true
|
||||
self.ProgressFrac = frac
|
||||
|
||||
self:SizeToContents()
|
||||
|
||||
end
|
||||
|
||||
function PANEL:KillSelf()
|
||||
|
||||
-- Infinite length
|
||||
if ( self.Length < 0 ) then return false end
|
||||
|
||||
if ( self.StartTime + self.Length < SysTime() ) then
|
||||
|
||||
self:Remove()
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
vgui.Register( "NoticePanel", PANEL, "DPanel" )
|
||||
255
lua/includes/modules/numpad.lua
Normal file
255
lua/includes/modules/numpad.lua
Normal file
@@ -0,0 +1,255 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
This module was primarily developed to enable toolmodes
|
||||
to share the numpad.
|
||||
|
||||
Scripted Entities can add functions to be excecuted when
|
||||
a certain key on the numpad is pressed or released.
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
if ( !SERVER ) then return end
|
||||
|
||||
local tonumber = tonumber
|
||||
local pairs = pairs
|
||||
local unpack = unpack
|
||||
local table = table
|
||||
local saverestore = saverestore
|
||||
local math = math
|
||||
local IsValid = IsValid
|
||||
local type = type
|
||||
local ErrorNoHaltWithStack = ErrorNoHaltWithStack
|
||||
|
||||
module( "numpad" )
|
||||
|
||||
local functions = {}
|
||||
local keys_in = {}
|
||||
local keys_out = {}
|
||||
local lastindex = 1
|
||||
local button_fired = false
|
||||
|
||||
function FromButton()
|
||||
|
||||
return button_fired == true
|
||||
|
||||
end
|
||||
|
||||
local function Save( save )
|
||||
|
||||
saverestore.WriteTable( keys_in, save )
|
||||
saverestore.WriteTable( keys_out, save )
|
||||
saverestore.WriteVar( lastindex, save )
|
||||
|
||||
end
|
||||
|
||||
local function Restore( restore )
|
||||
|
||||
keys_in = saverestore.ReadTable( restore )
|
||||
keys_out = saverestore.ReadTable( restore )
|
||||
lastindex = saverestore.ReadVar( restore )
|
||||
|
||||
end
|
||||
|
||||
saverestore.AddSaveHook( "NumpadModule", Save )
|
||||
saverestore.AddRestoreHook( "NumpadModule", Restore )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns a unique index based on a player.
|
||||
-----------------------------------------------------------]]
|
||||
local function GetPlayerIndex( ply )
|
||||
|
||||
if ( !IsValid( ply ) ) then return 0 end
|
||||
|
||||
return ply:SteamID64()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Fires the impulse to the child functions
|
||||
-----------------------------------------------------------]]
|
||||
local function FireImpulse( tab, pl, idx )
|
||||
|
||||
if ( idx == nil ) then
|
||||
idx = GetPlayerIndex( pl )
|
||||
end
|
||||
|
||||
if ( !tab ) then return end
|
||||
if ( !tab[ idx ] ) then return end
|
||||
|
||||
for k, v in pairs( tab[ idx ] ) do
|
||||
|
||||
local func = functions[ v.name ]
|
||||
|
||||
local retval = func( pl, unpack( v.arg ) )
|
||||
|
||||
-- Remove hook
|
||||
if ( retval == false ) then
|
||||
tab[ idx ][ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Console Command
|
||||
-----------------------------------------------------------]]
|
||||
function Activate( pl, num, bIsButton )
|
||||
|
||||
local key = math.Clamp( tonumber( num ), 0, 256 )
|
||||
|
||||
-- Hack. Kinda. Don't call it again until the key has been lifted.
|
||||
-- When holding down 9 or 3 on the numpad it will repeat. Ignore that.
|
||||
if ( IsValid( pl ) ) then
|
||||
pl.keystate = pl.keystate or {}
|
||||
if ( pl.keystate[ key ] ) then return end
|
||||
pl.keystate[ key ] = true
|
||||
end
|
||||
|
||||
button_fired = bIsButton
|
||||
|
||||
FireImpulse( keys_in[ key ], pl, nil )
|
||||
|
||||
-- And fire `all`
|
||||
FireImpulse( keys_in[ key ], pl, 0 )
|
||||
|
||||
button_fired = false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Console Command
|
||||
-----------------------------------------------------------]]
|
||||
function Deactivate( pl, num, bIsButton )
|
||||
|
||||
local key = math.Clamp( tonumber( num ) , 0, 256 )
|
||||
|
||||
if ( IsValid( pl ) ) then
|
||||
pl.keystate = pl.keystate or {}
|
||||
pl.keystate[ key ] = nil
|
||||
end
|
||||
|
||||
button_fired = bIsButton
|
||||
|
||||
FireImpulse( keys_out[ key ], pl, nil )
|
||||
|
||||
-- And fire `all`
|
||||
FireImpulse( keys_out[ key ], pl, 0 )
|
||||
|
||||
button_fired = false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Toggle
|
||||
-----------------------------------------------------------]]
|
||||
function Toggle( pl, num )
|
||||
|
||||
local key = math.Clamp( tonumber( num ), 0, 256 )
|
||||
|
||||
pl.keystate = pl.keystate or {}
|
||||
if ( pl.keystate[ key ] ) then return Deactivate( pl, num ) end
|
||||
|
||||
return Activate( pl, num )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Adds an impulse to to the specified table
|
||||
-----------------------------------------------------------]]
|
||||
local function AddImpulse( table, ply, impulse )
|
||||
|
||||
lastindex = lastindex + 1
|
||||
|
||||
local idx = GetPlayerIndex( ply )
|
||||
table[ idx ] = table[ idx ] or {}
|
||||
table[ idx ][ lastindex ] = impulse
|
||||
|
||||
return lastindex
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Adds a function to call when ply presses key
|
||||
-----------------------------------------------------------]]
|
||||
function OnDown( ply, key, name, ... )
|
||||
|
||||
if ( !key || key ~= key ) then ErrorNoHaltWithStack( "bad argument #2 to 'numpad.OnDown' (number expected, got ", type( key ), ")" ) return end
|
||||
keys_in[ key ] = keys_in[ key ] or {}
|
||||
|
||||
local impulse = {}
|
||||
impulse.name = name
|
||||
impulse.arg = { ... }
|
||||
|
||||
table.insert( impulse.arg, GetPlayerIndex( ply ) )
|
||||
|
||||
return AddImpulse( keys_in[ key ], ply, impulse )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Adds a function to call when ply releases key
|
||||
-----------------------------------------------------------]]
|
||||
function OnUp( ply, key, name, ... )
|
||||
|
||||
if ( !key || key ~= key ) then ErrorNoHaltWithStack( "bad argument #2 to 'numpad.OnUp' (number expected, got ", type( key ), ")" ) return end
|
||||
keys_out[ key ] = keys_out[ key ] or {}
|
||||
|
||||
local impulse = {}
|
||||
impulse.name = name
|
||||
impulse.arg = { ... }
|
||||
|
||||
table.insert( impulse.arg, GetPlayerIndex( ply ) )
|
||||
|
||||
return AddImpulse( keys_out[ key ], ply, impulse )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Removes key from tab (by unique index)
|
||||
-----------------------------------------------------------]]
|
||||
local function RemoveFromKeyTable( tab, idx )
|
||||
|
||||
for k, v_key in pairs( tab ) do
|
||||
|
||||
for k_, v_player in pairs( v_key ) do
|
||||
|
||||
if ( v_player[ idx ] != nil ) then
|
||||
v_player[ idx ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Removes key (by unique index)
|
||||
-----------------------------------------------------------]]
|
||||
function Remove( idx )
|
||||
|
||||
if ( !idx ) then return end
|
||||
|
||||
RemoveFromKeyTable( keys_out, idx )
|
||||
RemoveFromKeyTable( keys_in, idx )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Register a function
|
||||
-----------------------------------------------------------]]
|
||||
function Register( name, func )
|
||||
|
||||
functions[ name ] = func
|
||||
|
||||
end
|
||||
1211
lua/includes/modules/pk_pills.lua
Normal file
1211
lua/includes/modules/pk_pills.lua
Normal file
File diff suppressed because it is too large
Load Diff
467
lua/includes/modules/player_manager.lua
Normal file
467
lua/includes/modules/player_manager.lua
Normal file
@@ -0,0 +1,467 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local ErrorNoHalt = ErrorNoHalt
|
||||
local baseclass = baseclass
|
||||
local setmetatable = setmetatable
|
||||
local SERVER = SERVER
|
||||
local string = string
|
||||
local table = table
|
||||
local util = util
|
||||
|
||||
module( "player_manager" )
|
||||
|
||||
-- Stores a table of valid player models
|
||||
local ModelList = {}
|
||||
local ModelListRev = {}
|
||||
local HandNames = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Utility to add models to the acceptable model list
|
||||
-----------------------------------------------------------]]
|
||||
function AddValidModel( name, model )
|
||||
|
||||
ModelList[ name ] = model
|
||||
ModelListRev[ string.lower( model ) ] = name
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Valid hands
|
||||
--
|
||||
function AddValidHands( name, model, skin, body, matchBodySkin )
|
||||
|
||||
HandNames[ name ] = { model = model, skin = skin or 0, body = body or "0000000", matchBodySkin = matchBodySkin or false }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Return list of all valid player models
|
||||
-----------------------------------------------------------]]
|
||||
function AllValidModels( )
|
||||
return ModelList
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Translate the simple name of a model
|
||||
into the full model name
|
||||
-----------------------------------------------------------]]
|
||||
function TranslatePlayerModel( name )
|
||||
|
||||
if ( ModelList[ name ] != nil ) then
|
||||
return ModelList[ name ]
|
||||
end
|
||||
|
||||
return "models/player/kleiner.mdl"
|
||||
end
|
||||
|
||||
-- Translate from the full model name to simple model name
|
||||
function TranslateToPlayerModelName( model )
|
||||
|
||||
model = string.lower( model )
|
||||
|
||||
if ( ModelListRev[ model ] != nil ) then
|
||||
return ModelListRev[ model ]
|
||||
end
|
||||
|
||||
return "kleiner"
|
||||
end
|
||||
|
||||
--
|
||||
-- Translate hands based on model
|
||||
--
|
||||
function TranslatePlayerHands( name )
|
||||
|
||||
if ( HandNames[ name ] != nil ) then
|
||||
return HandNames[ name ]
|
||||
end
|
||||
|
||||
return { model = "models/weapons/c_arms_citizen.mdl", skin = 0, body = "100000000" }
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Compile a list of valid player models
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
AddValidModel( "alyx", "models/player/alyx.mdl" )
|
||||
AddValidHands( "alyx", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "barney", "models/player/barney.mdl" )
|
||||
AddValidHands( "barney", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "breen", "models/player/breen.mdl" )
|
||||
AddValidHands( "breen", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "charple", "models/player/charple.mdl" )
|
||||
AddValidHands( "charple", "models/weapons/c_arms_citizen.mdl", 2, "0000000" )
|
||||
|
||||
AddValidModel( "chell", "models/player/p2_chell.mdl" )
|
||||
AddValidHands( "chell", "models/weapons/c_arms_chell.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "corpse", "models/player/corpse1.mdl" )
|
||||
AddValidHands( "corpse", "models/weapons/c_arms_citizen.mdl", 2, "0000000" )
|
||||
|
||||
AddValidModel( "combine", "models/player/combine_soldier.mdl" )
|
||||
AddValidHands( "combine", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "combineprison", "models/player/combine_soldier_prisonguard.mdl" )
|
||||
AddValidHands( "combineprison", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "combineelite", "models/player/combine_super_soldier.mdl" )
|
||||
AddValidHands( "combineelite", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "eli", "models/player/eli.mdl" )
|
||||
AddValidHands( "eli", "models/weapons/c_arms_citizen.mdl", 1, "0000000" )
|
||||
|
||||
AddValidModel( "gman", "models/player/gman_high.mdl" )
|
||||
AddValidHands( "gman", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "kleiner", "models/player/kleiner.mdl" )
|
||||
AddValidHands( "kleiner", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "monk", "models/player/monk.mdl" )
|
||||
AddValidHands( "monk", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "mossman", "models/player/mossman.mdl" )
|
||||
AddValidHands( "mossman", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "mossmanarctic", "models/player/mossman_arctic.mdl" )
|
||||
AddValidHands( "mossmanarctic", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "odessa", "models/player/odessa.mdl" )
|
||||
AddValidHands( "odessa", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "police", "models/player/police.mdl" )
|
||||
AddValidHands( "police", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "policefem", "models/player/police_fem.mdl" )
|
||||
AddValidHands( "policefem", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "magnusson", "models/player/magnusson.mdl" )
|
||||
AddValidHands( "magnusson", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "stripped", "models/player/soldier_stripped.mdl" )
|
||||
AddValidHands( "stripped", "models/weapons/c_arms_hev.mdl", 2, "0000000" )
|
||||
|
||||
AddValidModel( "zombie", "models/player/zombie_classic.mdl" )
|
||||
AddValidHands( "zombie", "models/weapons/c_arms_citizen.mdl", 2, "0000000" )
|
||||
|
||||
AddValidModel( "zombiefast", "models/player/zombie_fast.mdl" )
|
||||
AddValidHands( "zombiefast", "models/weapons/c_arms_citizen.mdl", 2, "0000000" )
|
||||
|
||||
AddValidModel( "female01", "models/player/Group01/female_01.mdl" )
|
||||
AddValidHands( "female01", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "female02", "models/player/Group01/female_02.mdl" )
|
||||
AddValidHands( "female02", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "female03", "models/player/Group01/female_03.mdl" )
|
||||
AddValidHands( "female03", "models/weapons/c_arms_citizen.mdl", 1, "0000000" )
|
||||
AddValidModel( "female04", "models/player/Group01/female_04.mdl" )
|
||||
AddValidHands( "female04", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "female05", "models/player/Group01/female_05.mdl" )
|
||||
AddValidHands( "female05", "models/weapons/c_arms_citizen.mdl", 1, "0000000" )
|
||||
AddValidModel( "female06", "models/player/Group01/female_06.mdl" )
|
||||
AddValidHands( "female06", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "female07", "models/player/Group03/female_01.mdl" )
|
||||
AddValidHands( "female07", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "female08", "models/player/Group03/female_02.mdl" )
|
||||
AddValidHands( "female08", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "female09", "models/player/Group03/female_03.mdl" )
|
||||
AddValidHands( "female09", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "female10", "models/player/Group03/female_04.mdl" )
|
||||
AddValidHands( "female10", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "female11", "models/player/Group03/female_05.mdl" )
|
||||
AddValidHands( "female11", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "female12", "models/player/Group03/female_06.mdl" )
|
||||
AddValidHands( "female12", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
|
||||
AddValidModel( "male01", "models/player/Group01/male_01.mdl" )
|
||||
AddValidHands( "male01", "models/weapons/c_arms_citizen.mdl", 1, "0000000" )
|
||||
AddValidModel( "male02", "models/player/Group01/male_02.mdl" )
|
||||
AddValidHands( "male02", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male03", "models/player/Group01/male_03.mdl" )
|
||||
AddValidHands( "male03", "models/weapons/c_arms_citizen.mdl", 1, "0000000" )
|
||||
AddValidModel( "male04", "models/player/Group01/male_04.mdl" )
|
||||
AddValidHands( "male04", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male05", "models/player/Group01/male_05.mdl" )
|
||||
AddValidHands( "male05", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male06", "models/player/Group01/male_06.mdl" )
|
||||
AddValidHands( "male06", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male07", "models/player/Group01/male_07.mdl" )
|
||||
AddValidHands( "male07", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male08", "models/player/Group01/male_08.mdl" )
|
||||
AddValidHands( "male08", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "male09", "models/player/Group01/male_09.mdl" )
|
||||
AddValidHands( "male09", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "male10", "models/player/Group03/male_01.mdl" )
|
||||
AddValidHands( "male10", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "male11", "models/player/Group03/male_02.mdl" )
|
||||
AddValidHands( "male11", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male12", "models/player/Group03/male_03.mdl" )
|
||||
AddValidHands( "male12", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "male13", "models/player/Group03/male_04.mdl" )
|
||||
AddValidHands( "male13", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male14", "models/player/Group03/male_05.mdl" )
|
||||
AddValidHands( "male14", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male15", "models/player/Group03/male_06.mdl" )
|
||||
AddValidHands( "male15", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male16", "models/player/Group03/male_07.mdl" )
|
||||
AddValidHands( "male16", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male17", "models/player/Group03/male_08.mdl" )
|
||||
AddValidHands( "male17", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "male18", "models/player/Group03/male_09.mdl" )
|
||||
AddValidHands( "male18", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
|
||||
AddValidModel( "medic01", "models/player/Group03m/male_01.mdl" )
|
||||
AddValidHands( "medic01", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "medic02", "models/player/Group03m/male_02.mdl" )
|
||||
AddValidHands( "medic02", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic03", "models/player/Group03m/male_03.mdl" )
|
||||
AddValidHands( "medic03", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
AddValidModel( "medic04", "models/player/Group03m/male_04.mdl" )
|
||||
AddValidHands( "medic04", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic05", "models/player/Group03m/male_05.mdl" )
|
||||
AddValidHands( "medic05", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "medic06", "models/player/Group03m/male_06.mdl" )
|
||||
AddValidHands( "medic06", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic07", "models/player/Group03m/male_07.mdl" )
|
||||
AddValidHands( "medic07", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic08", "models/player/Group03m/male_08.mdl" )
|
||||
AddValidHands( "medic08", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic09", "models/player/Group03m/male_09.mdl" )
|
||||
AddValidHands( "medic09", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic10", "models/player/Group03m/female_01.mdl" )
|
||||
AddValidHands( "medic10", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "medic11", "models/player/Group03m/female_02.mdl" )
|
||||
AddValidHands( "medic11", "models/weapons/c_arms_refugee.mdl", 0, "0000000" )
|
||||
AddValidModel( "medic12", "models/player/Group03m/female_03.mdl" )
|
||||
AddValidHands( "medic12", "models/weapons/c_arms_refugee.mdl", 1, "0000000" )
|
||||
AddValidModel( "medic13", "models/player/Group03m/female_04.mdl" )
|
||||
AddValidHands( "medic13", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "medic14", "models/player/Group03m/female_05.mdl" )
|
||||
AddValidHands( "medic14", "models/weapons/c_arms_refugee.mdl", 0, "0100000" )
|
||||
AddValidModel( "medic15", "models/player/Group03m/female_06.mdl" )
|
||||
AddValidHands( "medic15", "models/weapons/c_arms_refugee.mdl", 1, "0100000" )
|
||||
|
||||
AddValidModel( "refugee01", "models/player/Group02/male_02.mdl" )
|
||||
AddValidHands( "refugee01", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "refugee02", "models/player/Group02/male_04.mdl" )
|
||||
AddValidHands( "refugee02", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "refugee03", "models/player/Group02/male_06.mdl" )
|
||||
AddValidHands( "refugee03", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "refugee04", "models/player/Group02/male_08.mdl" )
|
||||
AddValidHands( "refugee04", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
|
||||
--
|
||||
-- Game specific player models! (EP2, CSS, DOD)
|
||||
-- Moving them to here since we're now shipping all required files / fallbacks
|
||||
|
||||
AddValidModel( "magnusson", "models/player/magnusson.mdl" )
|
||||
AddValidHands( "magnusson", "models/weapons/c_arms_citizen.mdl", 0, "0000000" )
|
||||
AddValidModel( "skeleton", "models/player/skeleton.mdl" )
|
||||
AddValidHands( "skeleton", "models/weapons/c_arms_citizen.mdl", 2, "0000000" )
|
||||
AddValidModel( "zombine", "models/player/zombie_soldier.mdl" )
|
||||
AddValidHands( "zombine", "models/weapons/c_arms_combine.mdl", 0, "0000000" )
|
||||
|
||||
AddValidModel( "hostage01", "models/player/hostage/hostage_01.mdl" )
|
||||
AddValidModel( "hostage02", "models/player/hostage/hostage_02.mdl" )
|
||||
AddValidModel( "hostage03", "models/player/hostage/hostage_03.mdl" )
|
||||
AddValidModel( "hostage04", "models/player/hostage/hostage_04.mdl" )
|
||||
|
||||
AddValidModel( "css_arctic", "models/player/arctic.mdl" )
|
||||
AddValidHands( "css_arctic", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_gasmask", "models/player/gasmask.mdl" )
|
||||
AddValidHands( "css_gasmask", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_guerilla", "models/player/guerilla.mdl" )
|
||||
AddValidHands( "css_guerilla", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_leet", "models/player/leet.mdl" )
|
||||
AddValidHands( "css_leet", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_phoenix", "models/player/phoenix.mdl" )
|
||||
AddValidHands( "css_phoenix", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_riot", "models/player/riot.mdl" )
|
||||
AddValidHands( "css_riot", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_swat", "models/player/swat.mdl" )
|
||||
AddValidHands( "css_swat", "models/weapons/c_arms_cstrike.mdl", 0, "10000000" )
|
||||
AddValidModel( "css_urban", "models/player/urban.mdl" )
|
||||
AddValidHands( "css_urban", "models/weapons/c_arms_cstrike.mdl", 7, "10000000" )
|
||||
|
||||
AddValidModel( "dod_german", "models/player/dod_german.mdl" )
|
||||
AddValidHands( "dod_german", "models/weapons/c_arms_dod.mdl", 0, "10000000" )
|
||||
AddValidModel( "dod_american", "models/player/dod_american.mdl" )
|
||||
AddValidHands( "dod_american", "models/weapons/c_arms_dod.mdl", 1, "10000000" )
|
||||
|
||||
|
||||
--
|
||||
-- Player Class Stuff
|
||||
--
|
||||
|
||||
local Type = {}
|
||||
|
||||
function GetPlayerClasses()
|
||||
|
||||
return table.Copy( Type )
|
||||
|
||||
end
|
||||
|
||||
local function LookupPlayerClass( ply )
|
||||
|
||||
local id = ply:GetClassID()
|
||||
if ( id == 0 ) then return end
|
||||
|
||||
--
|
||||
-- Check the cache
|
||||
--
|
||||
local plyClass = ply.m_CurrentPlayerClass
|
||||
if ( plyClass && plyClass.Player == ply ) then
|
||||
if ( plyClass.ClassID == id && plyClass.Func ) then return plyClass end -- current class is still good, behave normally
|
||||
if ( plyClass.ClassChanged ) then plyClass:ClassChanged() end -- the class id changed, remove the old class
|
||||
end
|
||||
|
||||
--
|
||||
-- No class, lets create one
|
||||
--
|
||||
local classname = util.NetworkIDToString( id )
|
||||
if ( !classname ) then return end
|
||||
|
||||
--
|
||||
-- Get that type. Fail if we don't have the type.
|
||||
--
|
||||
local t = Type[ classname ]
|
||||
if ( !t ) then return end
|
||||
|
||||
local newClass = {
|
||||
Player = ply,
|
||||
ClassID = id,
|
||||
Func = function() end
|
||||
}
|
||||
|
||||
setmetatable( newClass, { __index = t } )
|
||||
|
||||
ply.m_CurrentPlayerClass = newClass
|
||||
|
||||
-- TODO: We probably want to reset previous DTVar stuff on the player
|
||||
newClass.Player:InstallDataTable()
|
||||
newClass:SetupDataTables()
|
||||
newClass:Init()
|
||||
return newClass
|
||||
|
||||
end
|
||||
|
||||
function RegisterClass( name, tab, base )
|
||||
|
||||
Type[ name ] = tab
|
||||
|
||||
--
|
||||
-- If we have a base method then hook
|
||||
-- it up in the meta table
|
||||
--
|
||||
if ( base ) then
|
||||
|
||||
if ( !Type[ name ] ) then ErrorNoHalt( "RegisterClass - deriving " .. name .. " from unknown class " .. base .. "!\n" ) end
|
||||
setmetatable( Type[ name ], { __index = Type[ base ] } )
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
util.AddNetworkString( name )
|
||||
end
|
||||
|
||||
--
|
||||
-- drive methods cooperate with the baseclass system
|
||||
-- /lua/includes/modules/baseclass.lua
|
||||
--
|
||||
baseclass.Set( name, Type[ name ] )
|
||||
|
||||
end
|
||||
|
||||
function SetPlayerClass( ply, classname )
|
||||
|
||||
if ( !Type[ classname ] ) then ErrorNoHalt( "SetPlayerClass - attempt to use unknown player class " .. classname .. "!\n" ) end
|
||||
|
||||
local id = util.NetworkStringToID( classname )
|
||||
ply:SetClassID( id )
|
||||
|
||||
-- Initialize the player class so the datatable and everything is set up
|
||||
-- This probably could be done better
|
||||
LookupPlayerClass( ply )
|
||||
|
||||
end
|
||||
|
||||
function GetPlayerClass( ply )
|
||||
|
||||
local id = ply:GetClassID()
|
||||
if ( id == 0 ) then return end
|
||||
|
||||
return util.NetworkIDToString( id )
|
||||
|
||||
end
|
||||
|
||||
function GetPlayerClassTable( ply )
|
||||
|
||||
local id = ply:GetClassID()
|
||||
if ( id == 0 ) then return end
|
||||
|
||||
local ct = Type[ util.NetworkIDToString( id ) ]
|
||||
if ( !ct ) then return end
|
||||
|
||||
return table.Copy( ct )
|
||||
|
||||
end
|
||||
|
||||
function ClearPlayerClass( ply )
|
||||
|
||||
ply:SetClassID( 0 )
|
||||
|
||||
end
|
||||
|
||||
function RunClass( ply, funcname, ... )
|
||||
|
||||
local class = LookupPlayerClass( ply )
|
||||
if ( !class ) then return end
|
||||
|
||||
local func = class[ funcname ]
|
||||
if ( !func ) then ErrorNoHalt( "Function " .. funcname .. " not found on player class!\n" ) return end
|
||||
|
||||
return func( class, ... )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Should be called on spawn automatically to set the variables below
|
||||
-- This is called in the base gamemode :PlayerSpawn function
|
||||
--
|
||||
function OnPlayerSpawn( ply, transiton )
|
||||
|
||||
local class = LookupPlayerClass( ply )
|
||||
if ( !class ) then return end
|
||||
|
||||
ply:SetSlowWalkSpeed( class.SlowWalkSpeed )
|
||||
ply:SetWalkSpeed( class.WalkSpeed )
|
||||
ply:SetRunSpeed( class.RunSpeed )
|
||||
ply:SetCrouchedWalkSpeed( class.CrouchedWalkSpeed )
|
||||
ply:SetDuckSpeed( class.DuckSpeed )
|
||||
ply:SetUnDuckSpeed( class.UnDuckSpeed )
|
||||
ply:SetJumpPower( class.JumpPower )
|
||||
ply:AllowFlashlight( class.CanUseFlashlight )
|
||||
ply:ShouldDropWeapon( class.DropWeaponOnDie )
|
||||
ply:SetNoCollideWithTeammates( class.TeammateNoCollide )
|
||||
ply:SetAvoidPlayers( class.AvoidPlayers )
|
||||
|
||||
if ( !transiton ) then
|
||||
ply:SetMaxHealth( class.MaxHealth )
|
||||
ply:SetMaxArmor( class.MaxArmor )
|
||||
ply:SetHealth( class.StartHealth )
|
||||
ply:SetArmor( class.StartArmor )
|
||||
end
|
||||
|
||||
end
|
||||
23
lua/includes/modules/playerload.lua
Normal file
23
lua/includes/modules/playerload.lua
Normal file
@@ -0,0 +1,23 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local loadQueue = {}
|
||||
|
||||
hook.Add( "PlayerInitialSpawn", "GM_FullLoadQueue", function( ply )
|
||||
loadQueue[ply] = true
|
||||
end )
|
||||
|
||||
hook.Add( "SetupMove", "GM_FullLoadInit", function( ply, _, cmd )
|
||||
if not loadQueue[ply] then return end
|
||||
if cmd:IsForced() then return end
|
||||
|
||||
loadQueue[ply] = nil
|
||||
hook.Run( "PlayerFullLoad", ply )
|
||||
end )
|
||||
415
lua/includes/modules/pon.lua
Normal file
415
lua/includes/modules/pon.lua
Normal file
@@ -0,0 +1,415 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--[[
|
||||
|
||||
DEVELOPMENTAL VERSION;
|
||||
|
||||
VERSION 1.2.2
|
||||
Copyright thelastpenguin™
|
||||
|
||||
You may use this for any purpose as long as:
|
||||
- You don't remove this copyright notice.
|
||||
- You don't claim this to be your own.
|
||||
- You properly credit the author, thelastpenguin™, if you publish your work based on (and/or using) this.
|
||||
|
||||
If you modify the code for any purpose, the above still applies to the modified code.
|
||||
|
||||
The author is not held responsible for any damages incured from the use of pon, you use it at your own risk.
|
||||
|
||||
DATA TYPES SUPPORTED:
|
||||
- tables - k,v - pointers
|
||||
- strings - k,v - pointers
|
||||
- numbers - k,v
|
||||
- booleans- k,v
|
||||
- Vectors - k,v
|
||||
- Angles - k,v
|
||||
- Entities- k,v
|
||||
- Players - k,v
|
||||
- PhysObj - k,v
|
||||
|
||||
CHANGE LOG
|
||||
V 1.1.0
|
||||
- Added Vehicle, NPC, NextBot, Player, Weapon
|
||||
V 1.2.0
|
||||
- Added custom handling for k,v tables without any array component.
|
||||
V 1.2.1
|
||||
- fixed deserialization bug.
|
||||
|
||||
THANKS TO...
|
||||
- VERCAS for the inspiration.
|
||||
]]
|
||||
|
||||
|
||||
local pon = {};
|
||||
_G.pon = pon;
|
||||
|
||||
local type, count = type, table.Count ;
|
||||
local tonumber = tonumber ;
|
||||
local format = string.format;
|
||||
do
|
||||
local type, count = type, table.Count ;
|
||||
local tonumber = tonumber ;
|
||||
local format = string.format;
|
||||
|
||||
local encode = {};
|
||||
|
||||
local tryCache ;
|
||||
|
||||
local cacheSize = 0;
|
||||
|
||||
encode['table'] = function( self, tbl, output, cache )
|
||||
|
||||
if( cache[ tbl ] )then
|
||||
output[ #output + 1 ] = format('(%x)', cache[tbl] );
|
||||
return ;
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ tbl ] = cacheSize;
|
||||
end
|
||||
|
||||
|
||||
local first = next(tbl, nil)
|
||||
local predictedNumeric = 1
|
||||
local lastKey = nil
|
||||
-- starts with a numeric dealio
|
||||
if first == 1 then
|
||||
output[#output + 1] = '{'
|
||||
|
||||
for k,v in next, tbl do
|
||||
if k == predictedNumeric then
|
||||
predictedNumeric = predictedNumeric + 1
|
||||
|
||||
local tv = type(v)
|
||||
if tv == 'string' then
|
||||
local pid = cache[v]
|
||||
if pid then
|
||||
output[#output + 1] = format('(%x)', pid)
|
||||
else
|
||||
cacheSize = cacheSize + 1
|
||||
cache[v] = cacheSize
|
||||
self.string(self, v, output, cache)
|
||||
end
|
||||
else
|
||||
self[tv](self, v, output, cache)
|
||||
end
|
||||
|
||||
else
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
predictedNumeric = predictedNumeric - 1
|
||||
else
|
||||
predictedNumeric = nil
|
||||
end
|
||||
|
||||
if predictedNumeric == nil then
|
||||
output[#output + 1] = '[' -- no array component
|
||||
else
|
||||
output[#output + 1] = '~' -- array component came first so shit needs to happen
|
||||
end
|
||||
|
||||
for k, v in next, tbl, predictedNumeric do
|
||||
local tk, tv = type(k), type(v)
|
||||
|
||||
-- WRITE KEY
|
||||
if tk == 'string' then
|
||||
local pid = cache[ k ];
|
||||
if( pid )then
|
||||
output[ #output + 1 ] = format('(%x)', pid );
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ k ] = cacheSize;
|
||||
|
||||
self.string( self, k, output, cache );
|
||||
end
|
||||
else
|
||||
self[tk](self, k, output, cache)
|
||||
end
|
||||
|
||||
-- WRITE VALUE
|
||||
if( tv == 'string' )then
|
||||
local pid = cache[ v ];
|
||||
if( pid )then
|
||||
output[ #output + 1 ] = format('(%x)', pid );
|
||||
else
|
||||
cacheSize = cacheSize + 1;
|
||||
cache[ v ] = cacheSize;
|
||||
|
||||
self.string( self, v, output, cache );
|
||||
end
|
||||
else
|
||||
self[ tv ]( self, v, output, cache );
|
||||
end
|
||||
end
|
||||
|
||||
output[#output + 1] = '}'
|
||||
end
|
||||
-- ENCODE STRING
|
||||
local gsub = string.gsub ;
|
||||
encode['string'] = function( self, str, output )
|
||||
--if tryCache( str, output ) then return end
|
||||
local estr, count = gsub( str, ";", "\\;");
|
||||
if( count == 0 )then
|
||||
output[ #output + 1 ] = '\''..str..';';
|
||||
else
|
||||
output[ #output + 1 ] = '"'..estr..'";';
|
||||
end
|
||||
end
|
||||
-- ENCODE NUMBER
|
||||
encode['number'] = function( self, num, output )
|
||||
if num%1 == 0 then
|
||||
if num < 0 then
|
||||
output[ #output + 1 ] = format( 'x%x;', -num );
|
||||
else
|
||||
output[ #output + 1 ] = format('X%x;', num );
|
||||
end
|
||||
else
|
||||
output[ #output + 1 ] = tonumber( num )..';';
|
||||
end
|
||||
end
|
||||
-- ENCODE BOOLEAN
|
||||
encode['boolean'] = function( self, val, output )
|
||||
output[ #output + 1 ] = val and 't' or 'f'
|
||||
end
|
||||
-- ENCODE VECTOR
|
||||
encode['Vector'] = function( self, val, output )
|
||||
output[ #output + 1 ] = ('v'..val.x..','..val.y)..(','..val.z..';');
|
||||
end
|
||||
-- ENCODE ANGLE
|
||||
encode['Angle'] = function( self, val, output )
|
||||
output[ #output + 1 ] = ('a'..val.p..','..val.y)..(','..val.r..';');
|
||||
end
|
||||
encode['Entity'] = function( self, val, output )
|
||||
local entIndex = val == NULL and '#' or val:EntIndex();
|
||||
output[ #output + 1] = 'E'..entIndex..';';
|
||||
end
|
||||
encode['Player'] = encode['Entity'];
|
||||
encode['Vehicle'] = encode['Entity'];
|
||||
encode['Weapon'] = encode['Entity'];
|
||||
encode['NPC'] = encode['Entity'];
|
||||
encode['NextBot'] = encode['Entity'];
|
||||
encode['PhysObj'] = encode['Entity'];
|
||||
|
||||
encode['nil'] = function( _, _, output )
|
||||
output[ #output + 1 ] = '?;';
|
||||
end
|
||||
|
||||
setmetatable( encode, {
|
||||
__index = function( self, key )
|
||||
local val = rawget( self, key );
|
||||
if val then return val end
|
||||
ErrorNoHalt('Type: '..key..' can not be encoded. Encoded as as pass-over value.');
|
||||
return rawget( self, 'nil' );
|
||||
end
|
||||
});
|
||||
|
||||
do
|
||||
local empty, concat = table.Empty, table.concat ;
|
||||
function pon.encode( tbl )
|
||||
local output = {};
|
||||
cacheSize = 0;
|
||||
encode[ 'table' ]( encode, tbl, output, {} );
|
||||
local res = concat( output );
|
||||
|
||||
return res;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do
|
||||
local tonumber = tonumber ;
|
||||
local find, sub, gsub, Explode = string.find, string.sub, string.gsub, string.Explode ;
|
||||
local Vector, Angle, Entity = Vector, Angle, Entity ;
|
||||
|
||||
local decode = {};
|
||||
decode['{'] = function( self, index, str, cache )
|
||||
|
||||
local cur = {};
|
||||
cache[ #cache + 1 ] = cur;
|
||||
|
||||
local k, v, tk, tv = 1, nil, nil, nil;
|
||||
while( true )do
|
||||
tv = sub( str, index, index );
|
||||
if( not tv or tv == '~' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
if( tv == '}' )then
|
||||
return index + 1, cur;
|
||||
end
|
||||
|
||||
-- READ THE VALUE
|
||||
index = index + 1;
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
cur[ k ] = v;
|
||||
|
||||
k = k + 1;
|
||||
end
|
||||
|
||||
while( true )do
|
||||
tk = sub( str, index, index );
|
||||
if( not tk or tk == '}' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
|
||||
-- READ THE KEY
|
||||
index = index + 1;
|
||||
index, k = self[ tk ]( self, index, str, cache );
|
||||
|
||||
-- READ THE VALUE
|
||||
tv = sub( str, index, index );
|
||||
index = index + 1;
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
|
||||
cur[ k ] = v;
|
||||
end
|
||||
|
||||
return index, cur;
|
||||
end
|
||||
decode['['] = function( self, index, str, cache )
|
||||
|
||||
local cur = {};
|
||||
cache[ #cache + 1 ] = cur;
|
||||
|
||||
local k, v, tk, tv = 1, nil, nil, nil;
|
||||
while( true )do
|
||||
tk = sub( str, index, index );
|
||||
if( not tk or tk == '}' )then
|
||||
index = index + 1;
|
||||
break ;
|
||||
end
|
||||
|
||||
-- READ THE KEY
|
||||
index = index + 1;
|
||||
index, k = self[ tk ]( self, index, str, cache );
|
||||
if not k then continue end
|
||||
|
||||
-- READ THE VALUE
|
||||
tv = sub( str, index, index );
|
||||
index = index + 1;
|
||||
if not self[tv] then
|
||||
print('did not find type: '..tv)
|
||||
end
|
||||
index, v = self[ tv ]( self, index, str, cache );
|
||||
|
||||
cur[ k ] = v;
|
||||
end
|
||||
|
||||
return index, cur;
|
||||
end
|
||||
|
||||
-- STRING
|
||||
decode['"'] = function( self, index, str, cache )
|
||||
local finish = find( str, '";', index, true );
|
||||
local res = gsub( sub( str, index, finish - 1 ), '\\;', ';' );
|
||||
index = finish + 2;
|
||||
|
||||
cache[ #cache + 1 ] = res;
|
||||
return index, res;
|
||||
end
|
||||
-- STRING NO ESCAPING NEEDED
|
||||
decode['\''] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local res = sub( str, index, finish - 1 )
|
||||
index = finish + 1;
|
||||
|
||||
cache[ #cache + 1 ] = res;
|
||||
return index, res;
|
||||
end
|
||||
|
||||
-- NUMBER
|
||||
decode['n'] = function( self, index, str, cache )
|
||||
index = index - 1;
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1 ) );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
decode['0'] = decode['n'];
|
||||
decode['1'] = decode['n'];
|
||||
decode['2'] = decode['n'];
|
||||
decode['3'] = decode['n'];
|
||||
decode['4'] = decode['n'];
|
||||
decode['5'] = decode['n'];
|
||||
decode['6'] = decode['n'];
|
||||
decode['7'] = decode['n'];
|
||||
decode['8'] = decode['n'];
|
||||
decode['9'] = decode['n'];
|
||||
decode['-'] = decode['n'];
|
||||
-- positive hex
|
||||
decode['X'] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
-- negative hex
|
||||
decode['x'] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = -tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, num;
|
||||
end
|
||||
|
||||
-- POINTER
|
||||
decode['('] = function( self, index, str, cache )
|
||||
local finish = find( str, ')', index, true );
|
||||
local num = tonumber( sub( str, index, finish - 1), 16 );
|
||||
index = finish + 1;
|
||||
return index, cache[ num ];
|
||||
end
|
||||
|
||||
-- BOOLEAN. ONE DATA TYPE FOR YES, ANOTHER FOR NO.
|
||||
decode[ 't' ] = function( self, index )
|
||||
return index, true;
|
||||
end
|
||||
decode[ 'f' ] = function( self, index )
|
||||
return index, false;
|
||||
end
|
||||
|
||||
-- VECTOR
|
||||
decode[ 'v' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local vecStr = sub( str, index, finish - 1 );
|
||||
index = finish + 1;
|
||||
local segs = Explode( ',', vecStr, false );
|
||||
return index, Vector( segs[1], segs[2], segs[3] );
|
||||
end
|
||||
-- ANGLE
|
||||
decode[ 'a' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local angStr = sub( str, index, finish - 1 );
|
||||
index = finish + 1;
|
||||
local segs = Explode( ',', angStr, false );
|
||||
return index, Angle( tonumber( segs[1] ), tonumber( segs[2] ), tonumber( segs[3] ) );
|
||||
end
|
||||
-- ENTITY
|
||||
decode[ 'E' ] = function( self, index, str, cache )
|
||||
local finish = find( str, ';', index, true );
|
||||
local num = sub( str, index, finish - 1 );
|
||||
index = finish + 1;
|
||||
return index, num == '#' and NULL or Entity( num );
|
||||
end
|
||||
-- PLAYER
|
||||
decode[ 'P' ] = decode[ 'E' ];
|
||||
-- NIL
|
||||
decode[ '?' ] = function( _, index )
|
||||
return index + 1, nil;
|
||||
end
|
||||
|
||||
|
||||
function pon.decode( data )
|
||||
local _, res = decode[ sub( data, 1, 1 ) ]( decode, 2, data, {});
|
||||
return res;
|
||||
end
|
||||
end
|
||||
65
lua/includes/modules/ppp_includes/console.lua
Normal file
65
lua/includes/modules/ppp_includes/console.lua
Normal file
@@ -0,0 +1,65 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
-- Convars
|
||||
pk_pills.convars = {}
|
||||
-- Admin vars
|
||||
pk_pills.convars.admin_restrict = CreateConVar("pk_pill_admin_restrict", game.IsDedicated() and 1 or 0, FCVAR_REPLICATED + FCVAR_NOTIFY, "Restrict morphing to admins.")
|
||||
pk_pills.convars.admin_anyweapons = CreateConVar("pk_pill_admin_anyweapons", 0, FCVAR_REPLICATED, "Allow use of any weapon when morphed.")
|
||||
pk_pills.convars.preserve = CreateConVar("pk_pill_preserve", 0, FCVAR_REPLICATED, "Makes player spit out pills when they unmorph or die.")
|
||||
|
||||
-- Client vars
|
||||
if CLIENT then
|
||||
pk_pills.convars.cl_thirdperson = CreateClientConVar("pk_pill_cl_thirdperson", 1)
|
||||
pk_pills.convars.cl_hidehud = CreateClientConVar("pk_pill_cl_hidehud", 0)
|
||||
end
|
||||
|
||||
-- Admin var setter command.
|
||||
if SERVER then
|
||||
local function admin_set(ply, cmd, args)
|
||||
if not ply then
|
||||
print("If you are using the server console, you should set the variables directly!")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not ply:IsSuperAdmin() then
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, "You must be a super admin to use this command.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local var = args[1]
|
||||
local value = args[2]
|
||||
|
||||
if not var then
|
||||
if ply then
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, "Please supply a valid convar name. Do not include 'pk_pill_admin_'.")
|
||||
end
|
||||
|
||||
return
|
||||
elseif not ConVarExists("pk_pill_admin_" .. var) then
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, "Convar 'pk_pill_admin_" .. var .. "' does not exist. Please supply a valid convar name. Do not include 'pk_pill_admin_'.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
if not value then
|
||||
ply:PrintMessage(HUD_PRINTCONSOLE, "Please supply a value to set the convar to.")
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
RunConsoleCommand("pk_pill_admin_" .. var, value)
|
||||
end
|
||||
|
||||
concommand.Add("pk_pill_admin_set", admin_set, nil, "Helper command for setting Morph Mod admin convars. Available to super admins.")
|
||||
end
|
||||
19
lua/includes/modules/ppp_includes/join_prompt.lua
Normal file
19
lua/includes/modules/ppp_includes/join_prompt.lua
Normal file
@@ -0,0 +1,19 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
if CLIENT then
|
||||
function pk_pills.join_prompt(name, addr)
|
||||
Derma_Query("Are you sure you want to join '" .. name .. "'?\nWARNING: You will exit your current game!", "", "Yes", function()
|
||||
LocalPlayer():ConCommand("connect " .. addr)
|
||||
end, "No")
|
||||
end
|
||||
end
|
||||
66
lua/includes/modules/ppp_includes/locomotion.lua
Normal file
66
lua/includes/modules/ppp_includes/locomotion.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
custom={}
|
||||
if SERVER then
|
||||
function custom.meleeEx(ply,ent,tbl)
|
||||
-- Small edit that can use a custom dmgType and doesn't force an animation, for morphs with multiple attacks in a single anim
|
||||
if !ply:IsOnGround() then return end
|
||||
timer.Simple(tbl.delay,function() if !IsValid(ent) then return end
|
||||
if !IsValid(ent) then return end
|
||||
if ply:TraceHullAttack(ply:EyePos(), ply:EyePos()+ply:EyeAngles():Forward()*tbl.range,
|
||||
Vector(-10,-10,-10),Vector(10,10,10),tbl.dmg,tbl.dmgType,0.1,true) then
|
||||
ent:PillSound("melee_hit")
|
||||
else
|
||||
ent:PillSound("melee_miss")
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function custom.LocoAnim(ply,ent,anim)
|
||||
-- New function that uses animation locomotion (ish)
|
||||
if !ply:IsOnGround() then return end
|
||||
ent:PillAnim(anim,true)
|
||||
local seq,dur = ent:GetPuppet():LookupSequence(ent.formTable.anims.default[anim])
|
||||
local ga,gb,gc = ent:GetPuppet():GetSequenceMovement(seq,0,1)
|
||||
if not ga then print("ga failed") return end -- The animation has no locomotion or it's invalid or we failed in some other way.
|
||||
|
||||
local pos = ply:GetPos()
|
||||
|
||||
local trin = {}
|
||||
trin.maxs = Vector(16, 16, 72)
|
||||
trin.mins = Vector(-16, -16, 0)
|
||||
trin.start = ply:EyePos()
|
||||
trin.endpos = gb
|
||||
trin.filter = {ply, ent, ent:GetPuppet()}
|
||||
local trout = util.TraceHull(trin)
|
||||
|
||||
local gd_prev = ent:GetPuppet():GetCycle()
|
||||
|
||||
for i=1,dur*1000 do
|
||||
timer.Simple(0.001*i,function()
|
||||
if !IsValid(ent) then return end
|
||||
if ply:GetPos() == trout.HitPos then return end -- Avoid going through walls if possible chief.
|
||||
local gd_cur = ent:GetPuppet():GetCycle()
|
||||
local ga2,gb2,gc2 = ent:GetPuppet():GetSequenceMovement(seq,gd_prev,gd_cur)
|
||||
gd_prev = gd_cur
|
||||
if not ga2 then print("ga failed") return end
|
||||
|
||||
if gd_cur==0 then return end
|
||||
|
||||
if !util.IsInWorld(ply:LocalToWorld(gb2)) then return end
|
||||
ply:SetPos(ply:LocalToWorld(gb2))
|
||||
ply:SetAngles(ply:LocalToWorldAngles(gc2))
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
103
lua/includes/modules/ppp_includes/nocompat.lua
Normal file
103
lua/includes/modules/ppp_includes/nocompat.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- Does what compat.lua used to without being so aggressive about compatability.
|
||||
-- If another addon wants to break things, IT CAN!
|
||||
AddCSLuaFile()
|
||||
|
||||
-- This will let us use the noclip key to exit morphs,
|
||||
-- while letting other mods that disable noclip do their thing.
|
||||
if CLIENT then
|
||||
local noclip_btns = {}
|
||||
|
||||
for i = KEY_FIRST, BUTTON_CODE_LAST do
|
||||
if input.LookupKeyBinding(i) == "noclip" then
|
||||
table.insert(noclip_btns, i)
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add("CreateMove", "momo_exit_check", function()
|
||||
if vgui.GetKeyboardFocus() == nil and not gui.IsGameUIVisible() then
|
||||
for _, key in pairs(noclip_btns) do
|
||||
if input.WasKeyPressed(key) then
|
||||
timer.Simple(0, function()
|
||||
RunConsoleCommand("pk_pill_restore")
|
||||
end)
|
||||
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Still dont let people noclip while morphed
|
||||
hook.Add("PlayerNoClip", "momo_block_noclip", function(ply)
|
||||
if IsValid(pk_pills.getMappedEnt(ply)) then return false end
|
||||
end)
|
||||
|
||||
-- Them hooks
|
||||
hook.Add("CalcView", "momo_calcview", function(ply, pos, ang, fov, nearZ, farZ)
|
||||
local ent = pk_pills.getMappedEnt(LocalPlayer())
|
||||
|
||||
if IsValid(ent) and ply:GetViewEntity() == ply then
|
||||
local startpos
|
||||
|
||||
if ent.formTable.type == "phys" then
|
||||
startpos = ent:LocalToWorld(ent.formTable.camera and ent.formTable.camera.offset or Vector(0, 0, 0))
|
||||
else
|
||||
startpos = pos
|
||||
end
|
||||
|
||||
if pk_pills.convars.cl_thirdperson:GetBool() then
|
||||
local dist
|
||||
|
||||
if ent.formTable.type == "phys" and ent.formTable.camera and ent.formTable.camera.distFromSize then
|
||||
dist = ent:BoundingRadius() * 5
|
||||
else
|
||||
dist = ent.formTable.camera and ent.formTable.camera.dist or 100
|
||||
end
|
||||
|
||||
local underslung = ent.formTable.camera and ent.formTable.camera.underslung
|
||||
local offset = LocalToWorld(Vector(-dist, 0, underslung and -dist / 5 or dist / 5), Angle(0, 0, 0), Vector(0, 0, 0), ang)
|
||||
|
||||
local tr = util.TraceHull({
|
||||
start = startpos,
|
||||
endpos = startpos + offset,
|
||||
filter = ent.camTraceFilter,
|
||||
mins = Vector(-5, -5, -5),
|
||||
maxs = Vector(5, 5, 5),
|
||||
mask = MASK_VISIBLE
|
||||
})
|
||||
|
||||
local view = {}
|
||||
view.origin = tr.HitPos
|
||||
view.angles = ang
|
||||
view.fov = fov
|
||||
view.drawviewer = true
|
||||
--[[else
|
||||
local view = {}
|
||||
view.origin = startpos
|
||||
view.angles = ang
|
||||
view.fov = fov
|
||||
return view]]
|
||||
|
||||
return view
|
||||
end
|
||||
end
|
||||
end)
|
||||
--[[
|
||||
hook.Add("CalcViewModelView","momo_calcviewmodel",function(wep,vm,oldPos,oldAng,pos,ang)
|
||||
local ent = pk_pills.getMappedEnt(LocalPlayer())
|
||||
local ply = wep.Owner
|
||||
if (IsValid(ent) and ply:GetViewEntity()==ply and pk_pills.convars.cl_thirdperson:GetBool()) then
|
||||
return oldPos+oldAng:Forward()*-1000,ang
|
||||
end
|
||||
end)]]
|
||||
70
lua/includes/modules/ppp_includes/restricted.lua
Normal file
70
lua/includes/modules/ppp_includes/restricted.lua
Normal file
@@ -0,0 +1,70 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
local restricted
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString("pk_pill_restricted")
|
||||
|
||||
-- rename old file
|
||||
if file.Exists("pill_config/restrictions.txt", "DATA") then
|
||||
file.Rename("pill_config/restrictions.txt", "pill_config/restricted.txt")
|
||||
end
|
||||
|
||||
-- load restrictions
|
||||
restricted = {}
|
||||
|
||||
for k, v in pairs(("\n"):Explode(file.Read("pill_config/restricted.txt") or "")) do
|
||||
restricted[v] = true
|
||||
end
|
||||
|
||||
pk_pills._restricted = restricted
|
||||
|
||||
concommand.Add("pk_pill_restrict", function(ply, cmd, args, str)
|
||||
if not ply:IsSuperAdmin() then return end
|
||||
local pill = args[1]
|
||||
local a = args[2]
|
||||
|
||||
if a == "on" then
|
||||
restricted[pill] = true
|
||||
elseif a == "off" then
|
||||
restricted[pill] = false
|
||||
end
|
||||
|
||||
local write_str = ""
|
||||
|
||||
for k, v in pairs(restricted) do
|
||||
if write_str ~= "" then
|
||||
write_str = write_str .. "\n"
|
||||
end
|
||||
|
||||
write_str = write_str .. k
|
||||
end
|
||||
|
||||
file.Write("pill_config/restricted.txt", write_str)
|
||||
net.Start("pk_pill_restricted")
|
||||
net.WriteTable(restricted)
|
||||
net.Broadcast()
|
||||
end)
|
||||
|
||||
hook.Add("PlayerInitialSpawn", "pk_pill_transmit_restricted", function(ply)
|
||||
net.Start("pk_pill_restricted")
|
||||
net.WriteTable(restricted)
|
||||
net.Send(ply)
|
||||
end)
|
||||
else
|
||||
pk_pills._restricted = {}
|
||||
|
||||
net.Receive("pk_pill_restricted", function(len, pl)
|
||||
restricted = net.ReadTable()
|
||||
pk_pills._restricted = restricted
|
||||
end)
|
||||
end
|
||||
206
lua/includes/modules/ppp_includes/sv_ai.lua
Normal file
206
lua/includes/modules/ppp_includes/sv_ai.lua
Normal file
@@ -0,0 +1,206 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local npc_sides = {
|
||||
npc_advisor = "hl_combine",
|
||||
npc_alyx = "default",
|
||||
npc_antlion = "hl_antlion",
|
||||
npc_antlion_grub = "hl_antlion",
|
||||
npc_antlionguard = "hl_antlion",
|
||||
npc_barnacle = "wild",
|
||||
npc_antlion_worker = "hl_antlion",
|
||||
npc_barney = "default",
|
||||
npc_breen = "hl_combine",
|
||||
npc_citizen = "default",
|
||||
npc_clawscanner = "hl_combine",
|
||||
npc_combine_camera = "hl_combine",
|
||||
npc_combine_s = "hl_combine",
|
||||
npc_combinedropship = "hl_combine",
|
||||
npc_combinegunship = "hl_combine",
|
||||
npc_crow = "harmless",
|
||||
npc_cscanner = "hl_combine",
|
||||
npc_dog = "default",
|
||||
npc_eli = "default",
|
||||
npc_fastzombie = "hl_zombie",
|
||||
npc_fastzombie_torso = "hl_zombie",
|
||||
npc_fisherman = "default",
|
||||
npc_gman = "harmless",
|
||||
npc_headcrab = "hl_zombie",
|
||||
npc_headcrab_black = "hl_zombie",
|
||||
npc_headcrab_fast = "hl_zombie",
|
||||
npc_helicopter = "hl_combine",
|
||||
npc_hunter = "hl_combine",
|
||||
npc_ichthyosaur = "wild",
|
||||
npc_kleiner = "default",
|
||||
npc_magnusson = "default",
|
||||
npc_manhack = "hl_combine",
|
||||
npc_metropolice = "hl_combine",
|
||||
npc_monk = "default",
|
||||
npc_mossman = "default",
|
||||
npc_pigeon = "harmless",
|
||||
npc_poisonzombie = "hl_zombie",
|
||||
npc_rollermine = "hl_combine",
|
||||
npc_seagull = "harmless",
|
||||
npc_sniper = "hl_combine",
|
||||
npc_stalker = "hl_combine",
|
||||
npc_strider = "hl_combine",
|
||||
npc_turret_ceiling = "hl_combine",
|
||||
npc_turret_floor = "hl_combine",
|
||||
npc_turret_ground = "hl_combine",
|
||||
npc_vortigaunt = "default",
|
||||
npc_zombie = "hl_zombie",
|
||||
npc_zombie_torso = "hl_zombie",
|
||||
npc_zombine = "hl_zombie"
|
||||
}
|
||||
|
||||
local side_relationships = {
|
||||
default = {
|
||||
hl_combine = D_HT,
|
||||
hl_antlion = D_HT,
|
||||
hl_zombie = D_HT,
|
||||
hl_infiltrator = D_LI
|
||||
},
|
||||
hl_combine = {
|
||||
default = D_HT,
|
||||
hl_antlion = D_HT,
|
||||
hl_zombie = D_HT,
|
||||
hl_infiltrator = D_LI
|
||||
},
|
||||
hl_antlion = {
|
||||
default = D_HT,
|
||||
hl_combine = D_HT,
|
||||
hl_zombie = D_HT,
|
||||
hl_infiltrator = D_HT
|
||||
},
|
||||
hl_zombie = {
|
||||
default = D_HT,
|
||||
hl_combine = D_HT,
|
||||
hl_antlion = D_HT,
|
||||
hl_infiltrator = D_HT
|
||||
}
|
||||
}
|
||||
|
||||
local team_map = {}
|
||||
|
||||
--AI TEAMS
|
||||
function setAiTeam(ent, side)
|
||||
if ent:IsPlayer() and side == "default" then
|
||||
team_map[ent] = nil
|
||||
else
|
||||
team_map[ent] = side
|
||||
end
|
||||
|
||||
for _, npc in pairs(ents.FindByClass("npc_*")) do
|
||||
if npc == ent or not npc.AddEntityRelationship or not IsValid(npc) then continue end
|
||||
local otherSide = getAiTeam(npc)
|
||||
|
||||
--if otherSide==nil then continue end
|
||||
if side == otherSide or side == "harmless" then
|
||||
npc:AddEntityRelationship(ent, D_LI, 99)
|
||||
elseif side == "wild" then
|
||||
npc:AddEntityRelationship(ent, D_HT, 99)
|
||||
else
|
||||
local relationship = (side_relationships[otherSide] or {})[side]
|
||||
|
||||
if relationship then
|
||||
npc:AddEntityRelationship(ent, relationship, 99)
|
||||
end
|
||||
end
|
||||
|
||||
if ent:IsNPC() then
|
||||
if otherSide == side or otherSide == "harmless" then
|
||||
ent:AddEntityRelationship(npc, D_LI, 99)
|
||||
elseif side == "wild" then
|
||||
ent:AddEntityRelationship(npc, D_HT, 99)
|
||||
else
|
||||
local relationship = (side_relationships[side] or {})[otherSide]
|
||||
|
||||
if relationship then
|
||||
ent:AddEntityRelationship(npc, relationship, 99)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if ent:IsNPC() then
|
||||
for _, ply in pairs(player.GetAll()) do
|
||||
local otherSide = getAiTeam(ply)
|
||||
|
||||
if otherSide == side or otherSide == "harmless" then
|
||||
ent:AddEntityRelationship(ply, D_LI, 99)
|
||||
elseif side == "wild" then
|
||||
ent:AddEntityRelationship(ply, D_HT, 99)
|
||||
else
|
||||
local relationship = (side_relationships[side] or {})[otherSide]
|
||||
|
||||
if relationship then
|
||||
ent:AddEntityRelationship(ply, relationship, 99)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not ent:IsPlayer() and ent:GetTable() then
|
||||
ent:CallOnRemove("ClearAiTeam", function()
|
||||
team_map[ent] = nil
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function getAiTeam(ent)
|
||||
local side
|
||||
side = team_map[ent]
|
||||
if side then return side end
|
||||
side = npc_sides[ent:GetClass()]
|
||||
if side then return side end
|
||||
--if ent.formTable then side=ent.formTable.side end
|
||||
--if side then return side end
|
||||
if ent:IsPlayer() then return "default" end
|
||||
|
||||
return "harmless"
|
||||
end
|
||||
|
||||
hook.Add("OnEntityCreated", "pk_pill_npc_spawn", function(npc)
|
||||
if npc.AddEntityRelationship then
|
||||
local otherSide = getAiTeam(npc)
|
||||
if otherSide == nil then return end
|
||||
|
||||
for ent, side in pairs(team_map) do
|
||||
if not IsValid(ent) then continue end --This really shouldn't happen. But it does. ):
|
||||
|
||||
if side == otherSide or side == "harmless" then
|
||||
npc:AddEntityRelationship(ent, D_LI, 99)
|
||||
elseif side == "wild" then
|
||||
npc:AddEntityRelationship(ent, D_HT, 99)
|
||||
else
|
||||
local relationship = (side_relationships[otherSide] or {})[side]
|
||||
if relationship == nil then continue end
|
||||
npc:AddEntityRelationship(ent, relationship, 99)
|
||||
end
|
||||
|
||||
--TODO CHECK AGAINST ALL NPCS, NOT JUST ONES IN THIS LIST -- THIS MIGHT ACTUALLY BE RIGHT
|
||||
if ent:IsNPC() then
|
||||
if otherSide == side or otherSide == "harmless" then
|
||||
ent:AddEntityRelationship(npc, D_LI, 99)
|
||||
elseif side == "wild" then
|
||||
ent:AddEntityRelationship(npc, D_HT, 99)
|
||||
else
|
||||
local relationship = (side_relationships[side] or {})[otherSide]
|
||||
if relationship == nil then continue end
|
||||
ent:AddEntityRelationship(npc, relationship, 99)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
hook.Add("PlayerDisconnected", "pk_pill_clearplayerteam", function(ply)
|
||||
team_map[ply] = nil
|
||||
end)
|
||||
35
lua/includes/modules/ppp_includes/tf2lib.lua
Normal file
35
lua/includes/modules/ppp_includes/tf2lib.lua
Normal file
@@ -0,0 +1,35 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
--Speed modifications done by tf2 weapons, effects, etc.
|
||||
hook.Add("SetupMove", "momo_tf2_movemod", function(ply, mv, cmd)
|
||||
local speedmod = 1
|
||||
|
||||
--Check weapons
|
||||
for _, wep in pairs(ply:GetWeapons()) do
|
||||
if wep.momo_SpeedMod then
|
||||
local thismod = wep:momo_SpeedMod()
|
||||
|
||||
if thismod then
|
||||
speedmod = speedmod * thismod
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--Change the speed
|
||||
if speedmod ~= 1 then
|
||||
local basevel = mv:GetVelocity()
|
||||
basevel.x = basevel.x * speedmod
|
||||
basevel.y = basevel.y * speedmod
|
||||
mv:SetVelocity(basevel)
|
||||
end
|
||||
end)
|
||||
132
lua/includes/modules/ppp_includes/util.lua
Normal file
132
lua/includes/modules/ppp_includes/util.lua
Normal file
@@ -0,0 +1,132 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
helpers = {}
|
||||
|
||||
function helpers.makeList(str, n1, n2)
|
||||
if not n2 then
|
||||
n2 = n1
|
||||
n1 = 1
|
||||
end
|
||||
|
||||
local lst = {}
|
||||
|
||||
for i = n1, n2 do
|
||||
table.insert(lst, string.Replace(str, "#", tostring(i)))
|
||||
end
|
||||
|
||||
return lst
|
||||
end
|
||||
|
||||
common = {}
|
||||
|
||||
if SERVER then
|
||||
function common.shoot(ply, ent, tbl)
|
||||
local aim = ent.formTable.aim
|
||||
if ent.formTable.canAim and not ent.formTable.canAim(ply, ent) then return end
|
||||
if aim.usesSecondaryEnt and not IsValid(ent:GetPillAimEnt()) then return end
|
||||
local aimEnt = aim.usesSecondaryEnt and ent:GetPillAimEnt() or (ent.formTable.type == "ply" and ent:GetPuppet()) or ent
|
||||
local start
|
||||
|
||||
if aim.attachment then
|
||||
start = aimEnt:GetAttachment(aimEnt:LookupAttachment(aim.attachment))
|
||||
elseif aim.offset then
|
||||
local a = ply:EyeAngles()
|
||||
a.p = 0
|
||||
|
||||
start = {
|
||||
Pos = ply:EyePos() + a:Forward() * aim.offset,
|
||||
Ang = ply:EyeAngles()
|
||||
}
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
local bullet = {}
|
||||
|
||||
-- PLZ FIX
|
||||
if aim.overrideStart then
|
||||
bullet.Src = ent:LocalToWorld(aim.overrideStart)
|
||||
else
|
||||
if not start then return end
|
||||
bullet.Src = start.Pos
|
||||
end
|
||||
|
||||
--debugoverlay.Sphere(bullet.Src,10,1, Color(0,0,255), true)
|
||||
--[[bullet.Src = start.Pos]]
|
||||
bullet.Attacker = ply
|
||||
|
||||
if aim.simple then
|
||||
bullet.Dir = ply:EyeAngles():Forward()
|
||||
else
|
||||
bullet.Dir = start.Ang:Forward()
|
||||
end
|
||||
|
||||
if tbl.spread then
|
||||
bullet.Spread = Vector(tbl.spread, tbl.spread, 0)
|
||||
end
|
||||
|
||||
bullet.Num = tbl.num
|
||||
bullet.Damage = tbl.damage
|
||||
bullet.Force = tbl.force
|
||||
bullet.Tracer = tbl.tracer and not aim.fixTracers and 1 or 0
|
||||
|
||||
if aim.fixTracers then
|
||||
bullet.Callback = function(_ply, tr, dmg)
|
||||
local ed = EffectData()
|
||||
ed:SetStart(tr.StartPos)
|
||||
ed:SetOrigin(tr.HitPos)
|
||||
ed:SetScale(5000)
|
||||
util.Effect(tbl.tracer, ed)
|
||||
end
|
||||
else
|
||||
bullet.TracerName = tbl.tracer
|
||||
end
|
||||
|
||||
--[[bullet.Callback=function(ply,tr,dmg)
|
||||
if tr.HitPos then
|
||||
debugoverlay.Sphere(tr.HitPos,50,5, Color(0,255,0), true)
|
||||
end
|
||||
end]]
|
||||
aimEnt:FireBullets(bullet)
|
||||
|
||||
--Animation
|
||||
if tbl.anim then
|
||||
ent:PillAnim(tbl.anim, true)
|
||||
end
|
||||
|
||||
--Sound
|
||||
ent:PillSound("shoot", true)
|
||||
end
|
||||
|
||||
function common.melee(ply, ent, tbl)
|
||||
if not ply:IsOnGround() then return end
|
||||
|
||||
if tbl.animCount then
|
||||
ent:PillAnim("melee" .. math.random(tbl.animCount), true)
|
||||
else
|
||||
ent:PillAnim("melee", true)
|
||||
end
|
||||
|
||||
ent:PillGesture("melee")
|
||||
ent:PillSound("melee")
|
||||
|
||||
timer.Simple(tbl.delay, function()
|
||||
if not IsValid(ent) then return end
|
||||
|
||||
if ply:TraceHullAttack(ply:EyePos(), ply:EyePos() + ply:EyeAngles():Forward() * tbl.range, Vector(-10, -10, -10), Vector(10, 10, 10), tbl.dmg, DMG_SLASH, 1, true) then
|
||||
ent:PillSound("melee_hit")
|
||||
else
|
||||
ent:PillSound("melee_miss")
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
201
lua/includes/modules/ppp_includes/vox.lua
Normal file
201
lua/includes/modules/ppp_includes/vox.lua
Normal file
@@ -0,0 +1,201 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
AddCSLuaFile()
|
||||
local voxPacks = {}
|
||||
|
||||
function registerVox(name, tbl)
|
||||
voxPacks[name] = tbl
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
concommand.Add("pk_pill_voxmenu", function(ply, cmd, args, str)
|
||||
if pk_pills.getMappedEnt(ply) and pk_pills.getMappedEnt(ply).formTable.voxSet then
|
||||
local voiceMenuSrc = [[
|
||||
<head>
|
||||
<style>
|
||||
body {-webkit-user-select: none; font-family: Arial;}
|
||||
h1 {margin: 10px 0; background-color: #CCF; border: 1px solid #00A; color: #00A; width: 150px; font-style:italic;}
|
||||
.close {background: red; border: 2px solid black; float: right;}
|
||||
.close:hover {background: #F44;}
|
||||
#input {height: 55px; background: white; border: 1px solid gray; overflow-x: auto; white-space: nowrap; font-size: 30px;}
|
||||
#picker {background: #CCC; border: 1px solid black; margin-top: 10px; overflow-y: auto; position: relative;}
|
||||
#picker>div {margin: 4px;cursor: pointer;}
|
||||
#cursor {display: inline-block; width: 0; height: 26px; border-left: 2px solid black; margin-top: 2px;}
|
||||
|
||||
#picker>div:hover {background-color: #FFC; border: 1px solid #AA0;}
|
||||
#selected {background-color: #CCF; border: 1px solid #00A;}
|
||||
|
||||
.highlight {color: red; font-weight: bold;}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<button class="close" onclick="console.log('RUNLUA:SELF:Remove()')">X</button>
|
||||
<h1>PillVox</h1>
|
||||
<div id="input"></div>
|
||||
<div id="picker"></div>
|
||||
</body>
|
||||
<script>
|
||||
var picker = document.getElementById('picker')
|
||||
var input = document.getElementById('input')
|
||||
picker.style.height= (window.innerHeight-150)+"px"
|
||||
|
||||
var phrases = []
|
||||
|
||||
var txt=""
|
||||
var cPos=0
|
||||
|
||||
function htmlSafe(str) {
|
||||
return String(str).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/ /g,' ')
|
||||
}
|
||||
|
||||
function render(renderpicker) {
|
||||
//search
|
||||
var begin = txt.substr(0,cPos)
|
||||
var end = txt.substr(cPos)
|
||||
|
||||
input.innerHTML=htmlSafe(begin)+"<div id='cursor'></div>"+htmlSafe(end)
|
||||
input.scrollLeft = input.scrollWidth
|
||||
|
||||
//picker
|
||||
if (renderpicker) {
|
||||
var out=[]
|
||||
if (txt=="") {
|
||||
for (var i in phrases) {
|
||||
out.push("<div data-phrase='"+phrases[i]+"' onclick='pick(this)'>"+phrases[i]+"</div>")
|
||||
}
|
||||
} else {
|
||||
var tosort=[]
|
||||
for (var i in phrases) {
|
||||
var phrase = phrases[i]
|
||||
|
||||
var fragments = txt.trim().split(' ')
|
||||
var score=0
|
||||
|
||||
var highlighted = phrase.replace(new RegExp(fragments.join("|"),"gi"), function(matched) {
|
||||
score+=matched.length
|
||||
return "<span class='highlight'>"+matched+"</span>"
|
||||
})
|
||||
score+=1/phrase.length
|
||||
|
||||
if (highlighted!=phrase) {
|
||||
tosort.push({html: ("<div data-phrase='"+phrase.replace(/'/g,"'")+"' onclick='pick(this)'>"+highlighted+"</div>"), score: score})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
tosort.sort(function(a,b) {return b.score-a.score})
|
||||
for (j in tosort) {
|
||||
out.push(tosort[j].html)
|
||||
}
|
||||
}
|
||||
picker.innerHTML=out.join('')
|
||||
|
||||
var selectedElement = picker.childNodes[0]
|
||||
if (selectedElement) {
|
||||
selectedElement.setAttribute("id","selected")
|
||||
selected = selectedElement.dataset.phrase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pick(e) {
|
||||
console.log('RUNLUA:RunConsoleCommand("pk_pill_vox","'+e.dataset.phrase+'")')
|
||||
console.log('RUNLUA:SELF:Remove()')
|
||||
}
|
||||
|
||||
function init(t) {
|
||||
for (k in t) {
|
||||
phrases.push(k)
|
||||
}
|
||||
phrases.sort()
|
||||
render(true)
|
||||
}
|
||||
|
||||
//cursor
|
||||
setInterval(function() {
|
||||
var cursor = document.getElementById('cursor')
|
||||
if (cursor.style.visibility=='visible')
|
||||
cursor.style.visibility='hidden'
|
||||
else
|
||||
cursor.style.visibility='visible'
|
||||
},400)
|
||||
|
||||
document.addEventListener('keydown', function(event) {
|
||||
var key = event.keyCode
|
||||
|
||||
if (key>=65 && key<=90) {
|
||||
txt=txt.substr(0,cPos)+String.fromCharCode(key+32)+txt.substr(cPos)
|
||||
cPos++
|
||||
render(true)
|
||||
} else if (key>=48 && key<=57 || key==32) {
|
||||
txt=txt.substr(0,cPos)+String.fromCharCode(key)+txt.substr(cPos)
|
||||
cPos++
|
||||
render(true)
|
||||
} else if (key==8) {
|
||||
if (cPos>0) {
|
||||
txt=txt.substr(0,cPos-1)+txt.substr(cPos)
|
||||
cPos--
|
||||
}
|
||||
render(true)
|
||||
} else if (key==13) {
|
||||
var selectedElement = document.getElementById('selected')
|
||||
if (selectedElement) {
|
||||
pick(selectedElement)
|
||||
} else {
|
||||
console.log('RUNLUA:SELF:Remove()')
|
||||
}
|
||||
render()
|
||||
} else if (key==37) {
|
||||
if (cPos>0) {
|
||||
cPos--
|
||||
}
|
||||
render()
|
||||
} else if (key==39) {
|
||||
if (cPos<txt.length) {
|
||||
cPos++
|
||||
}
|
||||
render()
|
||||
} else if (key==38) {
|
||||
var selectedElement = document.getElementById('selected')
|
||||
if (selectedElement.previousSibling) {
|
||||
selectedElement.removeAttribute('id')
|
||||
selectedElement=selectedElement.previousSibling
|
||||
selectedElement.setAttribute("id","selected")
|
||||
picker.scrollTop = selectedElement.offsetTop-225
|
||||
}
|
||||
} else if (key==40) {
|
||||
var selectedElement = document.getElementById('selected')
|
||||
if (selectedElement.nextSibling) {
|
||||
selectedElement.removeAttribute('id')
|
||||
selectedElement=selectedElement.nextSibling
|
||||
selectedElement.setAttribute("id","selected")
|
||||
picker.scrollTop = selectedElement.offsetTop-225
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
]]
|
||||
local html = vgui.Create("DHTML", panel)
|
||||
html:SetPos(10, ScrH() / 6)
|
||||
html:SetSize(300, ScrH() * (2 / 3))
|
||||
html:SetAllowLua(true)
|
||||
html:SetHTML(voiceMenuSrc)
|
||||
html:RunJavascript("init(" .. util.TableToJSON(voxPacks[pk_pills.getMappedEnt(ply).formTable.voxSet]) .. ")")
|
||||
html:MakePopup()
|
||||
end
|
||||
end)
|
||||
else
|
||||
concommand.Add("pk_pill_vox", function(ply, cmd, args, str)
|
||||
if pk_pills.getMappedEnt(ply) and pk_pills.getMappedEnt(ply).formTable.voxSet then
|
||||
pk_pills.getMappedEnt(ply):EmitSound(voxPacks[pk_pills.getMappedEnt(ply).formTable.voxSet][args[1]])
|
||||
end
|
||||
end)
|
||||
end
|
||||
101
lua/includes/modules/presets.lua
Normal file
101
lua/includes/modules/presets.lua
Normal file
@@ -0,0 +1,101 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "presets", package.seeall )
|
||||
|
||||
-- TODO: A function to check/replace invalid characters for filenames!
|
||||
|
||||
local Presets = LoadPresets()
|
||||
|
||||
function GetTable( presetname )
|
||||
|
||||
if ( !presetname ) then return end
|
||||
presetname = presetname:Trim()
|
||||
if ( presetname == "" ) then return end
|
||||
|
||||
Presets[ presetname ] = Presets[ presetname ] or {}
|
||||
|
||||
return Presets[ presetname ]
|
||||
|
||||
end
|
||||
|
||||
function Exists( presetname, strName )
|
||||
|
||||
if ( !presetname || !strName ) then return false end
|
||||
presetname = presetname:Trim()
|
||||
strName = strName:Trim()
|
||||
if ( presetname == "" || strName == "" ) then return false end
|
||||
|
||||
if ( !Presets[ presetname ] || !Presets[ presetname ][ strName ] ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function Add( presetname, strName, pTable )
|
||||
|
||||
if ( !presetname || !strName ) then return end
|
||||
presetname = presetname:Trim()
|
||||
strName = strName:Trim()
|
||||
if ( presetname == "" || strName == "" ) then return end
|
||||
|
||||
Presets[ presetname ] = Presets[ presetname ] or {}
|
||||
Presets[ presetname ][ strName ] = pTable
|
||||
|
||||
-- Only save the specific preset group, not ALL of them
|
||||
SavePresets( { [ presetname ] = Presets[ presetname ] } )
|
||||
|
||||
end
|
||||
|
||||
function Rename( presetname, strName, strToName )
|
||||
|
||||
if ( !presetname || !strName || !strToName || strName == strToName ) then return end
|
||||
presetname = presetname:Trim()
|
||||
strName = strName:Trim()
|
||||
strToName = strToName:Trim()
|
||||
if ( presetname == "" || strName == "" || strToName == "" || strName == strToName ) then return end
|
||||
|
||||
Presets[ presetname ] = Presets[ presetname ] or {}
|
||||
Presets[ presetname ][ strToName ] = Presets[ presetname ][ strName ]
|
||||
Presets[ presetname ][ strName ] = nil
|
||||
|
||||
-- Only save the specific preset group, not ALL of them
|
||||
SavePresets( { [ presetname ] = Presets[ presetname ] } )
|
||||
|
||||
end
|
||||
|
||||
function Remove( presetname, strName )
|
||||
|
||||
if ( !presetname || !strName ) then return end
|
||||
presetname = presetname:Trim()
|
||||
strName = strName:Trim()
|
||||
if ( presetname == "" || strName == "" ) then return end
|
||||
|
||||
Presets[ presetname ] = Presets[ presetname ] or {}
|
||||
Presets[ presetname ][ strName ] = nil
|
||||
|
||||
-- Only save the specific preset group, not ALL of them
|
||||
SavePresets( { [ presetname ] = Presets[ presetname ] } )
|
||||
|
||||
end
|
||||
|
||||
-- Internal helper functions to not copypaste same code
|
||||
function BadNameAlert()
|
||||
|
||||
Derma_Message( "#preset.badname_desc", "#preset.badname_title", "#preset.okay" )
|
||||
|
||||
end
|
||||
|
||||
function OverwritePresetPrompt( func )
|
||||
|
||||
Derma_Query( "#preset.exists_desc", "#preset.exists_title", "#preset.overwrite", func, "#preset.cancel" )
|
||||
|
||||
end
|
||||
264
lua/includes/modules/properties.lua
Normal file
264
lua/includes/modules/properties.lua
Normal file
@@ -0,0 +1,264 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "properties", package.seeall )
|
||||
|
||||
local meta = {
|
||||
MsgStart = function( self )
|
||||
|
||||
net.Start( "properties" )
|
||||
net.WriteString( self.InternalName )
|
||||
|
||||
end,
|
||||
|
||||
MsgEnd = function( self )
|
||||
|
||||
net.SendToServer()
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
meta.__index = meta
|
||||
|
||||
List = {}
|
||||
-- .MenuLabel [string] Label to show on opened menu
|
||||
-- .Filter( ent ) [function] Return true if we should show a menu for this entity
|
||||
-- .Action( ent ) [function] On menu choice selected
|
||||
-- .Order [int] The order in which it should be shown on the menu
|
||||
-- .Receive( len, ply ) [function] A message has been received from the clientside version
|
||||
|
||||
function Add( name, tab )
|
||||
|
||||
name = name:lower()
|
||||
tab.InternalName = name
|
||||
setmetatable( tab, meta )
|
||||
|
||||
List[ name ] = tab
|
||||
|
||||
end
|
||||
|
||||
local function AddToggleOption( data, menu, ent, ply, tr )
|
||||
|
||||
if ( !menu.ToggleSpacer ) then
|
||||
menu.ToggleSpacer = menu:AddSpacer()
|
||||
menu.ToggleSpacer:SetZPos( 500 )
|
||||
end
|
||||
|
||||
local option = menu:AddOption( data.MenuLabel, function() data:Action( ent, tr ) end )
|
||||
option:SetChecked( data:Checked( ent, ply ) )
|
||||
option:SetZPos( 501 )
|
||||
return option
|
||||
|
||||
end
|
||||
|
||||
local function AddOption( data, menu, ent, ply, tr )
|
||||
|
||||
if ( data.Type == "toggle" ) then return AddToggleOption( data, menu, ent, ply, tr ) end
|
||||
|
||||
if ( data.PrependSpacer ) then
|
||||
menu:AddSpacer()
|
||||
end
|
||||
|
||||
local option = menu:AddOption( data.MenuLabel, function() data:Action( ent, tr ) end )
|
||||
|
||||
if ( data.MenuIcon ) then
|
||||
option:SetImage( data.MenuIcon )
|
||||
end
|
||||
|
||||
if ( data.MenuOpen ) then
|
||||
data.MenuOpen( data, option, ent, tr )
|
||||
end
|
||||
|
||||
return option
|
||||
|
||||
end
|
||||
|
||||
function OpenEntityMenu( ent, tr )
|
||||
|
||||
local menu = DermaMenu()
|
||||
|
||||
for k, v in SortedPairsByMemberValue( List, "Order" ) do
|
||||
|
||||
if ( !v.Filter ) then continue end
|
||||
if ( !v:Filter( ent, LocalPlayer() ) ) then continue end
|
||||
|
||||
local option = AddOption( v, menu, ent, LocalPlayer(), tr )
|
||||
|
||||
if ( v.OnCreate ) then v:OnCreate( menu, option ) end
|
||||
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
|
||||
end
|
||||
|
||||
function OnScreenClick( eyepos, eyevec )
|
||||
|
||||
local ent, tr = GetHovered( eyepos, eyevec )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
OpenEntityMenu( ent, tr )
|
||||
|
||||
end
|
||||
|
||||
-- Use this check in your properties to see if given entity can be affected by it
|
||||
-- Ideally this should be done automatically for you, but due to how this system was set up, its now impossible
|
||||
function CanBeTargeted( ent, ply )
|
||||
if ( !IsValid( ent ) ) then return false end
|
||||
if ( ent:IsPlayer() ) then return false end
|
||||
|
||||
-- Check the range if player object is given
|
||||
-- This is not perfect, but it is close enough and its definitely better than nothing
|
||||
if ( IsValid( ply ) ) then
|
||||
local mins = ent:OBBMins()
|
||||
local maxs = ent:OBBMaxs()
|
||||
local maxRange = math.max( math.abs( mins.x ) + maxs.x, math.abs( mins.y ) + maxs.y, math.abs( mins.z ) + maxs.z )
|
||||
local pos = ent:LocalToWorld( ent:OBBCenter() ) --ent:GetPos()
|
||||
|
||||
if ( pos:Distance( ply:GetShootPos() ) > maxRange + 1024 ) then return false end
|
||||
end
|
||||
|
||||
return !( ent:GetPhysicsObjectCount() < 1 && ent:GetSolid() == SOLID_NONE && bit.band( ent:GetSolidFlags(), FSOLID_USE_TRIGGER_BOUNDS ) == 0 && bit.band( ent:GetSolidFlags(), FSOLID_CUSTOMRAYTEST ) == 0 )
|
||||
end
|
||||
|
||||
function GetHovered( eyepos, eyevec )
|
||||
|
||||
local ply = LocalPlayer()
|
||||
local filter = ply:GetViewEntity()
|
||||
|
||||
if ( filter == ply ) then
|
||||
local veh = ply:GetVehicle()
|
||||
|
||||
if ( veh:IsValid() && ( !veh:IsVehicle() || !veh:GetThirdPersonMode() ) ) then
|
||||
-- A dirty hack for prop_vehicle_crane. util.TraceLine returns the vehicle but it hits phys_bone_follower - something that needs looking into
|
||||
filter = { filter, veh, unpack( ents.FindByClass( "phys_bone_follower" ) ) }
|
||||
end
|
||||
end
|
||||
|
||||
local trace = util.TraceLine( {
|
||||
start = eyepos,
|
||||
endpos = eyepos + eyevec * 1024,
|
||||
filter = filter
|
||||
} )
|
||||
|
||||
-- Hit COLLISION_GROUP_DEBRIS and stuff
|
||||
if ( !trace.Hit || !IsValid( trace.Entity ) ) then
|
||||
trace = util.TraceLine( {
|
||||
start = eyepos,
|
||||
endpos = eyepos + eyevec * 1024,
|
||||
filter = filter,
|
||||
mask = MASK_ALL
|
||||
} )
|
||||
end
|
||||
|
||||
if ( !trace.Hit || !IsValid( trace.Entity ) ) then return end
|
||||
|
||||
return trace.Entity, trace
|
||||
|
||||
end
|
||||
|
||||
-- Receives commands from clients
|
||||
if ( SERVER ) then
|
||||
|
||||
util.AddNetworkString( "properties" )
|
||||
|
||||
net.Receive( "properties", function( len, client )
|
||||
if ( !IsValid( client ) ) then return end
|
||||
|
||||
local name = net.ReadString()
|
||||
if ( !name ) then return end
|
||||
|
||||
local prop = List[ name ]
|
||||
if ( !prop ) then return end
|
||||
if ( !prop.Receive ) then return end
|
||||
|
||||
prop:Receive( len, client )
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
local lastEyePos = vector_origin
|
||||
local function UpdateEyePos()
|
||||
-- A bit of a hack due to EyePos() being affected by other rendering functions
|
||||
-- So we cache the value when we know it is the correct value for the frame
|
||||
lastEyePos = EyePos()
|
||||
end
|
||||
|
||||
hook.Add( "PreDrawHalos", "PropertiesHover", function()
|
||||
|
||||
if ( !IsValid( vgui.GetHoveredPanel() ) || !vgui.GetHoveredPanel():IsWorldClicker() ) then return end
|
||||
|
||||
UpdateEyePos()
|
||||
|
||||
local ent = GetHovered( lastEyePos, LocalPlayer():GetAimVector() )
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local c = Color( 255, 255, 255, 255 )
|
||||
c.r = 200 + math.sin( RealTime() * 50 ) * 55
|
||||
c.g = 200 + math.sin( RealTime() * 20 ) * 55
|
||||
c.b = 200 + math.cos( RealTime() * 60 ) * 55
|
||||
|
||||
local t = { ent }
|
||||
if ( ent.GetActiveWeapon && IsValid( ent:GetActiveWeapon() ) ) then table.insert( t, ent:GetActiveWeapon() ) end
|
||||
halo.Add( t, c, 2, 2, 2, true, false )
|
||||
|
||||
end )
|
||||
|
||||
hook.Add( "PreDrawEffects", "PropertiesUpdateEyePos", function()
|
||||
UpdateEyePos()
|
||||
end )
|
||||
|
||||
hook.Add( "GUIMousePressed", "PropertiesClick", function( code, vector )
|
||||
|
||||
if ( !IsValid( vgui.GetHoveredPanel() ) || !vgui.GetHoveredPanel():IsWorldClicker() ) then return end
|
||||
|
||||
if ( code == MOUSE_RIGHT && !input.IsButtonDown( MOUSE_LEFT ) ) then
|
||||
OnScreenClick( lastEyePos, vector )
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
local wasPressed = false
|
||||
hook.Add( "PreventScreenClicks", "PropertiesPreventClicks", function()
|
||||
|
||||
if ( !input.IsButtonDown( MOUSE_RIGHT ) ) then wasPressed = false end
|
||||
|
||||
if ( wasPressed && input.IsButtonDown( MOUSE_RIGHT ) && !input.IsButtonDown( MOUSE_LEFT ) ) then return true end
|
||||
|
||||
if ( !IsValid( vgui.GetHoveredPanel() ) || !vgui.GetHoveredPanel():IsWorldClicker() ) then return end
|
||||
|
||||
local ply = LocalPlayer()
|
||||
if ( !IsValid( ply ) ) then return end
|
||||
|
||||
--
|
||||
-- Are we pressing the right mouse button?
|
||||
-- (We check whether we're pressing the left too, to allow for physgun freezes)
|
||||
--
|
||||
if ( input.IsButtonDown( MOUSE_RIGHT ) && !input.IsButtonDown( MOUSE_LEFT ) ) then
|
||||
|
||||
--
|
||||
-- Are we hovering an entity? If so, then stomp the action
|
||||
--
|
||||
local hovered = GetHovered( lastEyePos, ply:GetAimVector() )
|
||||
|
||||
if ( IsValid( hovered ) ) then
|
||||
wasPressed = true
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
436
lua/includes/modules/saverestore.lua
Normal file
436
lua/includes/modules/saverestore.lua
Normal file
@@ -0,0 +1,436 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local Msg = Msg
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local gmod = gmod
|
||||
local table = table
|
||||
|
||||
--[[
|
||||
|
||||
This module is to help bind the engine's saverestore stuff to Lua.
|
||||
|
||||
This is so we can save Lua stuff in the save game file. The entities
|
||||
should automatically save most of their table contents to the save file.
|
||||
|
||||
!!Warning!!: Editing this file may render old saves useless.
|
||||
|
||||
You can hook into this system like so
|
||||
|
||||
local function MySaveFunction( save )
|
||||
saverestore.WriteTable( my_table, save )
|
||||
end
|
||||
|
||||
local function MyRestoreFunction( restore )
|
||||
my_table = saverestore.ReadTable( restore )
|
||||
end
|
||||
|
||||
saverestore.AddSaveHook( "HookNameHere", MySaveFunction )
|
||||
saverestore.AddRestoreHook( "HookNameHere", MyRestoreFunction )
|
||||
|
||||
--]]
|
||||
|
||||
module( "saverestore" )
|
||||
|
||||
local TYPE_NONE = 0
|
||||
local TYPE_FLOAT = 1 -- Treat all numbers as floats (they're all the same to Lua)
|
||||
local TYPE_STRING = 2
|
||||
local TYPE_ENTITY = 3
|
||||
local TYPE_VECTOR = 4
|
||||
local TYPE_TABLE = 5
|
||||
local TYPE_BOOL = 6
|
||||
local TYPE_ANGLE = 7
|
||||
|
||||
local SaveHooks = {}
|
||||
local RestoreHooks = {}
|
||||
local TableRefs = {}
|
||||
local TableRef = 1
|
||||
|
||||
function PreSave()
|
||||
|
||||
TableRefs = {}
|
||||
TableRef = 1
|
||||
|
||||
end
|
||||
|
||||
function PreRestore()
|
||||
|
||||
TableRefs = {}
|
||||
TableRef = 1
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTypeStr
|
||||
Desc: Given a string returns a TYPE_
|
||||
-----------------------------------------------------------]]
|
||||
local function GetTypeStr( name )
|
||||
|
||||
if ( name == "function" ) then return TYPE_NONE end
|
||||
|
||||
if ( name == "number" ) then return TYPE_FLOAT end
|
||||
if ( name == "string" ) then return TYPE_STRING end
|
||||
if ( name == "Entity" ) then return TYPE_ENTITY end
|
||||
if ( name == "Vehicle" ) then return TYPE_ENTITY end
|
||||
if ( name == "NPC" ) then return TYPE_ENTITY end
|
||||
if ( name == "Player" ) then return TYPE_ENTITY end
|
||||
if ( name == "Weapon" ) then return TYPE_ENTITY end
|
||||
if ( name == "Vector" ) then return TYPE_VECTOR end
|
||||
if ( name == "Angle" ) then return TYPE_ANGLE end
|
||||
if ( name == "table" ) then return TYPE_TABLE end
|
||||
if ( name == "boolean" ) then return TYPE_BOOL end
|
||||
|
||||
-- These aren't saved
|
||||
if ( name == "ConVar" ) then return TYPE_NONE end
|
||||
if ( name == "PhysObj" ) then return TYPE_NONE end
|
||||
|
||||
-- Bitch about it incase I've forgot to hook a savable type up
|
||||
Msg( "Can't save unknown type " .. name .. "\n" )
|
||||
return TYPE_NONE
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetType
|
||||
Desc: Given a variable returns a TYPE_
|
||||
-----------------------------------------------------------]]
|
||||
local function GetType( var )
|
||||
|
||||
return GetTypeStr( type(var) )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsWritable
|
||||
Desc: Returns true if we can save the K/V pair
|
||||
-----------------------------------------------------------]]
|
||||
local function IsWritable( k, v )
|
||||
|
||||
local itype = GetType( k )
|
||||
if ( itype == TYPE_NONE ) then return false end
|
||||
if ( itype == TYPE_STRING && k == "SR_Recursion" ) then return false end
|
||||
|
||||
local itype = GetType( v )
|
||||
if ( itype == TYPE_NONE ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: WriteVar
|
||||
Desc: Writes a single variable to the save
|
||||
-----------------------------------------------------------]]
|
||||
function WritableKeysInTable( t )
|
||||
|
||||
local i = 0
|
||||
|
||||
for k, v in pairs( t ) do
|
||||
if ( IsWritable( k, v ) ) then
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
return i
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: WriteVar
|
||||
Desc: Writes a single variable to the save
|
||||
-----------------------------------------------------------]]
|
||||
function WriteVar( var, save )
|
||||
|
||||
local itype = GetType( var )
|
||||
if ( itype == TYPE_NONE ) then return end
|
||||
|
||||
save:StartBlock( type( var ) )
|
||||
|
||||
if ( itype == TYPE_FLOAT ) then
|
||||
save:WriteFloat( var )
|
||||
elseif ( itype == TYPE_BOOL ) then
|
||||
save:WriteBool( var )
|
||||
elseif ( itype == TYPE_STRING ) then
|
||||
save:WriteString( var )
|
||||
elseif ( itype == TYPE_ENTITY ) then
|
||||
save:WriteEntity( var )
|
||||
elseif ( itype == TYPE_ANGLE ) then
|
||||
save:WriteAngle( var )
|
||||
elseif ( itype == TYPE_VECTOR ) then
|
||||
save:WriteVector( var )
|
||||
elseif ( itype == TYPE_TABLE ) then
|
||||
WriteTable( var, save )
|
||||
else
|
||||
Msg( "Error! Saving unsupported Type: " .. type( var ) .. "\n" )
|
||||
end
|
||||
|
||||
save:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ReadVar
|
||||
Desc: Reads a single variable
|
||||
-----------------------------------------------------------]]
|
||||
function ReadVar( restore )
|
||||
|
||||
local retval = 0
|
||||
local typename = restore:StartBlock()
|
||||
|
||||
local itype = GetTypeStr( typename )
|
||||
|
||||
if ( itype == TYPE_FLOAT ) then
|
||||
retval = restore:ReadFloat()
|
||||
elseif ( itype == TYPE_BOOL ) then
|
||||
retval = restore:ReadBool()
|
||||
elseif ( itype == TYPE_STRING ) then
|
||||
retval = restore:ReadString()
|
||||
elseif ( itype == TYPE_ENTITY ) then
|
||||
retval = restore:ReadEntity()
|
||||
elseif ( itype == TYPE_ANGLE ) then
|
||||
retval = restore:ReadAngle()
|
||||
elseif ( itype == TYPE_VECTOR ) then
|
||||
retval = restore:ReadVector()
|
||||
elseif ( itype == TYPE_TABLE ) then
|
||||
retval = ReadTable( restore )
|
||||
else
|
||||
Msg( "Error! Loading unsupported Type: " .. typename .. "\n" )
|
||||
end
|
||||
|
||||
restore:EndBlock()
|
||||
|
||||
return retval
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: WriteTable
|
||||
Desc: Writes a table to the save
|
||||
-----------------------------------------------------------]]
|
||||
function WriteTable( tab, save )
|
||||
|
||||
-- Write a blank table (because read will be expecting one)
|
||||
if ( tab == nil ) then
|
||||
|
||||
save:StartBlock( "Table" )
|
||||
save:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
-- We have already saved this table
|
||||
if ( TableRefs[ tab ] ) then
|
||||
|
||||
save:StartBlock( "TableRef" )
|
||||
save:WriteInt( TableRefs[ tab ] )
|
||||
save:EndBlock()
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
TableRefs[ tab ] = TableRef
|
||||
|
||||
save:StartBlock( "Table" )
|
||||
|
||||
local iCount = WritableKeysInTable( tab )
|
||||
|
||||
save:WriteInt( TableRef )
|
||||
TableRef = TableRef + 1
|
||||
|
||||
save:WriteInt( iCount )
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
if ( IsWritable( k, v ) ) then
|
||||
|
||||
WriteVar( k, save )
|
||||
WriteVar( v, save )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
save:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ReadTable
|
||||
Desc: Assumes a table is waiting to be read, returns a table
|
||||
-----------------------------------------------------------]]
|
||||
function ReadTable( restore )
|
||||
|
||||
local name = restore:StartBlock()
|
||||
local tab = {}
|
||||
|
||||
if ( name == "TableRef" ) then
|
||||
|
||||
local ref = restore:ReadInt()
|
||||
if ( !TableRefs[ ref ] ) then
|
||||
TableRefs[ ref ] = {}
|
||||
return
|
||||
end
|
||||
|
||||
tab = TableRefs[ ref ]
|
||||
|
||||
else
|
||||
|
||||
local iRef = restore:ReadInt()
|
||||
local iCount = restore:ReadInt()
|
||||
|
||||
if ( TableRefs[ iRef ] ) then
|
||||
tab = TableRefs[ iRef ]
|
||||
end
|
||||
|
||||
for i = 0, iCount - 1 do
|
||||
|
||||
local k = ReadVar( restore )
|
||||
local v = ReadVar( restore )
|
||||
tab[ k ] = v
|
||||
|
||||
end
|
||||
|
||||
TableRefs[ iRef ] = tab
|
||||
|
||||
end
|
||||
|
||||
restore:EndBlock()
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SaveEntity
|
||||
Desc: Called by the engine for each entity
|
||||
-----------------------------------------------------------]]
|
||||
function SaveEntity( ent, save )
|
||||
|
||||
save:StartBlock( "EntityTable" )
|
||||
|
||||
WriteTable( ent:GetTable(), save )
|
||||
|
||||
save:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LoadEntity
|
||||
Desc: Called by the engine for each entity
|
||||
-----------------------------------------------------------]]
|
||||
function LoadEntity( ent, restore )
|
||||
|
||||
local EntTable = ent:GetTable()
|
||||
|
||||
local name = restore:StartBlock()
|
||||
|
||||
if ( name == "EntityTable" ) then
|
||||
|
||||
table.Merge( EntTable, ReadTable( restore ) )
|
||||
|
||||
end
|
||||
|
||||
restore:EndBlock()
|
||||
|
||||
ent:SetTable( EntTable )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AddSaveHook
|
||||
Desc: Adds a hook enabling something to save something..
|
||||
-----------------------------------------------------------]]
|
||||
function AddSaveHook( name, func )
|
||||
|
||||
local h = {}
|
||||
h.Name = name
|
||||
h.Func = func
|
||||
SaveHooks[ name ] = h
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AddRestoreHook
|
||||
Desc: Adds a hook enabling something to restore something..
|
||||
-----------------------------------------------------------]]
|
||||
function AddRestoreHook( name, func )
|
||||
|
||||
local h = {}
|
||||
h.Name = name
|
||||
h.Func = func
|
||||
RestoreHooks[ name ] = h
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SaveGlobal
|
||||
Desc: Should save any Lua stuff that isn't entity based.
|
||||
-----------------------------------------------------------]]
|
||||
function SaveGlobal( save )
|
||||
|
||||
save:StartBlock( "GameMode" )
|
||||
WriteTable( gmod.GetGamemode(), save )
|
||||
save:EndBlock()
|
||||
|
||||
for k, v in pairs( SaveHooks ) do
|
||||
|
||||
save:StartBlock( v.Name )
|
||||
|
||||
v.Func( save )
|
||||
|
||||
save:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LoadGlobal
|
||||
Desc: ...
|
||||
-----------------------------------------------------------]]
|
||||
function LoadGlobal( restore )
|
||||
|
||||
local name = restore:StartBlock()
|
||||
|
||||
if ( name == "GameMode" ) then
|
||||
table.Merge( gmod.GetGamemode(), ReadTable( restore ) )
|
||||
end
|
||||
|
||||
restore:EndBlock()
|
||||
|
||||
|
||||
while ( name != "EndGlobal" ) do
|
||||
|
||||
name = restore:StartBlock()
|
||||
|
||||
local tab = RestoreHooks[ name ]
|
||||
if ( tab ) then
|
||||
|
||||
tab.Func( restore )
|
||||
|
||||
end
|
||||
|
||||
restore:EndBlock()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
288
lua/includes/modules/scripted_ents.lua
Normal file
288
lua/includes/modules/scripted_ents.lua
Normal file
@@ -0,0 +1,288 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: scripted_ents
|
||||
Desc: Scripted Entity factory
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
module( "scripted_ents", package.seeall )
|
||||
|
||||
local Aliases = {}
|
||||
local SEntList = {}
|
||||
|
||||
local BaseClasses = {}
|
||||
BaseClasses[ "anim" ] = "base_anim"
|
||||
BaseClasses[ "point" ] = "base_point"
|
||||
BaseClasses[ "brush" ] = "base_brush"
|
||||
BaseClasses[ "filter" ] = "base_filter"
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TableInherit( t, base )
|
||||
Desc: Copies any missing data from base to t
|
||||
-----------------------------------------------------------]]
|
||||
local function TableInherit( t, base )
|
||||
|
||||
for k, v in pairs( base ) do
|
||||
|
||||
if ( t[ k ] == nil ) then
|
||||
t[ k ] = v
|
||||
elseif ( k != "BaseClass" && istable( t[ k ] ) && istable( v ) ) then
|
||||
TableInherit( t[ k ], v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
t[ "BaseClass" ] = base
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsBasedOn( name, base )
|
||||
Desc: Checks if name is based on base
|
||||
-----------------------------------------------------------]]
|
||||
function IsBasedOn( name, base )
|
||||
local t = GetStored( name )
|
||||
if not t then return false end
|
||||
if t.Base == name then return false end
|
||||
|
||||
if t.Base == base then return true end
|
||||
return IsBasedOn( t.Base, base )
|
||||
end
|
||||
|
||||
function Register( t, name )
|
||||
|
||||
if ( hook.Run( "PreRegisterSENT", t, name ) == false ) then return end
|
||||
|
||||
if ( isstring( t.ClassNameOverride ) ) then name = t.ClassNameOverride end
|
||||
|
||||
local Base = t.Base
|
||||
if ( !Base ) then Base = BaseClasses[ t.Type ] end
|
||||
|
||||
local old = SEntList[ name ]
|
||||
local tab = {}
|
||||
|
||||
tab.type = t.Type
|
||||
tab.t = t
|
||||
tab.isBaseType = true
|
||||
tab.Base = Base
|
||||
tab.t.ClassName = name
|
||||
|
||||
if ( !Base ) then
|
||||
Msg( "WARNING: Scripted entity " .. name .. " has an invalid base entity!\n" )
|
||||
end
|
||||
|
||||
SEntList[ name ] = tab
|
||||
|
||||
-- Allow all SENTS to be duplicated, unless specified
|
||||
if ( !t.DisableDuplicator ) then
|
||||
duplicator.Allow( name )
|
||||
end
|
||||
|
||||
--
|
||||
-- If we're reloading this entity class
|
||||
-- then refresh all the existing entities.
|
||||
--
|
||||
if ( old != nil ) then
|
||||
|
||||
--
|
||||
-- For each entity using this class
|
||||
--
|
||||
for _, entity in ipairs( ents.FindByClass( name ) ) do
|
||||
|
||||
--
|
||||
-- Replace the contents with this entity table
|
||||
--
|
||||
table.Merge( entity, tab.t )
|
||||
|
||||
--
|
||||
-- Call OnReloaded hook (if it has one)
|
||||
--
|
||||
if ( entity.OnReloaded ) then
|
||||
entity:OnReloaded()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Update entity table of entities that are based on this entity
|
||||
for _, e in ipairs( ents.GetAll() ) do
|
||||
if ( IsBasedOn( e:GetClass(), name ) ) then
|
||||
|
||||
table.Merge( e, Get( e:GetClass() ) )
|
||||
|
||||
if ( e.OnReloaded ) then
|
||||
e:OnReloaded()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( !t.Spawnable ) then return end
|
||||
|
||||
list.Set( "SpawnableEntities", name, {
|
||||
-- Required information
|
||||
PrintName = t.PrintName,
|
||||
ClassName = name,
|
||||
Category = t.Category,
|
||||
|
||||
-- Optional information
|
||||
NormalOffset = t.NormalOffset,
|
||||
DropToFloor = t.DropToFloor,
|
||||
Author = t.Author,
|
||||
AdminOnly = t.AdminOnly,
|
||||
Information = t.Information,
|
||||
ScriptedEntityType = t.ScriptedEntityType,
|
||||
IconOverride = t.IconOverride
|
||||
} )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- All scripts have been loaded...
|
||||
--
|
||||
function OnLoaded()
|
||||
|
||||
--
|
||||
-- Once all the scripts are loaded we can set up the baseclass
|
||||
-- - we have to wait until they're all setup because load order
|
||||
-- could cause some entities to load before their bases!
|
||||
--
|
||||
for k, v in pairs( SEntList ) do
|
||||
|
||||
baseclass.Set( k, Get( k ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Get( name, retval )
|
||||
|
||||
-- Do we have an alias?
|
||||
if ( Aliases[ name ] ) then
|
||||
name = Aliases[ name ]
|
||||
end
|
||||
|
||||
if ( SEntList[ name ] == nil ) then return nil end
|
||||
|
||||
-- Create/copy a new table
|
||||
local retval = retval or {}
|
||||
for k, v in pairs( SEntList[ name ].t ) do
|
||||
if ( istable( v ) ) then
|
||||
retval[ k ] = table.Copy( v )
|
||||
else
|
||||
retval[ k ] = v
|
||||
end
|
||||
end
|
||||
|
||||
-- Derive from base class
|
||||
if ( SEntList[ name ].Base != name ) then
|
||||
|
||||
local base = Get( SEntList[ name ].Base )
|
||||
|
||||
if ( !base ) then
|
||||
Msg("ERROR: Trying to derive entity " .. tostring( name ) .. " from non existant entity " .. tostring( SEntList[ name ].Base ) .. "!\n" )
|
||||
else
|
||||
retval = TableInherit( retval, base )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return retval
|
||||
|
||||
end
|
||||
|
||||
function GetType( name )
|
||||
|
||||
for k, v in pairs( BaseClasses ) do
|
||||
if ( name == v ) then return k end
|
||||
end
|
||||
|
||||
local ent = SEntList[ name ]
|
||||
if ( ent == nil ) then return nil end
|
||||
|
||||
if ( ent.type ) then
|
||||
return ent.type
|
||||
end
|
||||
|
||||
if ( ent.Base ) then
|
||||
return GetType( ent.Base )
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetStored( string )
|
||||
Desc: Gets the REAL sent table, not a copy
|
||||
-----------------------------------------------------------]]
|
||||
function GetStored( name )
|
||||
return SEntList[ name ]
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetList( string )
|
||||
Desc: Get a list of all the registered SENTs
|
||||
-----------------------------------------------------------]]
|
||||
function GetList()
|
||||
local result = {}
|
||||
|
||||
for k,v in pairs( SEntList ) do
|
||||
result[ k ] = v
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function GetSpawnable()
|
||||
|
||||
local result = {}
|
||||
|
||||
for k, v in pairs( SEntList ) do
|
||||
|
||||
local tab = v.t
|
||||
|
||||
if ( tab.Spawnable ) then
|
||||
table.insert( result, tab )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
function Alias( From, To )
|
||||
|
||||
Aliases[ From ] = To
|
||||
|
||||
end
|
||||
|
||||
function GetMember( entity_name, membername )
|
||||
|
||||
if ( !entity_name ) then return end
|
||||
|
||||
local ent = SEntList[ entity_name ]
|
||||
|
||||
if ( !ent ) then return end
|
||||
|
||||
local member = ent.t[ membername ]
|
||||
if ( member != nil ) then return member end
|
||||
|
||||
-- If our base is the same as us - don't infinite loop!
|
||||
if ( entity_name == ent.Base ) then return end
|
||||
|
||||
return GetMember( ent.Base, membername )
|
||||
|
||||
end
|
||||
59
lua/includes/modules/search.lua
Normal file
59
lua/includes/modules/search.lua
Normal file
@@ -0,0 +1,59 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "search", package.seeall )
|
||||
|
||||
local Providers = {}
|
||||
|
||||
function AddProvider( func, id )
|
||||
|
||||
local prov = {
|
||||
func = func,
|
||||
}
|
||||
|
||||
if ( id ) then
|
||||
Providers[ id ] = prov
|
||||
else
|
||||
table.insert( Providers, prov )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function GetResults( str, types, maxResults )
|
||||
|
||||
if ( !maxResults || maxResults < 1 ) then maxResults = 1024 end
|
||||
|
||||
local str = str:lower()
|
||||
if ( str == "" ) then return {} end
|
||||
|
||||
local results = {}
|
||||
|
||||
for k, v in pairs( Providers ) do
|
||||
if ( isstring( types ) ) then
|
||||
if ( types != k ) then continue end
|
||||
elseif ( istable( types ) ) then
|
||||
if ( !table.HasValue( types, k ) ) then continue end
|
||||
end
|
||||
|
||||
local tbl = v.func( str )
|
||||
for _, e in pairs( tbl ) do
|
||||
table.insert( results, e )
|
||||
end
|
||||
|
||||
if ( #results >= maxResults ) then break end
|
||||
|
||||
end
|
||||
|
||||
-- Todo. Sort, weighted?
|
||||
|
||||
return results
|
||||
|
||||
end
|
||||
98
lua/includes/modules/sound_vj_track.lua
Normal file
98
lua/includes/modules/sound_vj_track.lua
Normal file
@@ -0,0 +1,98 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
/*--------------------------------------------------
|
||||
=============== VJ Theme Soundtrack Module ===============
|
||||
*** Copyright (c) 2012-2023 by DrVrej, All rights reserved. ***
|
||||
No parts of this code or any of its contents may be reproduced, copied, modified or adapted,
|
||||
without the prior written consent of the author, unless otherwise indicated for stand-alone materials.
|
||||
INFO: Thanks to Orion for creating the original code
|
||||
--------------------------------------------------*/
|
||||
//AddCSLuaFile()
|
||||
module("sound_vj_track",package.seeall)
|
||||
//if SERVER then return end
|
||||
//print("The Module is running!")
|
||||
//if CLIENT then
|
||||
local MetatableMusic = {}
|
||||
MetatableMusic.__index = MetatableMusic
|
||||
MUSIC_CHANNEL_INDEX = {[1] = {CurTrack = NULL, CurTrackName = "!"}}
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
AddChannel = function()
|
||||
MUSIC_CHANNEL_INDEX[#MUSIC_CHANNEL_INDEX+1] = {CurTrack = NULL, CurTrackName = "!"}
|
||||
return MUSIC_CHANNEL_INDEX[#MUSIC_CHANNEL_INDEX+1]
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
GetChannel = function(index)
|
||||
return MUSIC_CHANNEL_INDEX[index] or Error("WARNING! VJ SOUNDTRACK CHANNEL DOES NOT EXIST: "..index) or Error("INVALID VJ SOUNDTRACK INPUT!")
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Add = function(name,path,dur)
|
||||
MetatableMusic[name] = {Path = path, Duration = dur}
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Get = function(name)
|
||||
return MetatableMusic[name]
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
GetCurrentTrack = function(chn)
|
||||
return GetChannel(chn).CurTrack
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
SetCurrentTrack = function(chn,csp,name)
|
||||
GetChannel(chn).CurTrack = csp
|
||||
GetChannel(chn).CurTrackName = name
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
GetCurrentTrackName = function(chn)
|
||||
return GetChannel(chn).CurTrackName
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Play = function(chn,sound_vj_track,soundlevel)
|
||||
if not sound_vj_track then return print("VJ Soundtrack wasn't able to find any sound to play!") end
|
||||
if istable(sound_vj_track) then
|
||||
if #sound_vj_track < 1 then return print("VJ Soundtrack didn't play any track since the table is empty!") end -- If the table is empty then end it
|
||||
sound_vj_track = sound_vj_track[math.random(1,#sound_vj_track)]
|
||||
end
|
||||
local CSoundPatch = CreateSound(LocalPlayer(),Get(sound_vj_track).Path)
|
||||
CSoundPatch:Play()
|
||||
CSoundPatch:SetSoundLevel(soundlevel) -- Play the track globally!
|
||||
if (GetCurrentTrack(chn) ~= NULL) && IsPlaying(chn) then
|
||||
//Stop(chn)
|
||||
end
|
||||
SetCurrentTrack(chn,CSoundPatch,sound_vj_track)
|
||||
GetChannel(chn).bFaded = false
|
||||
print("Current VJ Soundtrack track is "..sound_vj_track.." in channel "..chn)
|
||||
//print("Current VJ Soundtrack track in channel "..chn.." = "..sound_vj_track)
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
IsPlaying = function(chn)
|
||||
return (GetCurrentTrack(chn) ~= NULL) && GetCurrentTrack(chn):IsPlaying() && GetChannel(chn).bFaded == false
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Stop = function(chn)
|
||||
if IsPlaying(chn) then
|
||||
GetCurrentTrack(chn):Stop()
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
FadeOut = function(chn,tm)
|
||||
local tm = tm or 2 -- If no number is set then just fadeout in 2 seconds
|
||||
if IsPlaying(chn) then
|
||||
GetCurrentTrack(chn):FadeOut(tm)
|
||||
GetChannel(chn).bFaded = true
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||
Duration = function(chn)
|
||||
if (not chn) or (chn == nil) or (chn == NULL) then return end
|
||||
if GetCurrentTrackName(chn) == "!" then return end
|
||||
return MetatableMusic[GetCurrentTrackName(chn)].Duration
|
||||
end
|
||||
//end
|
||||
316
lua/includes/modules/spawnmenu.lua
Normal file
316
lua/includes/modules/spawnmenu.lua
Normal file
@@ -0,0 +1,316 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local spawnmenu_engine = spawnmenu
|
||||
|
||||
module( "spawnmenu", package.seeall )
|
||||
|
||||
local g_ToolMenu = {}
|
||||
local CreationMenus = {}
|
||||
local PropTable = {}
|
||||
local PropTableCustom = {}
|
||||
|
||||
local ActiveToolPanel = nil
|
||||
local ActiveSpawnlistID = 1000
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Tool Tabs
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
function SetActiveControlPanel( pnl )
|
||||
ActiveToolPanel = pnl
|
||||
end
|
||||
|
||||
function ActiveControlPanel()
|
||||
return ActiveToolPanel
|
||||
end
|
||||
|
||||
function GetTools()
|
||||
return g_ToolMenu
|
||||
end
|
||||
|
||||
function GetToolMenu( name, label, icon )
|
||||
|
||||
--
|
||||
-- This is a dirty hack so that Main stays at the front of the tabs.
|
||||
--
|
||||
if ( name == "Main" ) then name = "AAAAAAA_Main" end
|
||||
|
||||
label = label or name
|
||||
icon = icon or "icon16/wrench.png"
|
||||
|
||||
for k, v in ipairs( g_ToolMenu ) do
|
||||
|
||||
if ( v.Name == name ) then return v.Items end
|
||||
|
||||
end
|
||||
|
||||
local NewMenu = { Name = name, Items = {}, Label = label, Icon = icon }
|
||||
table.insert( g_ToolMenu, NewMenu )
|
||||
|
||||
--
|
||||
-- Order the tabs by NAME
|
||||
--
|
||||
table.SortByMember( g_ToolMenu, "Name", true )
|
||||
|
||||
return NewMenu.Items
|
||||
|
||||
end
|
||||
|
||||
function ClearToolMenus()
|
||||
|
||||
g_ToolMenu = {}
|
||||
|
||||
end
|
||||
|
||||
function AddToolTab( strName, strLabel, Icon )
|
||||
|
||||
GetToolMenu( strName, strLabel, Icon )
|
||||
|
||||
end
|
||||
|
||||
function SwitchToolTab( id )
|
||||
|
||||
local Tab = g_SpawnMenu:GetToolMenu():GetToolPanel( id )
|
||||
if ( !IsValid( Tab ) or !IsValid( Tab.PropertySheetTab ) ) then return end
|
||||
|
||||
Tab.PropertySheetTab:DoClick()
|
||||
|
||||
end
|
||||
|
||||
function ActivateToolPanel( tabId, ctrlPnl, toolName )
|
||||
|
||||
local Tab = g_SpawnMenu:GetToolMenu():GetToolPanel( tabId )
|
||||
if ( !IsValid( Tab ) ) then return end
|
||||
|
||||
spawnmenu.SetActiveControlPanel( ctrlPnl )
|
||||
|
||||
if ( ctrlPnl ) then
|
||||
Tab:SetActive( ctrlPnl )
|
||||
end
|
||||
|
||||
SwitchToolTab( tabId )
|
||||
|
||||
if ( toolName && Tab.SetActiveToolText ) then
|
||||
Tab:SetActiveToolText( toolName )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- While technically tool class names CAN be duplicate, it normally should never happen.
|
||||
function ActivateTool( strName, noCommand )
|
||||
|
||||
-- I really don't like this triple loop
|
||||
for tab, v in ipairs( g_ToolMenu ) do
|
||||
for _, items in pairs( v.Items ) do
|
||||
for _, item in pairs( items ) do
|
||||
|
||||
if ( istable( item ) && item.ItemName && item.ItemName == strName ) then
|
||||
|
||||
if ( !noCommand && item.Command && string.len( item.Command ) > 1 ) then
|
||||
RunConsoleCommand( unpack( string.Explode( " ", item.Command ) ) )
|
||||
end
|
||||
|
||||
local cp = controlpanel.Get( strName )
|
||||
if ( !cp:GetInitialized() ) then
|
||||
cp:FillViaTable( { Text = item.Text, ControlPanelBuildFunction = item.CPanelFunction } )
|
||||
end
|
||||
|
||||
ActivateToolPanel( tab, cp, strName )
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function AddToolCategory( tab, RealName, PrintName )
|
||||
|
||||
local Menu = GetToolMenu( tab )
|
||||
|
||||
-- Does this category already exist?
|
||||
for k, v in ipairs( Menu ) do
|
||||
|
||||
if ( v.Text == PrintName ) then return end
|
||||
if ( v.ItemName == RealName ) then return end
|
||||
|
||||
end
|
||||
|
||||
table.insert( Menu, { Text = PrintName, ItemName = RealName } )
|
||||
|
||||
end
|
||||
|
||||
function AddToolMenuOption( tab, category, itemname, text, command, controls, cpanelfunction, TheTable )
|
||||
|
||||
local Menu = GetToolMenu( tab )
|
||||
local CategoryTable = nil
|
||||
|
||||
for k, v in ipairs( Menu ) do
|
||||
if ( v.ItemName && v.ItemName == category ) then CategoryTable = v break end
|
||||
end
|
||||
|
||||
-- No table found.. lets create one
|
||||
if ( !CategoryTable ) then
|
||||
CategoryTable = { Text = "#" .. category, ItemName = category }
|
||||
table.insert( Menu, CategoryTable )
|
||||
end
|
||||
|
||||
TheTable = TheTable or {}
|
||||
|
||||
TheTable.ItemName = itemname
|
||||
TheTable.Text = text
|
||||
TheTable.Command = command
|
||||
TheTable.Controls = controls
|
||||
TheTable.CPanelFunction = cpanelfunction
|
||||
|
||||
table.insert( CategoryTable, TheTable )
|
||||
|
||||
-- Keep the table sorted
|
||||
table.SortByMember( CategoryTable, "Text", true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Creation Tabs
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function AddCreationTab( strName, pFunction, pMaterial, iOrder, strTooltip )
|
||||
|
||||
iOrder = iOrder or 1000
|
||||
|
||||
pMaterial = pMaterial or "icon16/exclamation.png"
|
||||
|
||||
CreationMenus[ strName ] = { Function = pFunction, Icon = pMaterial, Order = iOrder, Tooltip = strTooltip }
|
||||
|
||||
end
|
||||
|
||||
function GetCreationTabs()
|
||||
|
||||
return CreationMenus
|
||||
|
||||
end
|
||||
|
||||
function SwitchCreationTab( id )
|
||||
|
||||
local tab = g_SpawnMenu:GetCreationMenu():GetCreationTab( id )
|
||||
if ( !tab or !IsValid( tab.Tab ) ) then return end
|
||||
|
||||
tab.Tab:DoClick()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
|
||||
Spawn lists
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function GetPropTable()
|
||||
|
||||
return PropTable
|
||||
|
||||
end
|
||||
|
||||
function GetCustomPropTable()
|
||||
|
||||
return PropTableCustom
|
||||
|
||||
end
|
||||
|
||||
function AddPropCategory( strFilename, strName, tabContents, icon, id, parentid, needsapp )
|
||||
|
||||
PropTableCustom[ strFilename ] = {
|
||||
name = strName,
|
||||
contents = tabContents,
|
||||
icon = icon,
|
||||
id = id or ActiveSpawnlistID,
|
||||
parentid = parentid or 0,
|
||||
needsapp = needsapp
|
||||
}
|
||||
|
||||
if ( !id ) then ActiveSpawnlistID = ActiveSpawnlistID + 1 end
|
||||
|
||||
end
|
||||
|
||||
-- Populate the spawnmenu from the text files (engine)
|
||||
function PopulateFromEngineTextFiles()
|
||||
|
||||
-- Reset the already loaded prop list before loading them again.
|
||||
-- This caused the spawnlists to duplicate into crazy trees when spawnmenu_reload'ing after saving edited spawnlists
|
||||
PropTable = {}
|
||||
|
||||
spawnmenu_engine.PopulateFromTextFiles( function( strFilename, strName, tabContents, icon, id, parentid, needsapp )
|
||||
PropTable[ strFilename ] = {
|
||||
name = strName,
|
||||
contents = tabContents,
|
||||
icon = icon,
|
||||
id = id,
|
||||
parentid = parentid or 0,
|
||||
needsapp = needsapp
|
||||
}
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
-- Save the spawnfists to text files (engine)
|
||||
function DoSaveToTextFiles( props )
|
||||
|
||||
spawnmenu_engine.SaveToTextFiles( props )
|
||||
|
||||
end
|
||||
|
||||
--[[
|
||||
|
||||
Content Providers
|
||||
|
||||
Functions that populate the spawnmenu from the spawnmenu txt files.
|
||||
|
||||
function MyFunction( ContentPanel, ObjectTable )
|
||||
|
||||
local myspawnicon = CreateSpawnicon( ObjectTable.model )
|
||||
ContentPanel:AddItem( myspawnicon )
|
||||
|
||||
end
|
||||
|
||||
spawnmenu.AddContentType( "model", MyFunction )
|
||||
|
||||
--]]
|
||||
|
||||
local cp = {}
|
||||
|
||||
function AddContentType( name, func )
|
||||
cp[ name ] = func
|
||||
end
|
||||
|
||||
function GetContentType( name )
|
||||
|
||||
if ( !cp[ name ] ) then
|
||||
|
||||
cp[ name ] = function() end
|
||||
Msg( "spawnmenu.GetContentType( ", name, " ) - not found!\n" )
|
||||
|
||||
end
|
||||
|
||||
return cp[ name ]
|
||||
end
|
||||
|
||||
function CreateContentIcon( type, parent, tbl )
|
||||
|
||||
local ctrlpnl = GetContentType( type )
|
||||
if ( ctrlpnl ) then return ctrlpnl( parent, tbl ) end
|
||||
|
||||
end
|
||||
49
lua/includes/modules/sui.lua
Normal file
49
lua/includes/modules/sui.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
if sui then return end
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
sui = {}
|
||||
|
||||
do
|
||||
local wspace_chs = {} -- whitespace characters except a normal space " "
|
||||
for k, v in ipairs({0x0c, 0x0a, 0x0d, 0x09, 0x0b}) do
|
||||
wspace_chs[string.char(v)] = true
|
||||
end
|
||||
sui.wspace_chs = wspace_chs
|
||||
|
||||
local cntrl_chs = {string.char(0x7f)} -- control characters
|
||||
for i = 0x00, 0x1f do
|
||||
cntrl_chs[string.char(i)] = true
|
||||
end
|
||||
sui.cntrl_chs = cntrl_chs
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile("sui/libs/tdlib/cl_tdlib.lua")
|
||||
AddCSLuaFile("sui/libs/bshadows.lua")
|
||||
AddCSLuaFile("sui/libs/gif_loader.lua")
|
||||
AddCSLuaFile("sui/libs/png_encoder.lua")
|
||||
AddCSLuaFile("sui/libs/types.lua")
|
||||
AddCSLuaFile("sui/cl_base.lua")
|
||||
else
|
||||
include("sui/libs/tdlib/cl_tdlib.lua")
|
||||
include("sui/libs/bshadows.lua")
|
||||
include("sui/libs/types.lua")
|
||||
include("sui/cl_base.lua")
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
for _, f in ipairs(file.Find("sui/vgui/*.lua", "LUA")) do
|
||||
AddCSLuaFile("sui/vgui/" .. f)
|
||||
end
|
||||
end
|
||||
221
lua/includes/modules/team.lua
Normal file
221
lua/includes/modules/team.lua
Normal file
@@ -0,0 +1,221 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
module( "team", package.seeall )
|
||||
|
||||
local TeamInfo = {}
|
||||
local DefaultColor = Color(255, 255, 100, 255)
|
||||
|
||||
TeamInfo[TEAM_CONNECTING] = { Name = "Joining/Connecting", Color = DefaultColor, Score = 0, Joinable = false }
|
||||
TeamInfo[TEAM_UNASSIGNED] = { Name = "Unassigned", Color = DefaultColor, Score = 0, Joinable = false }
|
||||
TeamInfo[TEAM_SPECTATOR] = { Name = "Spectator", Color = DefaultColor, Score = 0, Joinable = true }
|
||||
|
||||
--[[------------------------------------------------------------
|
||||
|
||||
Call this to set up your team. It should be called in
|
||||
a shared file. This system assumes that your teams are
|
||||
static. If you want to have dynamic teams you need to
|
||||
code this yourself.
|
||||
|
||||
id should be a number. It's best to do something like
|
||||
|
||||
TEAM_TERRORISTS = 2
|
||||
|
||||
at the top of your code somewhere so you can reference
|
||||
teams via a variable rather than a number.
|
||||
|
||||
--------------------------------------------------------------]]
|
||||
function SetUp( id, name, color, joinable )
|
||||
|
||||
if ( joinable == nil ) then joinable = true end
|
||||
|
||||
TeamInfo[id] = { Name = name, Color = color, Score = 0, Joinable = joinable }
|
||||
|
||||
end
|
||||
|
||||
|
||||
function GetAllTeams()
|
||||
|
||||
return TeamInfo -- copyof?
|
||||
|
||||
end
|
||||
|
||||
function Valid( id )
|
||||
|
||||
if ( !TeamInfo[id] ) then return false end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function Joinable( id )
|
||||
|
||||
if ( !TeamInfo[id] ) then return false end
|
||||
return TeamInfo[id].Joinable
|
||||
|
||||
end
|
||||
|
||||
function GetSpawnPoint( id )
|
||||
|
||||
if ( !TeamInfo[id] ) then return end
|
||||
return TeamInfo[id].SpawnPointTable
|
||||
|
||||
end
|
||||
|
||||
function GetSpawnPoints( id )
|
||||
|
||||
if ( IsTableOfEntitiesValid( TeamInfo[id].SpawnPoints ) ) then return TeamInfo[id].SpawnPoints end
|
||||
|
||||
local SpawnPointTable = team.GetSpawnPoint( id )
|
||||
if ( !SpawnPointTable ) then return end
|
||||
|
||||
TeamInfo[id].SpawnPoints = {}
|
||||
|
||||
for k, entname in pairs( SpawnPointTable ) do
|
||||
|
||||
TeamInfo[id].SpawnPoints = table.Add( TeamInfo[id].SpawnPoints, ents.FindByClass( entname ) )
|
||||
|
||||
end
|
||||
|
||||
return TeamInfo[id].SpawnPoints
|
||||
|
||||
end
|
||||
|
||||
function SetSpawnPoint( id, ent_name )
|
||||
|
||||
if ( !TeamInfo[id] ) then return end
|
||||
if ( !istable( ent_name ) ) then ent_name = {ent_name} end
|
||||
|
||||
TeamInfo[id].SpawnPointTable = ent_name
|
||||
|
||||
end
|
||||
|
||||
function SetClass( id, classtable )
|
||||
|
||||
if ( !TeamInfo[id] ) then return end
|
||||
if ( !istable( classtable ) ) then classtable = {classtable} end
|
||||
|
||||
TeamInfo[id].SelectableClasses = classtable
|
||||
|
||||
end
|
||||
|
||||
function GetClass( id )
|
||||
|
||||
if ( !TeamInfo[id] ) then return end
|
||||
return TeamInfo[id].SelectableClasses
|
||||
|
||||
end
|
||||
|
||||
function TotalDeaths(index)
|
||||
|
||||
local score = 0
|
||||
for id,pl in ipairs( player.GetAll() ) do
|
||||
if (pl:Team() == index) then
|
||||
score = score + pl:Deaths()
|
||||
end
|
||||
end
|
||||
return score
|
||||
|
||||
end
|
||||
|
||||
function TotalFrags(index)
|
||||
|
||||
local score = 0
|
||||
for id,pl in ipairs( player.GetAll() ) do
|
||||
if (pl:Team() == index) then
|
||||
score = score + pl:Frags()
|
||||
end
|
||||
end
|
||||
return score
|
||||
|
||||
end
|
||||
|
||||
function NumPlayers(index)
|
||||
|
||||
return #GetPlayers(index)
|
||||
|
||||
end
|
||||
|
||||
function GetPlayers(index)
|
||||
|
||||
local TeamPlayers = {}
|
||||
|
||||
for id,pl in ipairs( player.GetAll() ) do
|
||||
if (IsValid(pl) and pl:Team() == index) then
|
||||
table.insert(TeamPlayers, pl)
|
||||
end
|
||||
end
|
||||
|
||||
return TeamPlayers
|
||||
|
||||
end
|
||||
|
||||
function GetScore(index)
|
||||
|
||||
return GetGlobalInt( "Team."..tostring(index)..".Score", 0 )
|
||||
|
||||
end
|
||||
|
||||
function GetName( index )
|
||||
|
||||
if (!TeamInfo[index]) then return "" end
|
||||
return TeamInfo[index].Name
|
||||
|
||||
end
|
||||
|
||||
function SetColor( index, color )
|
||||
|
||||
if ( !TeamInfo[ index ] ) then return false; end
|
||||
TeamInfo[ index ].Color = color
|
||||
|
||||
return color
|
||||
|
||||
end
|
||||
|
||||
function GetColor( index )
|
||||
|
||||
if (!TeamInfo[index]) then return DefaultColor end
|
||||
return table.Copy( TeamInfo[index].Color )
|
||||
|
||||
end
|
||||
|
||||
function SetScore(index, score)
|
||||
|
||||
return SetGlobalInt( "Team."..tostring(index)..".Score", score )
|
||||
|
||||
end
|
||||
|
||||
function AddScore(index, score)
|
||||
|
||||
SetScore( index, GetScore( index ) + score )
|
||||
|
||||
end
|
||||
|
||||
function BestAutoJoinTeam()
|
||||
|
||||
local SmallestTeam = TEAM_UNASSIGNED
|
||||
local SmallestPlayers = 1000
|
||||
|
||||
for id, tm in pairs( team.GetAllTeams() ) do
|
||||
|
||||
if ( id != TEAM_SPECTATOR && id != TEAM_UNASSIGNED && id != TEAM_CONNECTING && tm.Joinable ) then
|
||||
|
||||
local PlayerCount = team.NumPlayers( id )
|
||||
if ( PlayerCount < SmallestPlayers || (PlayerCount == SmallestPlayers && id < SmallestTeam ) ) then
|
||||
SmallestPlayers = PlayerCount
|
||||
SmallestTeam = id
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return SmallestTeam
|
||||
|
||||
end
|
||||
519
lua/includes/modules/undo.lua
Normal file
519
lua/includes/modules/undo.lua
Normal file
@@ -0,0 +1,519 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "undo", package.seeall )
|
||||
|
||||
-- undo.Create("Wheel")
|
||||
-- undo.AddEntity( axis )
|
||||
-- undo.AddEntity( constraint )
|
||||
-- undo.SetPlayer( self.Owner )
|
||||
-- undo.Finish()
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
local ClientUndos = {}
|
||||
local bIsDirty = true
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetTable
|
||||
Returns the undo table for whatever reason
|
||||
-----------------------------------------------------------]]
|
||||
function GetTable()
|
||||
return ClientUndos
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
UpdateUI
|
||||
Actually updates the UI. Removes old controls and
|
||||
re-creates them using the new data.
|
||||
-----------------------------------------------------------]]
|
||||
local function UpdateUI()
|
||||
|
||||
local Panel = controlpanel.Get( "Undo" )
|
||||
if ( !IsValid( Panel ) ) then return end
|
||||
|
||||
Panel:Clear()
|
||||
Panel:AddControl( "Header", { Description = "#spawnmenu.utilities.undo.help" } )
|
||||
|
||||
local ComboBox = Panel:ListBox()
|
||||
ComboBox:SetTall( 500 )
|
||||
|
||||
local Limit = 100
|
||||
local Count = 0
|
||||
for k, v in ipairs( ClientUndos ) do
|
||||
|
||||
local Item = ComboBox:AddItem( tostring( v.Name ) )
|
||||
Item.DoClick = function() RunConsoleCommand( "gmod_undonum", tostring( v.Key ) ) end
|
||||
|
||||
Count = Count + 1
|
||||
if ( Count > Limit ) then break end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
AddUndo
|
||||
Called from server. Adds a new undo to our UI
|
||||
-----------------------------------------------------------]]
|
||||
net.Receive( "Undo_AddUndo", function()
|
||||
|
||||
local k = net.ReadInt( 16 )
|
||||
local v = net.ReadString()
|
||||
|
||||
table.insert( ClientUndos, 1, { Key = k, Name = v } )
|
||||
|
||||
MakeUIDirty()
|
||||
|
||||
end )
|
||||
|
||||
-- Called from server, fires GM:OnUndo
|
||||
net.Receive( "Undo_FireUndo", function()
|
||||
|
||||
local name = net.ReadString()
|
||||
local hasCustomText = net.ReadBool()
|
||||
local customtext
|
||||
if ( hasCustomText ) then
|
||||
customtext = net.ReadString()
|
||||
end
|
||||
|
||||
hook.Run( "OnUndo", name, customtext )
|
||||
|
||||
end )
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Undone
|
||||
Called from server. Notifies us that one of our undos
|
||||
has been undone or made redundant. We act by updating
|
||||
out data (We wait until the UI is viewed until updating)
|
||||
-----------------------------------------------------------]]
|
||||
local function Undone()
|
||||
|
||||
local key = net.ReadInt( 16 )
|
||||
|
||||
local NewUndo = {}
|
||||
local i = 1
|
||||
for k, v in ipairs( ClientUndos ) do
|
||||
|
||||
if ( v.Key != key ) then
|
||||
NewUndo [ i ] = v
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
ClientUndos = NewUndo
|
||||
NewUndo = nil
|
||||
|
||||
MakeUIDirty()
|
||||
|
||||
end
|
||||
net.Receive( "Undo_Undone", Undone )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
MakeUIDirty
|
||||
Makes the UI dirty - it will re-create the controls
|
||||
the next time it is viewed.
|
||||
-----------------------------------------------------------]]
|
||||
function MakeUIDirty()
|
||||
|
||||
bIsDirty = true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
CPanelPaint
|
||||
Called when the inner panel of the undo CPanel is painted
|
||||
We hook onto this to determine when the panel is viewed.
|
||||
When it's viewed we update the UI if it's marked as dirty
|
||||
-----------------------------------------------------------]]
|
||||
local function CPanelUpdate( panel )
|
||||
|
||||
-- This is kind of a shitty way of doing it - but we only want
|
||||
-- to update the UI when it's visible.
|
||||
if ( bIsDirty ) then
|
||||
|
||||
-- Doing this in a timer so it calls it in a sensible place
|
||||
-- Calling in the paint function could cause all kinds of problems
|
||||
-- It's a hack but hey welcome to GMod!
|
||||
timer.Simple( 0, UpdateUI )
|
||||
bIsDirty = false
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
SetupUI
|
||||
Adds a hook (CPanelPaint) to the control panel paint
|
||||
function so we can determine when it is being drawn.
|
||||
-----------------------------------------------------------]]
|
||||
function SetupUI()
|
||||
|
||||
local UndoPanel = controlpanel.Get( "Undo" )
|
||||
if ( !IsValid( UndoPanel ) ) then return end
|
||||
|
||||
-- Mark as dirty please
|
||||
MakeUIDirty()
|
||||
|
||||
-- Panels only think when they're visible
|
||||
UndoPanel.Think = CPanelUpdate
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PostReloadToolsMenu", "BuildUndoUI", SetupUI )
|
||||
|
||||
end
|
||||
|
||||
|
||||
if ( !SERVER ) then return end
|
||||
|
||||
local PlayerUndo = {}
|
||||
-- PlayerUndo
|
||||
-- - Player UniqueID
|
||||
-- - Undo Table
|
||||
-- - Name
|
||||
-- - Entities (table of ents)
|
||||
-- - Owner (player)
|
||||
|
||||
local Current_Undo = nil
|
||||
|
||||
util.AddNetworkString( "Undo_Undone" )
|
||||
util.AddNetworkString( "Undo_AddUndo" )
|
||||
util.AddNetworkString( "Undo_FireUndo" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetTable
|
||||
Returns the undo table for whatever reason
|
||||
-----------------------------------------------------------]]
|
||||
function GetTable()
|
||||
return PlayerUndo
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetTable
|
||||
Save/Restore the undo tables
|
||||
-----------------------------------------------------------]]
|
||||
local function Save( save )
|
||||
|
||||
saverestore.WriteTable( PlayerUndo, save )
|
||||
|
||||
end
|
||||
|
||||
local function Restore( restore )
|
||||
|
||||
PlayerUndo = saverestore.ReadTable( restore )
|
||||
|
||||
end
|
||||
|
||||
saverestore.AddSaveHook( "UndoTable", Save )
|
||||
saverestore.AddRestoreHook( "UndoTable", Restore )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Start a new undo
|
||||
-----------------------------------------------------------]]
|
||||
function Create( text )
|
||||
|
||||
Current_Undo = {}
|
||||
Current_Undo.Name = text
|
||||
Current_Undo.Entities = {}
|
||||
Current_Undo.Owner = nil
|
||||
Current_Undo.Functions = {}
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Adds an entity to this undo (The entity is removed on undo)
|
||||
-----------------------------------------------------------]]
|
||||
function SetCustomUndoText( CustomUndoText )
|
||||
|
||||
if ( !Current_Undo ) then return end
|
||||
|
||||
Current_Undo.CustomUndoText = CustomUndoText
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Adds an entity to this undo (The entity is removed on undo)
|
||||
-----------------------------------------------------------]]
|
||||
function AddEntity( ent )
|
||||
|
||||
if ( !Current_Undo ) then return end
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
table.insert( Current_Undo.Entities, ent )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Add a function to call to this undo
|
||||
-----------------------------------------------------------]]
|
||||
function AddFunction( func, ... )
|
||||
|
||||
if ( !Current_Undo ) then return end
|
||||
if ( !func ) then return end
|
||||
|
||||
table.insert( Current_Undo.Functions, { func, {...} } )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Replace Entity
|
||||
-----------------------------------------------------------]]
|
||||
function ReplaceEntity( from, to )
|
||||
|
||||
local ActionTaken = false
|
||||
|
||||
for _, PlayerTable in pairs( PlayerUndo ) do
|
||||
for _, UndoTable in pairs( PlayerTable ) do
|
||||
if ( UndoTable.Entities ) then
|
||||
|
||||
for key, ent in pairs( UndoTable.Entities ) do
|
||||
if ( ent == from ) then
|
||||
UndoTable.Entities[ key ] = to
|
||||
ActionTaken = true
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return ActionTaken
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Sets who's undo this is
|
||||
-----------------------------------------------------------]]
|
||||
function SetPlayer( ply )
|
||||
|
||||
if ( !Current_Undo ) then return end
|
||||
if ( !IsValid( ply ) ) then return end
|
||||
|
||||
Current_Undo.Owner = ply
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
SendUndoneMessage
|
||||
Sends a message to notify the client that one of their
|
||||
undos has been removed. They can then update their GUI.
|
||||
-----------------------------------------------------------]]
|
||||
local function SendUndoneMessage( ent, id, ply )
|
||||
|
||||
if ( !IsValid( ply ) ) then return end
|
||||
|
||||
-- For further optimization we could queue up the ids and send them
|
||||
-- in one batch every 0.5 seconds or something along those lines.
|
||||
|
||||
net.Start( "Undo_Undone" )
|
||||
net.WriteInt( id, 16 )
|
||||
net.Send( ply )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Checks whether an undo is allowed to be created
|
||||
-----------------------------------------------------------]]
|
||||
local function Can_CreateUndo( undo )
|
||||
|
||||
local call = hook.Run( "CanCreateUndo", undo.Owner, undo )
|
||||
|
||||
return call == true or call == nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Finish
|
||||
-----------------------------------------------------------]]
|
||||
function Finish( NiceText )
|
||||
|
||||
if ( !Current_Undo ) then return end
|
||||
|
||||
-- Do not add undos that have no owner or anything to undo
|
||||
if ( !IsValid( Current_Undo.Owner ) or ( table.IsEmpty( Current_Undo.Entities ) && table.IsEmpty( Current_Undo.Functions ) ) or !Can_CreateUndo( Current_Undo ) ) then
|
||||
Current_Undo = nil
|
||||
return false
|
||||
end
|
||||
|
||||
local index = Current_Undo.Owner:UniqueID()
|
||||
PlayerUndo[ index ] = PlayerUndo[ index ] or {}
|
||||
|
||||
Current_Undo.NiceText = NiceText or Current_Undo.Name
|
||||
|
||||
local id = table.insert( PlayerUndo[ index ], Current_Undo )
|
||||
|
||||
net.Start( "Undo_AddUndo" )
|
||||
net.WriteInt( id, 16 )
|
||||
net.WriteString( Current_Undo.NiceText )
|
||||
net.Send( Current_Undo.Owner )
|
||||
|
||||
-- Have one of the entities in the undo tell us when it gets undone.
|
||||
if ( IsValid( Current_Undo.Entities[ 1 ] ) ) then
|
||||
|
||||
local ent = Current_Undo.Entities[ 1 ]
|
||||
ent:CallOnRemove( "undo" .. id, SendUndoneMessage, id, Current_Undo.Owner )
|
||||
|
||||
end
|
||||
|
||||
Current_Undo = nil
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Undos an undo
|
||||
-----------------------------------------------------------]]
|
||||
function Do_Undo( undo )
|
||||
|
||||
if ( !undo ) then return false end
|
||||
|
||||
if ( hook.Run( "PreUndo", undo ) == false ) then return end
|
||||
|
||||
local count = 0
|
||||
|
||||
-- Call each function
|
||||
if ( undo.Functions ) then
|
||||
for index, func in pairs( undo.Functions ) do
|
||||
|
||||
local success = func[ 1 ]( undo, unpack( func[ 2 ] ) )
|
||||
if ( success != false ) then
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
-- Remove each entity in this undo
|
||||
if ( undo.Entities ) then
|
||||
for index, entity in pairs( undo.Entities ) do
|
||||
|
||||
if ( IsValid( entity ) ) then
|
||||
entity:Remove()
|
||||
count = count + 1
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
if ( count > 0 ) then
|
||||
net.Start( "Undo_FireUndo" )
|
||||
net.WriteString( undo.Name )
|
||||
net.WriteBool( undo.CustomUndoText != nil )
|
||||
if ( undo.CustomUndoText != nil ) then
|
||||
net.WriteString( undo.CustomUndoText )
|
||||
end
|
||||
net.Send( undo.Owner )
|
||||
end
|
||||
|
||||
hook.Run( "PostUndo", undo, count )
|
||||
|
||||
return count
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Checks whether a player is allowed to undo
|
||||
-----------------------------------------------------------]]
|
||||
local function Can_Undo( ply, undo )
|
||||
|
||||
local call = hook.Run( "CanUndo", ply, undo )
|
||||
|
||||
return call == true or call == nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Console command
|
||||
-----------------------------------------------------------]]
|
||||
local function CC_UndoLast( pl, command, args )
|
||||
|
||||
local index = pl:UniqueID()
|
||||
PlayerUndo[ index ] = PlayerUndo[ index ] or {}
|
||||
|
||||
local last = nil
|
||||
local lastk = nil
|
||||
|
||||
for k, v in pairs( PlayerUndo[ index ] ) do
|
||||
|
||||
lastk = k
|
||||
last = v
|
||||
|
||||
end
|
||||
|
||||
-- No undos
|
||||
if ( !last ) then return end
|
||||
|
||||
-- This is quite messy, but if the player rejoined the server
|
||||
-- 'Owner' might no longer be a valid entity. So replace the Owner
|
||||
-- with the player that is doing the undoing
|
||||
last.Owner = pl
|
||||
|
||||
if ( !Can_Undo( pl, last ) ) then return end
|
||||
|
||||
local count = Do_Undo( last )
|
||||
|
||||
net.Start( "Undo_Undone" )
|
||||
net.WriteInt( lastk, 16 )
|
||||
net.Send( pl )
|
||||
|
||||
PlayerUndo[ index ][ lastk ] = nil
|
||||
|
||||
-- If our last undo object is already deleted then compact
|
||||
-- the undos until we hit one that does something
|
||||
if ( count == 0 ) then
|
||||
CC_UndoLast( pl )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Console command
|
||||
-----------------------------------------------------------]]
|
||||
local function CC_UndoNum( ply, command, args )
|
||||
|
||||
if ( !args[ 1 ] ) then return end
|
||||
|
||||
local index = ply:UniqueID()
|
||||
PlayerUndo[ index ] = PlayerUndo[ index ] or {}
|
||||
|
||||
local UndoNum = tonumber( args[ 1 ] )
|
||||
if ( !UndoNum ) then return end
|
||||
|
||||
local TheUndo = PlayerUndo[ index ][ UndoNum ]
|
||||
if ( !TheUndo ) then return end
|
||||
|
||||
-- Do the same as above
|
||||
TheUndo.Owner = ply
|
||||
|
||||
if ( !Can_Undo( ply, TheUndo ) ) then return end
|
||||
|
||||
-- Undo!
|
||||
Do_Undo( TheUndo )
|
||||
|
||||
-- Notify the client UI that the undo happened
|
||||
-- This is normally called by the deleted entity via SendUndoneMessage
|
||||
-- But in cases where the undo only has functions that will not do
|
||||
net.Start( "Undo_Undone" )
|
||||
net.WriteInt( UndoNum, 16 )
|
||||
net.Send( ply )
|
||||
|
||||
-- Don't delete the entry completely so nothing new takes its place and ruin CC_UndoLast's logic (expecting newest entry be at highest index)
|
||||
PlayerUndo[ index ][ UndoNum ] = {}
|
||||
|
||||
end
|
||||
|
||||
concommand.Add( "undo", CC_UndoLast, nil, "", { FCVAR_DONTRECORD } )
|
||||
concommand.Add( "gmod_undo", CC_UndoLast, nil, "", { FCVAR_DONTRECORD } )
|
||||
concommand.Add( "gmod_undonum", CC_UndoNum, nil, "", { FCVAR_DONTRECORD } )
|
||||
97
lua/includes/modules/usermessage.lua
Normal file
97
lua/includes/modules/usermessage.lua
Normal file
@@ -0,0 +1,97 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Globals that we are going to use
|
||||
local unpack = unpack
|
||||
local Msg = Msg
|
||||
|
||||
--[[
|
||||
This is merely a convenience function. If you pass numbers
|
||||
using this they're always sent as long. Which sucks if you're sending
|
||||
numbers that are always under 100 etc.
|
||||
--]]
|
||||
function SendUserMessage( name, ply, ... )
|
||||
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
umsg.Start( name, ply )
|
||||
|
||||
for k, v in ipairs( { ... } ) do
|
||||
local t = TypeID( v )
|
||||
|
||||
if ( t == TYPE_STRING ) then
|
||||
umsg.String( v )
|
||||
elseif ( t == TYPE_ENTITY ) then
|
||||
umsg.Entity( v )
|
||||
elseif ( t == TYPE_NUMBER ) then
|
||||
umsg.Long( v )
|
||||
elseif ( t == TYPE_VECTOR ) then
|
||||
umsg.Vector( v )
|
||||
elseif ( t == TYPE_ANGLE ) then
|
||||
umsg.Angle( v )
|
||||
elseif ( t == TYPE_BOOL ) then
|
||||
umsg.Bool( v )
|
||||
else
|
||||
ErrorNoHalt( "SendUserMessage: Couldn't send type " .. type( v ) .. "\n" )
|
||||
end
|
||||
end
|
||||
|
||||
umsg.End()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: usermessage
|
||||
Desc: Enables the server to send the client messages (in a bandwidth friendly manner)
|
||||
-----------------------------------------------------------]]
|
||||
module( "usermessage" )
|
||||
|
||||
local Hooks = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTable
|
||||
Desc: Returns the table of hooked usermessages
|
||||
-----------------------------------------------------------]]
|
||||
function GetTable()
|
||||
|
||||
return Hooks
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Hook
|
||||
Desc: Adds a hook
|
||||
-----------------------------------------------------------]]
|
||||
function Hook( messagename, func, ... )
|
||||
|
||||
Hooks[ messagename ] = {}
|
||||
|
||||
Hooks[ messagename ].Function = func
|
||||
Hooks[ messagename ].PreArgs = { ... }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Call( name, args )
|
||||
Desc: Called by the engine to call a gamemode hook
|
||||
-----------------------------------------------------------]]
|
||||
function IncomingMessage( MessageName, msg )
|
||||
|
||||
if ( Hooks[ MessageName ] ) then
|
||||
|
||||
Hooks[ MessageName ].Function( msg, unpack( Hooks[ MessageName ].PreArgs ) )
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
Msg( "Warning: Unhandled usermessage '" .. MessageName .. "'\n" )
|
||||
|
||||
end
|
||||
387
lua/includes/modules/utf8.lua
Normal file
387
lua/includes/modules/utf8.lua
Normal file
@@ -0,0 +1,387 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local bit = bit
|
||||
local error = error
|
||||
local ipairs = ipairs
|
||||
local string = string
|
||||
local table = table
|
||||
local unpack = unpack
|
||||
local math = math
|
||||
|
||||
module( "utf8" )
|
||||
|
||||
--
|
||||
-- Pattern that can be used with the string library to match a single UTF-8 byte-sequence.
|
||||
-- This expects the string to contain valid UTF-8 data.
|
||||
--
|
||||
charpattern = "[%z\x01-\x7F\xC2-\xF4][\x80-\xBF]*"
|
||||
|
||||
--
|
||||
-- Transforms indexes of a string to be positive.
|
||||
-- Negative indices will wrap around like the string library's functions.
|
||||
--
|
||||
local function strRelToAbs( str, ... )
|
||||
|
||||
local args = { ... }
|
||||
|
||||
for k, v in ipairs( args ) do
|
||||
v = v > 0 and v or math.max( #str + v + 1, 1 )
|
||||
|
||||
if v < 1 or v > #str + 1 then
|
||||
error( "bad index to string (out of range)", 3 )
|
||||
end
|
||||
|
||||
args[ k ] = v
|
||||
end
|
||||
|
||||
return unpack( args )
|
||||
|
||||
end
|
||||
|
||||
-- Decodes a single UTF-8 byte-sequence from a string, ensuring it is valid
|
||||
-- Returns the index of the first/last chars of a sequence and its codepoint
|
||||
--
|
||||
local function decode( str, startPos )
|
||||
|
||||
startPos = strRelToAbs( str, startPos or 1 )
|
||||
|
||||
local b1 = str:byte( startPos, startPos )
|
||||
|
||||
-- End of string
|
||||
if not b1 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Single-byte sequence
|
||||
if b1 < 0x80 then
|
||||
return startPos, startPos, b1
|
||||
end
|
||||
|
||||
-- Validate first byte of multi-byte sequence
|
||||
if b1 > 0xF4 or b1 < 0xC2 then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Get 'supposed' amount of continuation bytes from primary byte
|
||||
local contByteCount = b1 >= 0xF0 and 3 or
|
||||
b1 >= 0xE0 and 2 or
|
||||
b1 >= 0xC0 and 1
|
||||
|
||||
local endPos = startPos + contByteCount
|
||||
local codePoint = 0
|
||||
|
||||
-- The string doesn't have enough data for this many continutation bytes
|
||||
if #str < endPos then
|
||||
return nil
|
||||
end
|
||||
|
||||
-- Validate our continuation bytes
|
||||
for _, bX in ipairs { str:byte( startPos + 1, endPos ) } do
|
||||
|
||||
-- Invalid continuation byte hit
|
||||
if bit.band( bX, 0xC0 ) ~= 0x80 then
|
||||
return nil
|
||||
end
|
||||
|
||||
codePoint = bit.bor( bit.lshift( codePoint, 6 ), bit.band( bX, 0x3F ) )
|
||||
b1 = bit.lshift( b1, 1 )
|
||||
|
||||
end
|
||||
|
||||
codePoint = bit.bor( codePoint, bit.lshift( bit.band( b1, 0x7F ), contByteCount * 5 ) )
|
||||
|
||||
return startPos, endPos, codePoint
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Takes zero or more integers and returns a string containing the UTF-8 representation of each
|
||||
--
|
||||
function char( ... )
|
||||
|
||||
local buf = {}
|
||||
|
||||
for k, v in ipairs { ... } do
|
||||
|
||||
if v < 0 or v > 0x10FFFF then
|
||||
error( "bad argument #" .. k .. " to char (out of range)", 2 )
|
||||
end
|
||||
|
||||
local b1, b2, b3, b4 = nil, nil, nil, nil
|
||||
|
||||
if v < 0x80 then -- Single-byte sequence
|
||||
|
||||
table.insert( buf, string.char( v ) )
|
||||
|
||||
elseif v < 0x800 then -- Two-byte sequence
|
||||
|
||||
b1 = bit.bor( 0xC0, bit.band( bit.rshift( v, 6 ), 0x1F ) )
|
||||
b2 = bit.bor( 0x80, bit.band( v, 0x3F ) )
|
||||
|
||||
table.insert( buf, string.char( b1, b2 ) )
|
||||
|
||||
elseif v < 0x10000 then -- Three-byte sequence
|
||||
|
||||
b1 = bit.bor( 0xE0, bit.band( bit.rshift( v, 12 ), 0x0F ) )
|
||||
b2 = bit.bor( 0x80, bit.band( bit.rshift( v, 6 ), 0x3F ) )
|
||||
b3 = bit.bor( 0x80, bit.band( v, 0x3F ) )
|
||||
|
||||
table.insert( buf, string.char( b1, b2, b3 ) )
|
||||
|
||||
else -- Four-byte sequence
|
||||
|
||||
b1 = bit.bor( 0xF0, bit.band( bit.rshift( v, 18 ), 0x07 ) )
|
||||
b2 = bit.bor( 0x80, bit.band( bit.rshift( v, 12 ), 0x3F ) )
|
||||
b3 = bit.bor( 0x80, bit.band( bit.rshift( v, 6 ), 0x3F ) )
|
||||
b4 = bit.bor( 0x80, bit.band( v, 0x3F ) )
|
||||
|
||||
table.insert( buf, string.char( b1, b2, b3, b4 ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return table.concat( buf, "" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Iterates over a UTF-8 string similarly to pairs
|
||||
-- k = index of sequence, v = string value of sequence
|
||||
--
|
||||
function codes( str )
|
||||
|
||||
local i = 1
|
||||
|
||||
return function()
|
||||
|
||||
-- Have we hit the end of the iteration set?
|
||||
if i > #str then
|
||||
return nil
|
||||
end
|
||||
|
||||
local startPos, endPos, codePoint = decode( str, i )
|
||||
|
||||
if not startPos then
|
||||
error( "invalid UTF-8 code", 2 )
|
||||
end
|
||||
|
||||
i = endPos + 1
|
||||
|
||||
return startPos, codePoint
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns an integer-representation of the UTF-8 sequence(s) in a string
|
||||
-- startPos defaults to 1, endPos defaults to startPos
|
||||
--
|
||||
function codepoint( str, startPos, endPos )
|
||||
|
||||
startPos, endPos = strRelToAbs( str, startPos or 1, endPos or startPos or 1 )
|
||||
|
||||
local ret = {}
|
||||
|
||||
repeat
|
||||
local seqStartPos, seqEndPos, codePoint = decode( str, startPos )
|
||||
|
||||
if not seqStartPos then
|
||||
error( "invalid UTF-8 code", 2 )
|
||||
end
|
||||
|
||||
-- Increment current string index
|
||||
startPos = seqEndPos + 1
|
||||
|
||||
table.insert( ret, codePoint )
|
||||
until seqEndPos >= endPos
|
||||
|
||||
return unpack( ret )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns the length of a UTF-8 string. false, index is returned if an invalid sequence is hit
|
||||
-- startPos defaults to 1, endPos defaults to -1
|
||||
--
|
||||
function len( str, startPos, endPos )
|
||||
|
||||
startPos, endPos = strRelToAbs( str, startPos or 1, endPos or -1 )
|
||||
|
||||
local len = 0
|
||||
|
||||
while endPos >= startPos and startPos <= #str do
|
||||
local seqStartPos, seqEndPos = decode( str, startPos )
|
||||
|
||||
-- Hit an invalid sequence?
|
||||
if not seqStartPos then
|
||||
return false, startPos
|
||||
end
|
||||
|
||||
-- Increment current string pointer
|
||||
startPos = seqEndPos + 1
|
||||
|
||||
-- Increment length
|
||||
len = len + 1
|
||||
end
|
||||
|
||||
return len
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Returns the byte-index of the n'th UTF-8-character after the given byte-index (nil if none)
|
||||
-- startPos defaults to 1 when n is positive and -1 when n is negative
|
||||
-- If 0 is zero, this function instead returns the byte-index of the UTF-8-character startPos lies within.
|
||||
--
|
||||
function offset( str, n, startPos )
|
||||
|
||||
if startPos and ( startPos > #str or -startPos > #str or startPos == 0 ) then
|
||||
error( "bad index to string (out of range)", 2 )
|
||||
end
|
||||
|
||||
local pos = ( n >= 0 ) and 1 or #str
|
||||
pos = strRelToAbs( str, startPos or pos )
|
||||
|
||||
-- Back up to the start of this byte sequence
|
||||
if n == 0 then
|
||||
|
||||
while pos > 0 and not decode( str, pos ) do
|
||||
pos = pos - 1
|
||||
end
|
||||
|
||||
return pos
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Make sure we're on a valid sequence
|
||||
--
|
||||
if not decode( str, pos ) then
|
||||
error( "initial position is a continuation byte", 2 )
|
||||
end
|
||||
|
||||
-- Back up to (-n) byte sequences
|
||||
if n < 0 then
|
||||
|
||||
for i = 1, -n do
|
||||
pos = pos - 1
|
||||
|
||||
while pos > 0 and not decode( str, pos ) do
|
||||
pos = pos - 1
|
||||
end
|
||||
end
|
||||
|
||||
if pos < 1 then
|
||||
return nil
|
||||
end
|
||||
|
||||
return pos
|
||||
|
||||
end
|
||||
|
||||
-- Jump forward (n) byte sequences
|
||||
if n > 0 then
|
||||
|
||||
for i = 1, n do
|
||||
pos = pos + 1
|
||||
|
||||
while pos <= #str and not decode( str, pos ) do
|
||||
pos = pos + 1
|
||||
end
|
||||
end
|
||||
|
||||
if pos > #str then
|
||||
return nil
|
||||
end
|
||||
|
||||
return pos
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Forces a string to contain only valid UTF-8 data.
|
||||
-- Invalid sequences are replaced with U+FFFD.
|
||||
--
|
||||
function force( str )
|
||||
|
||||
local buf = {}
|
||||
|
||||
local curPos, endPos = 1, #str
|
||||
|
||||
-- Empty string?
|
||||
if endPos == 0 then
|
||||
return str
|
||||
end
|
||||
|
||||
repeat
|
||||
|
||||
local seqStartPos, seqEndPos = decode( str, curPos )
|
||||
|
||||
if not seqStartPos then
|
||||
|
||||
table.insert( buf, char( 0xFFFD ) )
|
||||
curPos = curPos + 1
|
||||
|
||||
else
|
||||
|
||||
table.insert( buf, str:sub( seqStartPos, seqEndPos ) )
|
||||
curPos = seqEndPos + 1
|
||||
|
||||
end
|
||||
|
||||
until curPos > endPos
|
||||
|
||||
return table.concat( buf, "" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Converts a relative index to an absolute
|
||||
-- This is different from the above in that it cares about characters and not bytes
|
||||
--
|
||||
local function strRelToAbsChar( str, pos )
|
||||
if pos < 0 then
|
||||
pos = math.max( pos + len( str ) + 1, 0 )
|
||||
end
|
||||
return pos
|
||||
end
|
||||
|
||||
--
|
||||
-- UTF-8 compilant version of str[idx]
|
||||
--
|
||||
function GetChar( str, idx )
|
||||
idx = strRelToAbsChar( str, idx )
|
||||
|
||||
if idx == 0 then return "" end
|
||||
if idx > len( str ) then return "" end
|
||||
|
||||
local off = offset( str, idx - 1 )
|
||||
return char( codepoint( str, off ) )
|
||||
end
|
||||
|
||||
--
|
||||
-- UTF-8 compilant version of string.sub
|
||||
--
|
||||
function sub( str, charstart, charend )
|
||||
charstart = strRelToAbsChar( str, charstart )
|
||||
charend = strRelToAbsChar( str, charend or -1 )
|
||||
|
||||
local buf = {}
|
||||
for i = charstart, charend do
|
||||
buf[#buf + 1] = GetChar( str, i )
|
||||
end
|
||||
|
||||
return table.concat( buf )
|
||||
end
|
||||
195
lua/includes/modules/weapons.lua
Normal file
195
lua/includes/modules/weapons.lua
Normal file
@@ -0,0 +1,195 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
module( "weapons", package.seeall )
|
||||
|
||||
local WeaponList = {}
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TableInherit( t, base )
|
||||
Desc: Copies any missing data from base to t
|
||||
-----------------------------------------------------------]]
|
||||
local function TableInherit( t, base )
|
||||
|
||||
for k, v in pairs( base ) do
|
||||
|
||||
if ( t[ k ] == nil ) then
|
||||
t[ k ] = v
|
||||
elseif ( k != "BaseClass" && istable( t[ k ] ) && istable( v ) ) then
|
||||
TableInherit( t[ k ], v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
t[ "BaseClass" ] = base
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsBasedOn( name, base )
|
||||
Desc: Checks if name is based on base
|
||||
-----------------------------------------------------------]]
|
||||
function IsBasedOn( name, base )
|
||||
local t = GetStored( name )
|
||||
if ( !t ) then return false end
|
||||
if ( t.Base == name ) then return false end
|
||||
|
||||
if ( t.Base == base ) then return true end
|
||||
return IsBasedOn( t.Base, base )
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Register( table, string, bool )
|
||||
Desc: Used to register your SWEP with the engine
|
||||
-----------------------------------------------------------]]
|
||||
function Register( t, name )
|
||||
|
||||
if ( hook.Run( "PreRegisterSWEP", t, name ) == false ) then return end
|
||||
|
||||
if ( isstring( t.ClassNameOverride ) ) then name = t.ClassNameOverride end
|
||||
|
||||
local old = WeaponList[ name ]
|
||||
t.ClassName = name
|
||||
WeaponList[ name ] = t
|
||||
|
||||
--baseclass.Set( name, t )
|
||||
|
||||
list.Set( "Weapon", name, {
|
||||
ClassName = name,
|
||||
PrintName = t.PrintName or name,
|
||||
Category = t.Category or "Other",
|
||||
Spawnable = t.Spawnable,
|
||||
AdminOnly = t.AdminOnly,
|
||||
ScriptedEntityType = t.ScriptedEntityType,
|
||||
IconOverride = t.IconOverride
|
||||
} )
|
||||
|
||||
-- Allow all SWEPS to be duplicated, unless specified
|
||||
if ( !t.DisableDuplicator ) then
|
||||
duplicator.Allow( name )
|
||||
end
|
||||
|
||||
--
|
||||
-- If we're reloading this entity class
|
||||
-- then refresh all the existing entities.
|
||||
--
|
||||
if ( old != nil ) then
|
||||
|
||||
-- Update SWEP table of entities that are based on this SWEP
|
||||
for _, e in ipairs( ents.GetAll() ) do
|
||||
local class = e:GetClass()
|
||||
|
||||
if ( class == name ) then
|
||||
--
|
||||
-- Replace the contents with this entity table
|
||||
--
|
||||
table.Merge( e, t )
|
||||
|
||||
--
|
||||
-- Call OnReloaded hook (if it has one)
|
||||
--
|
||||
if ( e.OnReloaded ) then
|
||||
e:OnReloaded()
|
||||
end
|
||||
end
|
||||
|
||||
if ( IsBasedOn( class, name ) ) then
|
||||
table.Merge( e, Get( class ) )
|
||||
|
||||
if ( e.OnReloaded ) then
|
||||
e:OnReloaded()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- All scripts have been loaded...
|
||||
--
|
||||
function OnLoaded()
|
||||
|
||||
--
|
||||
-- Once all the scripts are loaded we can set up the baseclass
|
||||
-- - we have to wait until they're all setup because load order
|
||||
-- could cause some entities to load before their bases!
|
||||
--
|
||||
for k, v in pairs( WeaponList ) do
|
||||
|
||||
baseclass.Set( k, Get( k ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Get( string )
|
||||
Desc: Get a weapon by name.
|
||||
-----------------------------------------------------------]]
|
||||
function Get( name, retval )
|
||||
|
||||
local Stored = GetStored( name )
|
||||
if ( !Stored ) then return nil end
|
||||
|
||||
-- Create/copy a new table
|
||||
local retval = retval or {}
|
||||
for k, v in pairs( Stored ) do
|
||||
if ( istable( v ) ) then
|
||||
retval[ k ] = table.Copy( v )
|
||||
else
|
||||
retval[ k ] = v
|
||||
end
|
||||
end
|
||||
retval.Base = retval.Base or "weapon_base"
|
||||
|
||||
-- If we're not derived from ourselves (a base weapon)
|
||||
-- then derive from our 'Base' weapon.
|
||||
if ( retval.Base != name ) then
|
||||
|
||||
local base = Get( retval.Base )
|
||||
|
||||
if ( !base ) then
|
||||
Msg( "ERROR: Trying to derive weapon " .. tostring( name ) .. " from non existant SWEP " .. tostring( retval.Base ) .. "!\n" )
|
||||
else
|
||||
retval = TableInherit( retval, base )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return retval
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetStored( string )
|
||||
Desc: Gets the REAL weapon table, not a copy
|
||||
-----------------------------------------------------------]]
|
||||
function GetStored( name )
|
||||
return WeaponList[ name ]
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetList( string )
|
||||
Desc: Get a list of all the registered SWEPs
|
||||
-----------------------------------------------------------]]
|
||||
function GetList()
|
||||
local result = {}
|
||||
|
||||
for k, v in pairs( WeaponList ) do
|
||||
table.insert( result, v )
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
173
lua/includes/modules/widget.lua
Normal file
173
lua/includes/modules/widget.lua
Normal file
@@ -0,0 +1,173 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Widgets are like gui controls in the 3D world(!!!)
|
||||
--
|
||||
|
||||
widgets = {}
|
||||
|
||||
--
|
||||
-- Holds the currently hovered widget
|
||||
--
|
||||
widgets.Hovered = nil
|
||||
widgets.HoveredPos = vector_origin
|
||||
|
||||
--
|
||||
-- Holds the current pressed widget
|
||||
--
|
||||
widgets.Pressed = nil
|
||||
|
||||
local function UpdateHovered( pl, mv )
|
||||
|
||||
if ( !IsValid( pl ) ) then return end
|
||||
|
||||
if ( !pl:Alive() ) then
|
||||
pl:SetHoveredWidget( NULL )
|
||||
return
|
||||
end
|
||||
|
||||
local OldHovered = pl:GetHoveredWidget()
|
||||
pl:SetHoveredWidget( NULL )
|
||||
|
||||
local eyePos = pl:EyePos()
|
||||
local aimVector = pl:GetAimVector()
|
||||
aimVector:Mul( 256 )
|
||||
aimVector:Add( eyePos )
|
||||
|
||||
local trace =
|
||||
{
|
||||
start = eyePos,
|
||||
endpos = aimVector,
|
||||
filter = function( ent )
|
||||
|
||||
return IsValid( ent ) && ent:IsWidget()
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
-- debugoverlay.Line( trace.start, trace.endpos, 0.5 )
|
||||
|
||||
widgets.Tracing = true
|
||||
local tr = util.TraceLine( trace )
|
||||
widgets.Tracing = false
|
||||
|
||||
if ( !IsValid( tr.Entity ) ) then return end
|
||||
if ( tr.Entity:IsWorld() ) then return end
|
||||
if ( !tr.Entity:IsWidget() ) then return end
|
||||
|
||||
-- debugoverlay.Cross( tr.HitPos, 1, 60 )
|
||||
|
||||
if ( OldHovered != tr.Entity ) then
|
||||
|
||||
-- On hover changed? why bother?
|
||||
|
||||
end
|
||||
|
||||
pl:SetHoveredWidget( tr.Entity )
|
||||
pl.WidgetHitPos = tr.HitPos
|
||||
|
||||
end
|
||||
|
||||
local function UpdateButton( pl, mv, btn, mousebutton )
|
||||
|
||||
local now = mv:KeyDown( btn )
|
||||
local was = mv:KeyWasDown( btn )
|
||||
local hvr = pl:GetHoveredWidget()
|
||||
local prs = pl:GetPressedWidget()
|
||||
|
||||
if ( now && !was && IsValid( hvr ) ) then
|
||||
hvr:OnPress( pl, mousebutton, mv )
|
||||
end
|
||||
|
||||
if ( !now && was && IsValid( prs ) ) then
|
||||
prs:OnRelease( pl, mousebutton, mv )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- The idea here is to have exactly the same
|
||||
-- behaviour on the client as the server.
|
||||
--
|
||||
function widgets.PlayerTick( pl, mv )
|
||||
|
||||
UpdateHovered( pl, mv )
|
||||
|
||||
UpdateButton( pl, mv, IN_ATTACK, 1 )
|
||||
UpdateButton( pl, mv, IN_ATTACK2, 2 )
|
||||
|
||||
local prs = pl:GetPressedWidget()
|
||||
|
||||
if ( IsValid( prs ) ) then
|
||||
prs:PressedThinkInternal( pl, mv )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
---
|
||||
--- Render the widgets!
|
||||
---
|
||||
|
||||
local RenderList = {}
|
||||
|
||||
function widgets.RenderMe( ent )
|
||||
|
||||
--
|
||||
-- The pressed widget gets to decide what should draw
|
||||
--
|
||||
if ( LocalPlayer() && IsValid(LocalPlayer():GetPressedWidget()) ) then
|
||||
|
||||
if ( !LocalPlayer():GetPressedWidget():PressedShouldDraw( ent ) ) then
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
table.insert( RenderList, ent )
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PostDrawEffects", "RenderWidgets", function()
|
||||
|
||||
--
|
||||
-- Don't do anything if we don't have widgets to render!
|
||||
--
|
||||
if ( #RenderList == 0 ) then return end
|
||||
|
||||
cam.Start3D( EyePos(), EyeAngles() )
|
||||
|
||||
for k, v in ipairs( RenderList ) do
|
||||
|
||||
v:OverlayRender()
|
||||
|
||||
end
|
||||
|
||||
cam.End3D()
|
||||
|
||||
RenderList = {}
|
||||
|
||||
end )
|
||||
|
||||
|
||||
hook.Add( "PlayerTick", "TickWidgets", function( pl, mv ) widgets.PlayerTick( pl, mv ) end )
|
||||
|
||||
|
||||
|
||||
|
||||
local ENTITY = FindMetaTable( "Entity" )
|
||||
|
||||
function ENTITY:IsWidget()
|
||||
return self.Widget
|
||||
end
|
||||
543
lua/includes/util.lua
Normal file
543
lua/includes/util.lua
Normal file
@@ -0,0 +1,543 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
-- Temporary, DELETE ME after an update after May 2024
|
||||
if ( CLIENT and !vgui.GetAll ) then function vgui.GetAll() return {} end end
|
||||
|
||||
if ( !RegisterMetaTable ) then
|
||||
local metas = {}
|
||||
|
||||
local oldFindMetaTable = FindMetaTable
|
||||
FindMetaTable = function( name )
|
||||
local f = oldFindMetaTable( name )
|
||||
if ( f ) then return f end
|
||||
|
||||
return metas[ name ]
|
||||
end
|
||||
|
||||
function RegisterMetaTable( key, value )
|
||||
metas[ key ] = value
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Hack for debug.getregistry
|
||||
--
|
||||
local meta = {}
|
||||
function meta.__index( self, key )
|
||||
return FindMetaTable( key )
|
||||
end
|
||||
function meta.__newindex( self, key, value )
|
||||
rawset( self, key, value )
|
||||
|
||||
if ( isstring( key ) and istable( value ) ) then
|
||||
RegisterMetaTable( key, value )
|
||||
end
|
||||
end
|
||||
|
||||
local tbl = {}
|
||||
setmetatable( tbl, meta )
|
||||
function debug.getregistry() return tbl end
|
||||
|
||||
--
|
||||
-- Seed the rand!
|
||||
--
|
||||
math.randomseed( os.time() )
|
||||
|
||||
--
|
||||
-- Alias string.Format to global Format
|
||||
--
|
||||
Format = string.format
|
||||
|
||||
--
|
||||
-- Send C the flags for any materials we want to create
|
||||
--
|
||||
local C_Material = Material
|
||||
|
||||
function Material( name, words )
|
||||
|
||||
if ( !words ) then return C_Material( name ) end
|
||||
|
||||
local str = (words:find("vertexlitgeneric") and "1" or "0")
|
||||
str = str .. (words:find("nocull") and "1" or "0")
|
||||
str = str .. (words:find("alphatest") and "1" or "0")
|
||||
str = str .. (words:find("mips") and "1" or "0")
|
||||
str = str .. (words:find("noclamp") and "1" or "0")
|
||||
str = str .. (words:find("smooth") and "1" or "0")
|
||||
str = str .. (words:find("ignorez") and "1" or "0")
|
||||
|
||||
return C_Material( name, str )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
IsTableOfEntitiesValid
|
||||
-----------------------------------------------------------]]
|
||||
function IsTableOfEntitiesValid( tab )
|
||||
|
||||
if ( !tab ) then return false end
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
if ( !IsValid( v ) ) then return false end
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Color related functions - they now have their own
|
||||
metatable so better put them in their own separate
|
||||
file
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
include( "util/color.lua" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Prints a table to the console
|
||||
-----------------------------------------------------------]]
|
||||
function PrintTable( t, indent, done )
|
||||
local Msg = Msg
|
||||
|
||||
done = done or {}
|
||||
indent = indent or 0
|
||||
local keys = table.GetKeys( t )
|
||||
|
||||
table.sort( keys, function( a, b )
|
||||
if ( isnumber( a ) and isnumber( b ) ) then return a < b end
|
||||
return tostring( a ) < tostring( b )
|
||||
end )
|
||||
|
||||
done[ t ] = true
|
||||
|
||||
for i = 1, #keys do
|
||||
local key = keys[ i ]
|
||||
local value = t[ key ]
|
||||
key = ( type( key ) == "string" ) and "[\"" .. key .. "\"]" || "[" .. tostring( key ) .. "]"
|
||||
Msg( string.rep( "\t", indent ) )
|
||||
|
||||
if ( istable( value ) and !done[ value ] ) then
|
||||
|
||||
done[ value ] = true
|
||||
Msg( key, ":\n" )
|
||||
PrintTable ( value, indent + 2, done )
|
||||
done[ value ] = nil
|
||||
|
||||
else
|
||||
|
||||
Msg( key, "\t=\t", value, "\n" )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns a random vector
|
||||
-----------------------------------------------------------]]
|
||||
function VectorRand( min, max )
|
||||
min = min || -1
|
||||
max = max || 1
|
||||
return Vector( math.Rand( min, max ), math.Rand( min, max ), math.Rand( min, max ) )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns a random angle
|
||||
-----------------------------------------------------------]]
|
||||
function AngleRand( min, max )
|
||||
return Angle( math.Rand( min || -90, max || 90 ), math.Rand( min || -180, max || 180 ), math.Rand( min || -180, max || 180 ) )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns a random color
|
||||
-----------------------------------------------------------]]
|
||||
function ColorRand( alpha )
|
||||
if ( alpha ) then
|
||||
return Color( math.random( 0, 255 ), math.random( 0, 255 ), math.random( 0, 255 ), math.random( 0, 255 ) )
|
||||
end
|
||||
|
||||
return Color( math.random( 0, 255 ), math.random( 0, 255 ), math.random( 0, 255 ) )
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convenience function to precache a sound
|
||||
-----------------------------------------------------------]]
|
||||
function Sound( name )
|
||||
util.PrecacheSound( name )
|
||||
return name
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convenience function to precache a model
|
||||
-----------------------------------------------------------]]
|
||||
function Model( name )
|
||||
util.PrecacheModel( name )
|
||||
return name
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convenience function to precache a particle
|
||||
-----------------------------------------------------------]]
|
||||
function Particle( name )
|
||||
if ( CLIENT ) then
|
||||
game.AddParticles( name )
|
||||
end
|
||||
return name
|
||||
end
|
||||
|
||||
-- Some nice globals so we don't keep creating objects for no reason
|
||||
vector_origin = Vector( 0, 0, 0 )
|
||||
vector_up = Vector( 0, 0, 1 )
|
||||
angle_zero = Angle( 0, 0, 0 )
|
||||
|
||||
color_white = Color( 255, 255, 255, 255 )
|
||||
color_black = Color( 0, 0, 0, 255 )
|
||||
color_transparent = Color( 255, 255, 255, 0 )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Includes the file - and adds it so the CS file list
|
||||
-----------------------------------------------------------]]
|
||||
function IncludeCS( filename )
|
||||
if ( SERVER ) then
|
||||
AddCSLuaFile( filename )
|
||||
end
|
||||
|
||||
return include( filename )
|
||||
end
|
||||
|
||||
-- Globals
|
||||
FORCE_STRING = 1
|
||||
FORCE_NUMBER = 2
|
||||
FORCE_BOOL = 3
|
||||
FORCE_ANGLE = 4
|
||||
FORCE_COLOR = 5
|
||||
FORCE_VECTOR = 6
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
AccessorFunc
|
||||
Quickly make Get/Set accessor fuctions on the specified table
|
||||
-----------------------------------------------------------]]
|
||||
function AccessorFunc( tab, varname, name, iForce )
|
||||
|
||||
if ( !tab ) then debug.Trace() end
|
||||
|
||||
tab[ "Get" .. name ] = function( self ) return self[ varname ] end
|
||||
|
||||
if ( iForce == FORCE_STRING ) then
|
||||
tab[ "Set" .. name ] = function( self, v ) self[ varname ] = tostring( v ) end
|
||||
return end
|
||||
|
||||
if ( iForce == FORCE_NUMBER ) then
|
||||
tab[ "Set" .. name ] = function( self, v ) self[ varname ] = tonumber( v ) end
|
||||
return end
|
||||
|
||||
if ( iForce == FORCE_BOOL ) then
|
||||
tab[ "Set" .. name ] = function( self, v ) self[ varname ] = tobool( v ) end
|
||||
return end
|
||||
|
||||
if ( iForce == FORCE_ANGLE ) then
|
||||
tab[ "Set" .. name ] = function( self, v ) self[ varname ] = Angle( v ) end
|
||||
return end
|
||||
|
||||
if ( iForce == FORCE_COLOR ) then
|
||||
tab[ "Set" .. name ] = function( self, v )
|
||||
if ( type( v ) == "Vector" ) then self[ varname ] = v:ToColor()
|
||||
else self[ varname ] = string.ToColor( tostring( v ) ) end
|
||||
end
|
||||
return end
|
||||
|
||||
if ( iForce == FORCE_VECTOR ) then
|
||||
tab[ "Set" .. name ] = function( self, v )
|
||||
if ( IsColor( v ) ) then self[ varname ] = v:ToVector()
|
||||
else self[ varname ] = Vector( v ) end
|
||||
end
|
||||
return end
|
||||
|
||||
tab[ "Set" .. name ] = function( self, v ) self[ varname ] = v end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns true if object is valid (is not nil and IsValid)
|
||||
-----------------------------------------------------------]]
|
||||
function IsValid( object )
|
||||
|
||||
if ( !object ) then return false end
|
||||
|
||||
local isvalid = object.IsValid
|
||||
if ( !isvalid ) then return false end
|
||||
|
||||
return isvalid( object )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Safely remove an entity
|
||||
-----------------------------------------------------------]]
|
||||
function SafeRemoveEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) || ent:IsPlayer() ) then return end
|
||||
|
||||
ent:Remove()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Safely remove an entity (delayed)
|
||||
-----------------------------------------------------------]]
|
||||
function SafeRemoveEntityDelayed( ent, timedelay )
|
||||
|
||||
if ( !IsValid( ent ) || ent:IsPlayer() ) then return end
|
||||
|
||||
timer.Simple( timedelay, function() SafeRemoveEntity( ent ) end )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Simple lerp
|
||||
-----------------------------------------------------------]]
|
||||
function Lerp( delta, from, to )
|
||||
|
||||
if ( delta > 1 ) then return to end
|
||||
if ( delta < 0 ) then return from end
|
||||
|
||||
return from + ( to - from ) * delta
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convert Var to Bool
|
||||
-----------------------------------------------------------]]
|
||||
function tobool( val )
|
||||
if ( val == nil || val == false || val == 0 || val == "0" || val == "false" ) then return false end
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Universal function to filter out crappy models by name
|
||||
-----------------------------------------------------------]]
|
||||
local UselessModels = {
|
||||
"_gesture", "_anim", "_gst", "_pst", "_shd", "_ss", "_posture", "_anm",
|
||||
"ghostanim","_paths", "_shared", "anim_", "gestures_", "shared_ragdoll_"
|
||||
}
|
||||
|
||||
function IsUselessModel( modelname )
|
||||
|
||||
modelname = modelname:lower()
|
||||
|
||||
if ( !modelname:find( ".mdl", 1, true ) ) then return true end
|
||||
|
||||
for k, v in ipairs( UselessModels ) do
|
||||
if ( modelname:find( v, 1, true ) ) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
UTIL_IsUselessModel = IsUselessModel
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Given a number, returns the right 'th
|
||||
-----------------------------------------------------------]]
|
||||
local STNDRD_TBL = { "st", "nd", "rd" }
|
||||
function STNDRD( num )
|
||||
num = num % 100
|
||||
if ( num > 10 and num < 20 ) then
|
||||
return "th"
|
||||
end
|
||||
|
||||
return STNDRD_TBL[ num % 10 ] or "th"
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
From Simple Gamemode Base (Rambo_9)
|
||||
-----------------------------------------------------------]]
|
||||
function TimedSin( freq, min, max, offset )
|
||||
return math.sin( freq * math.pi * 2 * CurTime() + offset ) * ( max - min ) * 0.5 + min
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
From Simple Gamemode Base (Rambo_9)
|
||||
-----------------------------------------------------------]]
|
||||
function TimedCos( freq, min, max, offset )
|
||||
return math.cos( freq * math.pi * 2 * CurTime() + offset ) * ( max - min ) * 0.5 + min
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
IsEnemyEntityName
|
||||
-----------------------------------------------------------]]
|
||||
local EnemyNames = {
|
||||
-- Half-Life 1.
|
||||
monster_alien_grunt = true, monster_nihilanth = true, monster_tentacle = true, monster_alien_slave = true,
|
||||
monster_bigmomma = true, monster_bullchicken = true, monster_gargantua = true, monster_human_assassin = true,
|
||||
monster_babycrab = true, monster_human_grunt = true, monster_cockroach = true, monster_houndeye = true,
|
||||
monster_zombie = true, monster_headcrab = true, monster_alien_controller = true, monster_turret = true,
|
||||
monster_miniturret = true, monster_sentry = true,
|
||||
|
||||
-- Half-Life 2.
|
||||
npc_antlion = true, npc_antlionguard = true, npc_antlionguardian = true, npc_barnacle = true,
|
||||
npc_breen = true, npc_clawscanner = true, npc_combine_s = true, npc_cscanner = true, npc_fastzombie = true,
|
||||
npc_fastzombie_torso = true, npc_headcrab = true, npc_headcrab_fast = true, npc_headcrab_poison = true,
|
||||
npc_hunter = true, npc_metropolice = true, npc_manhack = true, npc_poisonzombie = true, npc_strider = true,
|
||||
npc_stalker = true, npc_zombie = true, npc_zombie_torso = true, npc_zombine = true, npc_combine_camera = true,
|
||||
npc_turret_ceiling = true, npc_combinedropship = true, npc_combinegunship = true, npc_helicopter = true,
|
||||
npc_turret_floor = true, npc_antlion_worker = true, npc_headcrab_black = true
|
||||
}
|
||||
|
||||
function IsEnemyEntityName( victimtype )
|
||||
return EnemyNames[ victimtype ] or false
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
IsFriendEntityName
|
||||
-----------------------------------------------------------]]
|
||||
local FriendlyNames = {
|
||||
-- Half-Life 1.
|
||||
monster_scientist = true, monster_barney = true,
|
||||
|
||||
-- Half-Life 2.
|
||||
npc_alyx = true, npc_barney = true, npc_citizen = true, npc_dog = true, npc_eli = true,
|
||||
npc_fisherman = true, npc_gman = true, npc_kleiner = true, npc_magnusson = true,
|
||||
npc_monk = true, npc_mossman = true, npc_odessa = true, npc_vortigaunt = true
|
||||
}
|
||||
|
||||
function IsFriendEntityName( victimtype )
|
||||
return FriendlyNames[ victimtype ] or false
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Is content mounted?
|
||||
IsMounted( "cstrike" )
|
||||
IsMounted( 4010 )
|
||||
-----------------------------------------------------------]]
|
||||
function IsMounted( name )
|
||||
|
||||
local games = engine.GetGames()
|
||||
|
||||
for k, v in pairs( games ) do
|
||||
|
||||
if ( !v.mounted ) then continue end
|
||||
|
||||
if ( v.depot == name ) then return true end
|
||||
if ( v.folder == name ) then return true end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Replacement for C++'s iff ? aa : bb
|
||||
-----------------------------------------------------------]]
|
||||
function Either( iff, aa, bb )
|
||||
if ( iff ) then return aa end
|
||||
return bb
|
||||
end
|
||||
|
||||
--
|
||||
-- You can use this function to add your own CLASS_ var.
|
||||
-- Adding in this way will ensure your CLASS_ doesn't collide with another
|
||||
--
|
||||
-- ie Add_NPC_Class( "MY_CLASS" )
|
||||
|
||||
function Add_NPC_Class( name )
|
||||
_G[ name ] = NUM_AI_CLASSES
|
||||
NUM_AI_CLASSES = NUM_AI_CLASSES + 1
|
||||
end
|
||||
|
||||
if ( CLIENT ) then
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Remember/Restore cursor position..
|
||||
Clientside only
|
||||
If you have a system where you hold a key to show the cursor
|
||||
Call RememberCursorPosition when the key is released and call
|
||||
RestoreCursorPosition to restore the cursor to where it was
|
||||
when the key was released.
|
||||
If you don't the cursor will appear in the middle of the screen
|
||||
-----------------------------------------------------------]]
|
||||
local StoredCursorPos = {}
|
||||
|
||||
function RememberCursorPosition()
|
||||
|
||||
local x, y = input.GetCursorPos()
|
||||
|
||||
-- If the cursor isn't visible it will return 0,0 ignore it.
|
||||
if ( x == 0 and y == 0 ) then return end
|
||||
|
||||
StoredCursorPos.x, StoredCursorPos.y = x, y
|
||||
|
||||
end
|
||||
|
||||
function RestoreCursorPosition()
|
||||
|
||||
if ( !StoredCursorPos.x || !StoredCursorPos.y ) then return end
|
||||
input.SetCursorPos( StoredCursorPos.x, StoredCursorPos.y )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- This is supposed to be clientside, but was exposed to both states for years due to a bug.
|
||||
--
|
||||
function CreateClientConVar( name, default, shouldsave, userdata, helptext, min, max )
|
||||
|
||||
local iFlags = 0
|
||||
|
||||
if ( shouldsave || shouldsave == nil ) then
|
||||
iFlags = bit.bor( iFlags, FCVAR_ARCHIVE )
|
||||
end
|
||||
|
||||
if ( userdata ) then
|
||||
iFlags = bit.bor( iFlags, FCVAR_USERINFO )
|
||||
end
|
||||
|
||||
return CreateConVar( name, default, iFlags, helptext, min, max )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convar access functions
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
local ConVarCache = {}
|
||||
|
||||
function GetConVar( name )
|
||||
local c = ConVarCache[ name ]
|
||||
if ( !c ) then
|
||||
c = GetConVar_Internal( name )
|
||||
if ( !c ) then
|
||||
return
|
||||
end
|
||||
|
||||
ConVarCache[ name ] = c
|
||||
end
|
||||
|
||||
return c
|
||||
end
|
||||
|
||||
function GetConVarNumber( name )
|
||||
if ( name == "maxplayers" ) then return game.MaxPlayers() end -- Backwards compatibility
|
||||
local c = GetConVar( name )
|
||||
return ( c and c:GetFloat() ) or 0
|
||||
end
|
||||
|
||||
function GetConVarString( name )
|
||||
if ( name == "maxplayers" ) then return tostring( game.MaxPlayers() ) end -- ew
|
||||
local c = GetConVar( name )
|
||||
return ( c and c:GetString() ) or ""
|
||||
end
|
||||
335
lua/includes/util/client.lua
Normal file
335
lua/includes/util/client.lua
Normal file
@@ -0,0 +1,335 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Get the real frame time, instead of the
|
||||
host_timescale linked frametime. This is for things
|
||||
like GUI effects. NOT FOR REAL IN GAME STUFF(!!!)
|
||||
-----------------------------------------------------------]]
|
||||
local FrameTime = 0
|
||||
local LastQuery = 0
|
||||
|
||||
function RealFrameTime() return FrameTime end
|
||||
|
||||
local function RealFrameTimeThink()
|
||||
|
||||
FrameTime = math.Clamp( SysTime() - LastQuery, 0, 0.1 )
|
||||
LastQuery = SysTime()
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Think", "RealFrameTime", RealFrameTimeThink ) -- Think is called after every frame on the client.
|
||||
|
||||
-- Make Portal 2 materials work out of the box
|
||||
matproxy.Add( {
|
||||
name = "FizzlerVortex",
|
||||
init = function( self, mat, values )
|
||||
end,
|
||||
bind = function( self, mat, ent )
|
||||
mat:SetFloat( "$flow_color_intensity", 1 )
|
||||
|
||||
-- Less than ideal, but serves as an example
|
||||
--[[local entities = {}
|
||||
for k, v in pairs( ents.FindInSphere( ent:GetPos(), ent:BoundingRadius() ) ) do
|
||||
if ( v == ent || v:GetMoveType() != MOVETYPE_VPHYSICS ) then continue end
|
||||
|
||||
table.insert( entities, v )
|
||||
end
|
||||
table.sort( entities, function( a, b ) return a:GetPos():Distance( ent:GetPos() ) < b:GetPos():Distance( ent:GetPos() ) end )
|
||||
|
||||
if ( entities[ 1 ] ) then
|
||||
mat:SetFloat( "$FLOW_VORTEX1", 1 )
|
||||
mat:SetVector( "$FLOW_VORTEX_POS1", entities[ 1 ]:GetPos() )
|
||||
else
|
||||
mat:SetFloat( "$FLOW_VORTEX1", 0 )
|
||||
end
|
||||
if ( entities[ 2 ] ) then
|
||||
mat:SetFloat( "$FLOW_VORTEX2", 1 )
|
||||
mat:SetVector( "$FLOW_VORTEX_POS2", entities[ 2 ]:GetPos() )
|
||||
else
|
||||
mat:SetFloat( "$FLOW_VORTEX2", 0 )
|
||||
end]]
|
||||
end
|
||||
} )
|
||||
|
||||
local function RenderSpawnIcon_Prop( model, pos, middle, size )
|
||||
|
||||
if ( size < 900 ) then
|
||||
size = size * ( 1 - ( size / 900 ) )
|
||||
else
|
||||
size = size * ( 1 - ( size / 4096 ) )
|
||||
end
|
||||
|
||||
size = math.Clamp( size, 5, 1000 )
|
||||
|
||||
local ViewAngle = Angle( 25, 220, 0 )
|
||||
local ViewPos = pos + ViewAngle:Forward() * size * -15
|
||||
local view = {}
|
||||
|
||||
view.fov = 4 + size * 0.04
|
||||
view.origin = ViewPos + middle
|
||||
view.znear = 1
|
||||
view.zfar = ViewPos:Distance( pos ) + size * 2
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_Ragdoll( model, pos, middle, size )
|
||||
|
||||
local at = model:GetAttachment( model:LookupAttachment( "eyes" ) )
|
||||
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
|
||||
|
||||
local ViewAngle = at.Ang + Angle( -10, 160, 0 )
|
||||
local ViewPos = at.Pos + ViewAngle:Forward() * -60 + ViewAngle:Up() * -2
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos
|
||||
view.znear = 0.1
|
||||
view.zfar = 100
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- For some TF2 ragdolls which do not have "eye" attachments
|
||||
--
|
||||
local function RenderSpawnIcon_Ragdoll_Head( model, pos, middle, size )
|
||||
|
||||
local at = model:GetAttachment( model:LookupAttachment( "head" ) )
|
||||
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
|
||||
|
||||
local ViewAngle = at.Ang + Angle( -10, 160, 0 )
|
||||
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -7 + ViewAngle:Right() * 1.5
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos
|
||||
view.znear = 0.1
|
||||
view.zfar = 100
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_Ragdoll_Facemask( model, pos, middle, size )
|
||||
|
||||
local at = model:GetAttachment( model:LookupAttachment( "facemask" ) )
|
||||
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
|
||||
|
||||
local ViewAngle = at.Ang
|
||||
ViewAngle:RotateAroundAxis( ViewAngle:Right(), -10 )
|
||||
ViewAngle:RotateAroundAxis( ViewAngle:Up(), 160 )
|
||||
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -2 + ViewAngle:Right() * -1
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos
|
||||
view.znear = 0.1
|
||||
view.zfar = 100
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_Ragdoll_Forward( model, pos, middle, size )
|
||||
|
||||
local at = model:GetAttachment( model:LookupAttachment( "forward" ) )
|
||||
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
|
||||
|
||||
local ViewAngle = at.Ang + Angle( 10, -20, 0 )
|
||||
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -1 + ViewAngle:Right() * 2.5
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos
|
||||
view.znear = 0.1
|
||||
view.zfar = 100
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_DOD( model, pos, middle, size )
|
||||
|
||||
local ViewAngle = Angle( 0, 160, 0 )
|
||||
local ViewPos = pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * 30 + ViewAngle:Right() * 2.5
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos + middle
|
||||
view.znear = 1
|
||||
view.zfar = ViewPos:Distance( pos ) + size * 2
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_CS( model, pos, middle, size )
|
||||
|
||||
local ViewAngle = Angle( 0, 160, 0 )
|
||||
local ViewPos = pos + ViewAngle:Forward() * -70 + ViewAngle:Up() * 32.4 + ViewAngle:Right() * 1.5
|
||||
local view = {}
|
||||
|
||||
view.fov = 10
|
||||
view.origin = ViewPos + middle
|
||||
view.znear = 1
|
||||
view.zfar = ViewPos:Distance( pos ) + size * 2
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
local function RenderSpawnIcon_Special( model, pos, middle, size, x, y, z )
|
||||
|
||||
local ViewAngle = Angle( 15, 140, 0 )
|
||||
local ViewPos = pos + ViewAngle:Forward() * x + ViewAngle:Up() * y + ViewAngle:Right() * z
|
||||
local view = {}
|
||||
|
||||
view.fov = 20
|
||||
view.origin = ViewPos + middle
|
||||
view.znear = 1
|
||||
view.zfar = ViewPos:Distance( pos ) + size * 2
|
||||
view.angles = ViewAngle
|
||||
|
||||
return view
|
||||
|
||||
end
|
||||
|
||||
SpawniconGenFunctions = {}
|
||||
|
||||
function PositionSpawnIcon( model, pos, noAngles )
|
||||
|
||||
local mn, mx = model:GetRenderBounds()
|
||||
local middle = ( mn + mx ) * 0.5
|
||||
local size = 0
|
||||
size = math.max( size, math.abs( mn.x ) + math.abs( mx.x ) )
|
||||
size = math.max( size, math.abs( mn.y ) + math.abs( mx.y ) )
|
||||
size = math.max( size, math.abs( mn.z ) + math.abs( mx.z ) )
|
||||
|
||||
model:SetPos( pos )
|
||||
if ( !noAngles ) then model:SetAngles( angle_zero ) end
|
||||
|
||||
local ModelName = model:GetModel()
|
||||
ModelName = string.Replace( ModelName, "--", "/" )
|
||||
ModelName = string.Replace( ModelName, "\\", "/" )
|
||||
ModelName = string.Replace( ModelName, "//", "/" )
|
||||
ModelName = string.Replace( ModelName, "\\\\", "/" )
|
||||
|
||||
local fnc = SpawniconGenFunctions[ ModelName ]
|
||||
if ( fnc ) then return fnc( model, pos, middle, size ) end
|
||||
|
||||
if ( model:LookupAttachment( "eyes" ) > 0 ) then
|
||||
return RenderSpawnIcon_Ragdoll( model, pos, middle, size )
|
||||
end
|
||||
|
||||
if ( model:LookupAttachment( "head" ) > 0 ) then
|
||||
return RenderSpawnIcon_Ragdoll_Head( model, pos, middle, size )
|
||||
end
|
||||
|
||||
-- CS:GO Player Models
|
||||
if ( model:LookupAttachment( "facemask" ) > 0 ) then
|
||||
return RenderSpawnIcon_Ragdoll_Facemask( model, pos, middle, size )
|
||||
end
|
||||
|
||||
-- CS:GO Hostages
|
||||
if ( model:LookupAttachment( "forward" ) > 0 ) then
|
||||
return RenderSpawnIcon_Ragdoll_Forward( model, pos, middle, size )
|
||||
end
|
||||
|
||||
return RenderSpawnIcon_Prop( model, pos, middle, size )
|
||||
|
||||
end
|
||||
|
||||
-- DOD Player Models
|
||||
SpawniconGenFunctions[ "models/player/american_assault.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/american_mg.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/american_rifleman.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/american_rocket.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/american_sniper.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/american_support.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_assault.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_mg.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_rifleman.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_rocket.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_sniper.mdl" ] = RenderSpawnIcon_DOD
|
||||
SpawniconGenFunctions[ "models/player/german_support.mdl" ] = RenderSpawnIcon_DOD
|
||||
|
||||
-- CS Player Models
|
||||
SpawniconGenFunctions[ "models/player/ct_gign.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/ct_sas.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/ct_urban.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/ct_gsg9.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/t_leet.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/t_phoenix.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/t_arctic.mdl" ] = RenderSpawnIcon_CS
|
||||
SpawniconGenFunctions[ "models/player/t_guerilla.mdl" ] = RenderSpawnIcon_CS
|
||||
|
||||
-- L4D Models
|
||||
SpawniconGenFunctions[ "models/infected/witch.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -40, 25, 0 ) end
|
||||
SpawniconGenFunctions[ "models/infected/smoker.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -60, 33, 10 ) end
|
||||
SpawniconGenFunctions[ "models/infected/hunter.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 26, 2 ) end
|
||||
SpawniconGenFunctions[ "models/infected/hulk.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -70, 30, 11 ) end
|
||||
SpawniconGenFunctions[ "models/infected/boomer.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 27, 0 ) end
|
||||
|
||||
SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] = function ( model, pos, middle, size )
|
||||
|
||||
local at = model:GetAttachment( model:LookupAttachment( "forward" ) )
|
||||
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
|
||||
|
||||
local ViewAngle = at.Ang + Angle( 180, 180, 0 ) + Angle( 10, -85, -85 )
|
||||
local ViewPos = at.Pos + ViewAngle:Forward() * -76 + ViewAngle:Up() * -1.5 + ViewAngle:Right() * 0
|
||||
return { fov = 10, origin = ViewPos, znear = 0.1, zfar = 200, angles = ViewAngle }
|
||||
|
||||
end
|
||||
|
||||
SpawniconGenFunctions[ "models/infected/common_female_nurse01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_female_rural01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
|
||||
|
||||
SpawniconGenFunctions[ "models/infected/common_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_test.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_morph_test.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] -- Bad start animation
|
||||
SpawniconGenFunctions[ "models/infected/common_male_fallen_survivor.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] -- Bad start animation
|
||||
|
||||
SpawniconGenFunctions[ "models/infected/common_male_baggagehandler_01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_male_pilot.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_male_rural01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_male_suit.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_military_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_police_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_patient_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_surgeon_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ] -- Bad start animation
|
||||
SpawniconGenFunctions[ "models/infected/common_tsaagent_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
SpawniconGenFunctions[ "models/infected/common_worker_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
|
||||
|
||||
-- ZPS Zombies
|
||||
SpawniconGenFunctions[ "models/zombies/zombie0/zombie0.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
SpawniconGenFunctions[ "models/zombies/zombie1/zombie1.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
SpawniconGenFunctions[ "models/zombies/zombie2/zombie2.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
SpawniconGenFunctions[ "models/zombies/zombie3/zombie3.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
SpawniconGenFunctions[ "models/zombies/zombie4/zombie4.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
SpawniconGenFunctions[ "models/zombies/zombie5/zombie5.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
|
||||
|
||||
-- L4D2
|
||||
SpawniconGenFunctions[ "models/infected/boomette.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 28, 0 ) end
|
||||
SpawniconGenFunctions[ "models/infected/charger.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -70, 14, 20 ) end
|
||||
SpawniconGenFunctions[ "models/infected/jockey.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 0, 7 ) end
|
||||
SpawniconGenFunctions[ "models/infected/spitter.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -1, 0, -70 ) end -- as good as deleted
|
||||
SpawniconGenFunctions[ "models/infected/hulk_dlc3.mdl" ] = SpawniconGenFunctions[ "models/infected/hulk.mdl" ]
|
||||
141
lua/includes/util/color.lua
Normal file
141
lua/includes/util/color.lua
Normal file
@@ -0,0 +1,141 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local COLOR = {}
|
||||
COLOR.__index = COLOR
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Register our metatable to make it accessible using FindMetaTable
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
debug.getregistry().Color = COLOR
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
To easily create a color table
|
||||
-----------------------------------------------------------]]
|
||||
function Color( r, g, b, a )
|
||||
|
||||
a = a or 255
|
||||
return setmetatable( { r = math.min( tonumber(r), 255 ), g = math.min( tonumber(g), 255 ), b = math.min( tonumber(b), 255 ), a = math.min( tonumber(a), 255 ) }, COLOR )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Change the alpha of a color
|
||||
-----------------------------------------------------------]]
|
||||
function ColorAlpha( c, a )
|
||||
|
||||
return Color( c.r, c.g, c.b, a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Checks if the given varible is a color object
|
||||
-----------------------------------------------------------]]
|
||||
function IsColor( obj )
|
||||
|
||||
return getmetatable(obj) == COLOR
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns color as a string
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:__tostring()
|
||||
|
||||
return string.format( "%d %d %d %d", self.r, self.g, self.b, self.a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Compares two colors
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:__eq( c )
|
||||
|
||||
return self.r == c.r and self.g == c.g and self.b == c.b and self.a == c.a
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Converts a color to HSL color space
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:ToHSL()
|
||||
|
||||
return ColorToHSL( self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Converts a color to HSV
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:ToHSV()
|
||||
|
||||
return ColorToHSV( self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Converts color to vector - loss of precision / alpha lost
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:ToVector()
|
||||
|
||||
return Vector( self.r / 255, self.g / 255, self.b / 255 )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Unpacks the color into four variables
|
||||
-----------------------------------------------------------]]
|
||||
function COLOR:Unpack()
|
||||
|
||||
return self.r, self.g, self.b, self.a
|
||||
|
||||
end
|
||||
|
||||
function COLOR:Lerp( target_clr, frac )
|
||||
|
||||
return Color( Lerp( frac, self.r, target_clr.r ), Lerp( frac, self.g, target_clr.g ), Lerp( frac, self.b, target_clr.b ), Lerp( frac, self.a, target_clr.a ) )
|
||||
|
||||
end
|
||||
|
||||
function COLOR:SetUnpacked( r, g, b, a )
|
||||
|
||||
self.r = r or 255
|
||||
self.g = g or 255
|
||||
self.b = b or 255
|
||||
self.a = a or 255
|
||||
|
||||
end
|
||||
|
||||
function COLOR:ToTable()
|
||||
|
||||
return { self.r, self.g, self.b, self.a }
|
||||
|
||||
end
|
||||
|
||||
local imat = FindMetaTable( "IMaterial" )
|
||||
|
||||
if ( imat.GetColor4Part ) then
|
||||
function imat:GetColor( ... )
|
||||
return Color( self:GetColor4Part( ... ) )
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- For those clients that do not have the above function yet
|
||||
-- TODO: Delete me
|
||||
local oldGetColor = imat.GetColor
|
||||
function imat:GetColor( ... )
|
||||
local tbl = oldGetColor( self, ... )
|
||||
return Color( tbl.r, tbl.g, tbl.b, tbl.a )
|
||||
end
|
||||
end
|
||||
50
lua/includes/util/javascript_util.lua
Normal file
50
lua/includes/util/javascript_util.lua
Normal file
@@ -0,0 +1,50 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function JS_Language( html )
|
||||
|
||||
html:AddFunction( "language", "Update", function( phrase )
|
||||
if ( !phrase ) then return end
|
||||
return language.GetPhrase( phrase )
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function JS_Utility( html )
|
||||
|
||||
html:AddFunction( "util", "MotionSensorAvailable", function()
|
||||
return motionsensor.IsAvailable()
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
function JS_Workshop( html )
|
||||
|
||||
html:AddFunction( "gmod", "OpenWorkshopFile", function( param ) steamworks.ViewFile( param ) end )
|
||||
html:AddFunction( "gmod", "DeleteLocal", function( param ) file.Delete( param, "MOD" ) end )
|
||||
html:AddFunction( "gmod", "FetchItems", function( namespace, cat, offset, perpage, extraTags, searchText, filter, sort )
|
||||
_G[ namespace ]:Fetch( cat, tonumber( offset ), tonumber( perpage ), string.Explode( ",", extraTags ), searchText, filter, sort )
|
||||
end )
|
||||
html:AddFunction( "gmod", "Vote", function( id, vote ) steamworks.Vote( id, tobool( vote ) ) end )
|
||||
html:AddFunction( "gmod", "SetFavorite", function( id, vote ) steamworks.SetFavorite( id, tobool( vote ) ) end )
|
||||
html:AddFunction( "gmod", "Publish", function( namespace, filePath, background ) _G[ namespace ]:Publish( filePath, background ) end )
|
||||
|
||||
// Dupes
|
||||
html:AddFunction( "gmod", "DownloadDupe", function( param ) ws_dupe:DownloadAndArm( param ) end )
|
||||
html:AddFunction( "gmod", "ArmDupe", function( param ) ws_dupe:Arm( param ) end )
|
||||
html:AddFunction( "gmod", "SaveDupe", function( param ) RunConsoleCommand( "dupe_save", "spawnmenu" ) end )
|
||||
|
||||
// Saves
|
||||
html:AddFunction( "gmod", "DownloadSave", function( param ) ws_save:DownloadAndLoad( param ) end )
|
||||
html:AddFunction( "gmod", "LoadSave", function( param ) ws_save:Load( param ) end )
|
||||
html:AddFunction( "gmod", "SaveSave", function( param ) RunConsoleCommand( "gm_save", "spawnmenu" ) end )
|
||||
|
||||
end
|
||||
103
lua/includes/util/model_database.lua
Normal file
103
lua/includes/util/model_database.lua
Normal file
@@ -0,0 +1,103 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--=============================================================================--
|
||||
-- ___ ___ _ _ _ __ _ ___ ___ __ __
|
||||
-- |_ _|| __| / \ | \_/ | / _| / \ | o \ o \\ V /
|
||||
-- | | | _| | o || \_/ | ( |_n| o || / / \ /
|
||||
-- |_| |___||_n_||_| |_| \__/|_n_||_|\\_|\\ |_| 2007
|
||||
--
|
||||
--=============================================================================--
|
||||
|
||||
local DatabasedModels = {}
|
||||
|
||||
if ( !sql.TableExists( "modelinfo" ) ) then
|
||||
|
||||
sql.Query( [[CREATE TABLE IF NOT EXISTS modelinfo ( name TEXT NOT NULL PRIMARY KEY,
|
||||
poseparams INTEGER,
|
||||
numsequences INTEGER,
|
||||
numattachments INTEGER,
|
||||
numbonecontrollers INTEGER,
|
||||
numskins INTEGER,
|
||||
size INTEGER );]] )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Called from the engine on model load to enable Lua to cache
|
||||
the model stats in a database, so that rather than building
|
||||
all in one go, they'll get updated as the player plays.
|
||||
-----------------------------------------------------------]]
|
||||
function OnModelLoaded( ModelName, NumPoseParams, NumSeq, NumAttachments, NumBoneControllers, NumSkins, Size )
|
||||
|
||||
local ModelName = string.lower( string.gsub( ModelName, "\\", "/" ) )
|
||||
ModelName = "models/".. ModelName
|
||||
|
||||
-- No need to store a model more than once per session
|
||||
if ( DatabasedModels[ ModelName ] ) then return end
|
||||
DatabasedModels[ ModelName ] = true
|
||||
|
||||
-- Just in case. Don't want errors spewing all over
|
||||
-- the place every time a model loads.
|
||||
if ( !sql.TableExists( "modelinfo" ) ) then return end
|
||||
|
||||
local safeModelName = SQLStr( ModelName )
|
||||
|
||||
--
|
||||
-- We delete the old entry because this model may have been updated.
|
||||
-- The chances are very slim, but there's no real harm in it.
|
||||
--
|
||||
sql.Query( "DELETE FROM modelinfo WHERE model = "..safeModelName )
|
||||
sql.Query( Format( [[INSERT INTO modelinfo ( name,
|
||||
poseparams,
|
||||
numsequences,
|
||||
numattachments,
|
||||
numbonecontrollers,
|
||||
numskins,
|
||||
size )
|
||||
|
||||
VALUES
|
||||
|
||||
( %s, %i, %i, %i, %i, %i, %i ) ]],
|
||||
|
||||
safeModelName,
|
||||
NumPoseParams,
|
||||
NumSeq,
|
||||
NumAttachments,
|
||||
NumBoneControllers,
|
||||
NumSkins,
|
||||
Size
|
||||
) )
|
||||
--[[
|
||||
MsgN( ModelName,
|
||||
"\nNumPoseParams: ", NumPoseParams,
|
||||
"\nNumSeq: ", NumSeq,
|
||||
"\nNumAttachments: ", NumAttachments,
|
||||
"\nNumBoneControllers: ", NumBoneControllers,
|
||||
"\nNumSkins: ", NumSkins,
|
||||
"\nSize: ", Size )
|
||||
--]]
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns the number of skins this model has. If we don't
|
||||
know, it will return 0
|
||||
-----------------------------------------------------------]]
|
||||
function NumModelSkins( ModelName )
|
||||
|
||||
local ModelName = string.lower( ModelName )
|
||||
local safeModelName = SQLStr( ModelName )
|
||||
local num = sql.QueryValue( "SELECT numskins FROM modelinfo WHERE name = " .. safeModelName )
|
||||
if ( num == nil ) then return 0 end
|
||||
|
||||
return tonumber( num ) or 0
|
||||
|
||||
end
|
||||
119
lua/includes/util/sql.lua
Normal file
119
lua/includes/util/sql.lua
Normal file
@@ -0,0 +1,119 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !sql ) then return end
|
||||
|
||||
|
||||
--[[----------------------------------------------------------
|
||||
Attempts to make a string safe to put into the database
|
||||
------------------------------------------------------------]]
|
||||
function sql.SQLStr( str_in, bNoQuotes )
|
||||
|
||||
local str = tostring( str_in )
|
||||
|
||||
str = str:gsub( "'", "''" )
|
||||
|
||||
local null_chr = string.find( str, "\0" )
|
||||
if ( null_chr ) then
|
||||
str = string.sub( str, 1, null_chr - 1 )
|
||||
end
|
||||
|
||||
if ( bNoQuotes ) then
|
||||
return str
|
||||
end
|
||||
|
||||
return "'" .. str .. "'"
|
||||
end
|
||||
|
||||
SQLStr = sql.SQLStr
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns true if the table exists. False if it doesn't
|
||||
-----------------------------------------------------------]]
|
||||
function sql.TableExists( name )
|
||||
|
||||
local r = sql.Query( "SELECT name FROM sqlite_master WHERE name=" .. SQLStr( name ) .. " AND type='table'" )
|
||||
|
||||
return r and true or false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns true if the index exists. False if it doesn't
|
||||
-----------------------------------------------------------]]
|
||||
function sql.IndexExists( name )
|
||||
|
||||
local r = sql.Query( "SELECT name FROM sqlite_master WHERE name=" .. SQLStr( name ) .. " AND type='index'" )
|
||||
|
||||
return r and true or false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Query and get a single row
|
||||
eg sql.QueryRow( "SELECT * from ratings LIMIT 1" )
|
||||
-----------------------------------------------------------]]
|
||||
function sql.QueryRow( query, row )
|
||||
|
||||
row = row or 1
|
||||
|
||||
local r = sql.Query( query )
|
||||
|
||||
if ( r ) then return r[ row ] end
|
||||
|
||||
return r
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Query and get a single value
|
||||
eg sql.QueryValue( "SELECT count(*) from ratings" )
|
||||
-----------------------------------------------------------]]
|
||||
function sql.QueryValue( query )
|
||||
|
||||
local r = sql.QueryRow( query )
|
||||
|
||||
if ( r ) then
|
||||
|
||||
-- Is this really the best way to get the first/only value in a table
|
||||
for k, v in pairs( r ) do return v end
|
||||
|
||||
end
|
||||
|
||||
return r
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Call before lots of inserts (100+), will hold off writing to disk
|
||||
until Commit is called, which will increase performance (a lot)
|
||||
-----------------------------------------------------------]]
|
||||
function sql.Begin()
|
||||
sql.Query( "BEGIN;" )
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
See Above
|
||||
-----------------------------------------------------------]]
|
||||
function sql.Commit()
|
||||
sql.Query( "COMMIT;" )
|
||||
end
|
||||
|
||||
|
||||
--[[----------------------------------------------------------
|
||||
m_strError is set by the dll
|
||||
------------------------------------------------------------]]
|
||||
function sql.LastError()
|
||||
return sql.m_strError
|
||||
end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user