This commit is contained in:
lifestorm
2024-08-04 23:54:45 +03:00
parent 0e770b2b49
commit df294d03aa
7526 changed files with 4011945 additions and 15 deletions

View 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

View 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

View 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" )

View 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

View 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

View 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

View 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

View 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

View 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

View 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 )

View 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

View 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

View 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

View 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

View 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 )

View 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

View 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

View 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

View 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

View 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

View 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

View 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 )

View 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 )

View 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

View 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

View 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

View 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 )

View 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

View 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
View 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

View 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

View 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

View 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

View 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

View 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
View 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

View 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" )

View 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/
--]]
function JBUmatTranspose3x3(matrix)
local tb = matrix:ToTable()
local tb1 = {
{tb[1][1], tb[2][1], tb[3][1], 0},
{tb[1][2], tb[2][2], tb[3][2], 0},
{tb[1][3], tb[2][3], tb[3][3], 0},
{0, 0, 0, 0},
}
return Matrix(tb1)
end
function JBUApproachVector(v1, v2, delta)
local x = math.Approach(v1.x, v2.x, delta)
local y = math.Approach(v1.y, v2.y, delta)
local z = math.Approach(v1.z, v2.z, delta)
return Vector(x,y,z)
end
function JBUFindTheEntInConstraints(_ent, _constraintname, _classname)
local tbl = {}
if(istable(_classname)) then
tbl = _classname
else
tbl[_classname] = true
end
local _const = constraint.FindConstraints(_ent, _constraintname)
for k, v in pairs(_const) do
local ent = NULL
if(tbl[v.Ent1:GetClass()]) then
ent = v.Ent1
elseif(tbl[v.Ent1:GetClass()]) then
ent = v.Ent2
end
if(IsValid(ent)) then return ent end
end
end
if(SERVER) then
__BakuVehicleTableAR3 = __BakuVehicleTableAR3 or {}
__BakuManTableAR3 = __BakuManTableAR3 or {}
__BakuRegisteredMannableClasses = __BakuRegisteredMannableClasses or {}
hook.Add("PlayerEnteredVehicle", "MannableTurretsBaku", function(ply, veh, role)
local mannedgun = __BakuManTableAR3[ply:EntIndex()]
if(IsValid(mannedgun)) then
mannedgun:AR3Deactivate()
end
local gun = __BakuVehicleTableAR3[veh:EntIndex()] or JBUFindTheEntInConstraints(veh, "Weld", __BakuRegisteredMannableClasses)
if(!IsValid(gun)) then __BakuVehicleTableAR3[veh:EntIndex()] = nil return end
gun._DriveMode = true
gun._Vehicle = veh
__BakuVehicleTableAR3[veh:EntIndex()] = gun
gun._User = ply
gun:AR3Activate()
end)
hook.Add("PlayerLeaveVehicle", "MannableTurretsBaku", function(ply, veh)
local gun = __BakuVehicleTableAR3[veh:EntIndex()] or JBUFindTheEntInConstraints(veh, "Weld", __BakuRegisteredMannableClasses)
if(!IsValid(gun)) then return end
gun:AR3Deactivate()
end)
end

19
lua/includes/menu.lua Normal file
View 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" )

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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 )

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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 )

View 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

View 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 )
--]]

View 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" )

View 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

View 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 = {
["&"] = "&amp;",
["<"] = "&lt;",
[">"] = "&gt;"
}, {
["&amp;"] = "&",
["&lt;"] = "<",
["&gt;"] = ">"
}
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

View 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

View 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 )

View 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!")

View 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

View 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" )

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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 )

View 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

View 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

View 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

View 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

View 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)]]

View 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

View 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)

View 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)

View 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

View 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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/ /g,'&nbsp;')
}
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,"&#39;")+"' 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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 } )

View 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

View 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

View 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

View 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
View 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

View 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
View 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

View 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

View 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

Some files were not shown because too many files have changed in this diff Show More