mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 13:53:45 +03:00
Upload
This commit is contained in:
28
lua/includes/extensions/angle.lua
Normal file
28
lua/includes/extensions/angle.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local meta = FindMetaTable( "Angle" )
|
||||
|
||||
-- Nothing in here, still leaving this file here just in case
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Angle Snap to nearest interval of degrees
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SnapTo( component, degrees )
|
||||
|
||||
if ( degrees == 0 ) then ErrorNoHalt( "The snap degrees must be non-zero.\n" ); return self; end
|
||||
if ( !self[ component ] ) then ErrorNoHalt( "You must choose a valid component of Angle( p || pitch, y || yaw, r || roll ) to snap such as Angle( 80, 40, 30 ):SnapTo( \"p\", 90 ):SnapTo( \"y\", 45 ):SnapTo( \"r\", 40 ); and yes, you can keep adding snaps.\n" ); return self; end
|
||||
|
||||
self[ component ] = math.Round( self[ component ] / degrees ) * degrees
|
||||
self[ component ] = math.NormalizeAngle( self[ component ] )
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
27
lua/includes/extensions/client/entity.lua
Normal file
27
lua/includes/extensions/client/entity.lua
Normal file
@@ -0,0 +1,27 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local meta = FindMetaTable( "Entity" )
|
||||
if ( !meta ) then return end
|
||||
|
||||
|
||||
--
|
||||
-- You can set the render angles and render origin on
|
||||
-- any entity. It will then render the entity at that
|
||||
-- origin using those angles.
|
||||
--
|
||||
-- Set them to nil if you don't want to override anything.
|
||||
--
|
||||
|
||||
AccessorFunc( meta, "m_RenderAngles", "RenderAngles" )
|
||||
AccessorFunc( meta, "m_RenderOrigin", "RenderOrigin" )
|
||||
24
lua/includes/extensions/client/globals.lua
Normal file
24
lua/includes/extensions/client/globals.lua
Normal file
@@ -0,0 +1,24 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
|
||||
function ScreenScale( width )
|
||||
return width * ( ScrW() / 640.0 )
|
||||
end
|
||||
|
||||
function ScreenScaleH( height )
|
||||
return height * ( ScrH() / 480.0 )
|
||||
end
|
||||
|
||||
SScale = ScreenScale
|
||||
631
lua/includes/extensions/client/panel.lua
Normal file
631
lua/includes/extensions/client/panel.lua
Normal file
@@ -0,0 +1,631 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include ( "panel/animation.lua" )
|
||||
include ( "panel/dragdrop.lua" )
|
||||
include ( "panel/selections.lua" )
|
||||
include ( "panel/scriptedpanels.lua" )
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
AccessorFunc( meta, "m_strCookieName", "CookieName" )
|
||||
|
||||
meta.SetFGColorEx = meta.SetFGColor
|
||||
meta.SetBGColorEx = meta.SetBGColor
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetFGColor
|
||||
Desc: Override to make it possible to pass Color's
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetFGColor( r, g, b, a )
|
||||
|
||||
if ( istable( r ) ) then
|
||||
return self:SetFGColorEx( r.r, r.g, r.b, r.a )
|
||||
end
|
||||
|
||||
return self:SetFGColorEx( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetBGColor
|
||||
Desc: Override to make it possible to pass Color's
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetBGColor( r, g, b, a )
|
||||
|
||||
if ( istable( r ) ) then
|
||||
return self:SetBGColorEx( r.r, r.g, r.b, r.a )
|
||||
end
|
||||
|
||||
return self:SetBGColorEx( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetHeight( h )
|
||||
self:SetSize( self:GetWide(), h )
|
||||
end
|
||||
meta.SetTall = meta.SetHeight
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetWidth( w )
|
||||
self:SetSize( w, self:GetTall() )
|
||||
end
|
||||
meta.SetWide = meta.SetWidth
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Set/GetX/Y
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetX()
|
||||
local x, y = self:GetPos()
|
||||
return x
|
||||
end
|
||||
function meta:GetY()
|
||||
local x, y = self:GetPos()
|
||||
return y
|
||||
end
|
||||
function meta:SetX( x )
|
||||
self:SetPos( x, self:GetY() )
|
||||
end
|
||||
function meta:SetY( y )
|
||||
self:SetPos( self:GetX(), y )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StretchToParent (borders)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:StretchToParent( l, u, r, d )
|
||||
|
||||
local w, h = self:GetParent():GetSize()
|
||||
|
||||
if ( l != nil ) then
|
||||
self.x = l
|
||||
end
|
||||
|
||||
if ( u != nil ) then
|
||||
self.y = u
|
||||
end
|
||||
|
||||
if ( r != nil ) then
|
||||
self:SetWide( w - self.x - r )
|
||||
end
|
||||
|
||||
if ( d != nil ) then
|
||||
self:SetTall( h - self.y - d )
|
||||
end
|
||||
|
||||
--self:SetPos( l, u )
|
||||
--self:SetSize( w - (r + l), h - (d + u) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyHeight
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyHeight( pnl )
|
||||
self:SetTall( pnl:GetTall() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyWidth
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyWidth( pnl )
|
||||
self:SetWide( pnl:GetWide() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyPos
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyPos( pnl )
|
||||
self:SetPos( pnl:GetPos() )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Align with the edge of the parent
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AlignBottom( m ) self:SetPos( self.x, self:GetParent():GetTall() - self:GetTall() - ( m or 0 ) ) end
|
||||
function meta:AlignRight( m ) self:SetPos( self:GetParent():GetWide() - self:GetWide() - ( m or 0 ), self.y ) end
|
||||
function meta:AlignTop( m ) self:SetPos( self.x, m or 0 ) end
|
||||
function meta:AlignLeft( m ) self:SetPos( m or 0, self.y ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Move relative to another panel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveAbove( pnl, m ) self:SetPos( self.x, pnl.y - self:GetTall() - ( m or 0 ) ) end
|
||||
function meta:MoveBelow( pnl, m ) self:SetPos( self.x, pnl.y + pnl:GetTall() + ( m or 0 ) ) end
|
||||
function meta:MoveRightOf( pnl, m ) self:SetPos( pnl.x + pnl:GetWide() + ( m or 0 ), self.y ) end
|
||||
function meta:MoveLeftOf( pnl, m ) self:SetPos( pnl.x - self:GetWide() - ( m or 0 ), self.y ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StretchRightTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:StretchRightTo( pnl, m ) self:SetWide( pnl.x - self.x - ( m or 0 ) ) end
|
||||
function meta:StretchBottomTo( pnl, m ) self:SetTall( pnl.y - self.y - ( m or 0 ) ) end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterVertical
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CenterVertical( fraction )
|
||||
self:SetY( self:GetParent():GetTall() * ( fraction or 0.5 ) - self:GetTall() * 0.5 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterHorizontal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CenterHorizontal( fraction )
|
||||
self:SetX( self:GetParent():GetWide() * ( fraction or 0.5 ) - self:GetWide() * 0.5 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CenterHorizontal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:Center()
|
||||
|
||||
self:CenterVertical()
|
||||
self:CenterHorizontal()
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyBounds
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CopyBounds( pnl )
|
||||
|
||||
local x, y, w, h = pnl:GetBounds()
|
||||
|
||||
self:SetPos( x, y )
|
||||
self:SetSize( w, h )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookieNumber
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetCookieName( cookiename )
|
||||
|
||||
self.m_strCookieName = cookiename
|
||||
|
||||
-- If we have a loadcookies function, call it.
|
||||
if ( self.LoadCookies ) then
|
||||
self:LoadCookies()
|
||||
self:InvalidateLayout()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookieNumber
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetCookieNumber( cookiename, default )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return default end
|
||||
|
||||
return cookie.GetNumber( name .. "." .. cookiename, default )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetCookie( cookiename, default )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return default end
|
||||
|
||||
return cookie.GetString( name .. "." .. cookiename, default )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetCookie( cookiename, value )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return end
|
||||
|
||||
return cookie.Set( name .. "." .. cookiename, value )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DeleteCookie
|
||||
-----------------------------------------------------------]]
|
||||
function meta:DeleteCookie( cookiename )
|
||||
|
||||
local name = self:GetCookieName()
|
||||
if ( !name ) then return end
|
||||
|
||||
return cookie.Delete( name .. "." .. cookiename )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: InvalidateParent
|
||||
-----------------------------------------------------------]]
|
||||
function meta:InvalidateParent( layoutnow )
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( !parent ) then return end
|
||||
if ( self.LayingOutParent ) then return end
|
||||
|
||||
self.LayingOutParent = true
|
||||
parent:InvalidateLayout( layoutnow )
|
||||
self.LayingOutParent = false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: PositionLabel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:PositionLabel( labelWidth, x, y, lbl, ctrl )
|
||||
|
||||
lbl:SetWide( labelWidth )
|
||||
lbl:SetPos( x, y )
|
||||
|
||||
ctrl.y = y
|
||||
ctrl:MoveRightOf( lbl, 0 )
|
||||
|
||||
return y + math.max( lbl:GetTall(), ctrl:GetTall() )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltip
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltip()
|
||||
return self.strTooltipText
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltipPanel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltipPanel()
|
||||
return self.pnlTooltipPanel
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetTooltipDelay
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetTooltipDelay()
|
||||
return self.numTooltipDelay
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltip
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltip( tooltip )
|
||||
self.strTooltipText = tooltip
|
||||
end
|
||||
meta.SetToolTip = meta.SetTooltip
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltipPanel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltipPanel( panel )
|
||||
self.pnlTooltipPanel = panel
|
||||
if ( IsValid( panel ) ) then panel:SetVisible( false ) end
|
||||
end
|
||||
meta.SetToolTipPanel = meta.SetTooltipPanel
|
||||
|
||||
-- Override which panel will be created instead of DTooltip
|
||||
function meta:SetTooltipPanelOverride( panel )
|
||||
self.pnlTooltipPanelOverride = panel
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTooltipDelay
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTooltipDelay( delay )
|
||||
self.numTooltipDelay = delay
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeToContentsY (Only works on Labels)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeToContentsY( addval )
|
||||
|
||||
local w, h = self:GetContentSize()
|
||||
if ( !w || !h ) then return end
|
||||
|
||||
self:SetTall( h + ( addval or 0 ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeToContentsX (Only works on Labels)
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeToContentsX( addval )
|
||||
|
||||
local w, h = self:GetContentSize()
|
||||
if ( !w || !h ) then return end
|
||||
|
||||
self:SetWide( w + ( addval or 0 ) )
|
||||
|
||||
end
|
||||
|
||||
-- Make sure all children update their skin, if SOMEHOW they cached their skin before the parent
|
||||
local function InvalidateSkinRecurse( self )
|
||||
|
||||
for id, pnl in pairs( self:GetChildren() ) do
|
||||
InvalidateSkinRecurse( pnl )
|
||||
pnl.m_iSkinIndex = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetSkin
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetSkin( strSkin )
|
||||
|
||||
if ( self.m_ForceSkinName == strSkin ) then return end
|
||||
|
||||
self.m_ForceSkinName = strSkin
|
||||
self.m_iSkinIndex = nil
|
||||
|
||||
InvalidateSkinRecurse( self )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetSkin
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetSkin()
|
||||
|
||||
local skin = nil
|
||||
|
||||
if ( derma.SkinChangeIndex() == self.m_iSkinIndex ) then
|
||||
|
||||
skin = self.m_Skin
|
||||
if ( skin ) then return skin end
|
||||
|
||||
end
|
||||
|
||||
-- We have a default skin
|
||||
if ( !skin && self.m_ForceSkinName ) then
|
||||
skin = derma.GetNamedSkin( self.m_ForceSkinName )
|
||||
end
|
||||
|
||||
-- No skin, inherit from parent
|
||||
local parent = self:GetParent()
|
||||
if ( !skin && IsValid( parent ) ) then
|
||||
skin = parent:GetSkin()
|
||||
end
|
||||
|
||||
-- Parent had no skin, use default
|
||||
if ( !skin ) then
|
||||
skin = derma.GetDefaultSkin()
|
||||
end
|
||||
|
||||
-- Save skin details on us so we don't have to keep looking up
|
||||
self.m_Skin = skin
|
||||
self.m_iSkinIndex = derma.SkinChangeIndex()
|
||||
|
||||
self:InvalidateLayout( false )
|
||||
|
||||
return skin
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ToggleVisible
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ToggleVisible()
|
||||
self:SetVisible( !self:IsVisible() )
|
||||
end
|
||||
|
||||
function meta:Distance( pnl )
|
||||
|
||||
if ( !IsValid( pnl ) ) then return 0 end
|
||||
|
||||
return self:DistanceFrom( pnl.x + pnl:GetWide() * 0.5, pnl.y + pnl:GetTall() * 0.5 )
|
||||
|
||||
end
|
||||
|
||||
function meta:DistanceFrom( x, y )
|
||||
|
||||
local x = self.x + self:GetWide() * 0.5 - x
|
||||
local y = self.y + self:GetTall() * 0.5 - y
|
||||
|
||||
return math.sqrt( x * x + y * y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Retusn the child position on this panel. Even if its parented to children of children.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetChildPosition( pnl )
|
||||
|
||||
local x = 0
|
||||
local y = 0
|
||||
|
||||
while ( IsValid( pnl ) && pnl != self ) do
|
||||
|
||||
x = x + pnl.x
|
||||
y = y + pnl.y
|
||||
|
||||
pnl = pnl:GetParent()
|
||||
|
||||
end
|
||||
|
||||
return x, y
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Returns true if the panel is valid. This does not
|
||||
check the type. If the passed object is anything other
|
||||
than a panel or nil, this will error. (speed)
|
||||
-----------------------------------------------------------]]
|
||||
function ValidPanel( pnl )
|
||||
|
||||
if ( !pnl ) then return false end
|
||||
|
||||
return pnl:IsValid()
|
||||
|
||||
end
|
||||
|
||||
function meta:InvalidateChildren( bRecurse )
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( bRecurse ) then
|
||||
v:InvalidateChildren( true )
|
||||
else
|
||||
v:InvalidateLayout( true )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:InvalidateLayout( true )
|
||||
|
||||
end
|
||||
|
||||
function meta:IsOurChild( child )
|
||||
|
||||
if ( !IsValid( child ) ) then return false end
|
||||
|
||||
return child:HasParent( self )
|
||||
|
||||
end
|
||||
|
||||
function meta:CopyBase( pnl )
|
||||
|
||||
self:CopyBounds( pnl )
|
||||
self:Dock( pnl:GetDock() )
|
||||
|
||||
// TODO. More.
|
||||
|
||||
end
|
||||
|
||||
function meta:Add( pnl )
|
||||
|
||||
if ( isstring( pnl ) ) then
|
||||
local pnl = vgui.Create( pnl, self )
|
||||
return pnl
|
||||
end
|
||||
|
||||
if ( istable( pnl ) ) then
|
||||
local pnl = vgui.CreateFromTable( pnl, self )
|
||||
return pnl
|
||||
end
|
||||
|
||||
pnl:SetParent( self )
|
||||
return pnl
|
||||
|
||||
end
|
||||
|
||||
function meta:GetClosestChild( x, y )
|
||||
|
||||
local distance = 9999
|
||||
local closest = nil
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
local dist = v:DistanceFrom( x, y )
|
||||
if ( dist < distance ) then
|
||||
distance = dist
|
||||
closest = v
|
||||
end
|
||||
end
|
||||
|
||||
return closest, distance
|
||||
|
||||
end
|
||||
|
||||
function meta:LocalCursorPos()
|
||||
return self:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
end
|
||||
|
||||
function meta:MoveToAfter( pnl )
|
||||
|
||||
local children = self:GetParent():GetChildren()
|
||||
|
||||
-- remove us from the table
|
||||
table.RemoveByValue( children, self )
|
||||
|
||||
-- find the key, where we want to be
|
||||
local key = table.KeyFromValue( children, pnl )
|
||||
|
||||
if ( key ) then
|
||||
-- insert us where we wanna be
|
||||
table.insert( children, key + 1, self )
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
for k, v in ipairs( children ) do
|
||||
v:SetZPos( k )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:MoveToBefore( pnl )
|
||||
|
||||
local children = self:GetParent():GetChildren()
|
||||
|
||||
-- remove us from the table
|
||||
table.RemoveByValue( children, self )
|
||||
|
||||
-- find the key, where we want to be
|
||||
local key = table.KeyFromValue( children, pnl )
|
||||
|
||||
if ( key ) then
|
||||
-- insert us where we wanna be
|
||||
table.insert( children, key, self )
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
||||
for k, v in ipairs( children ) do
|
||||
v:SetZPos( k )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:Clear()
|
||||
|
||||
for k, panel in ipairs( self:GetChildren() ) do
|
||||
panel:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:IsHovered()
|
||||
return vgui.GetHoveredPanel() == self
|
||||
end
|
||||
|
||||
function meta:Show()
|
||||
self:SetVisible( true )
|
||||
end
|
||||
|
||||
function meta:Hide()
|
||||
self:SetVisible( false )
|
||||
end
|
||||
|
||||
function meta:IsChildHovered( bImmediate )
|
||||
|
||||
local Hovered = vgui.GetHoveredPanel()
|
||||
if ( !IsValid( Hovered ) ) then return false end
|
||||
if ( Hovered == self ) then return false end
|
||||
|
||||
-- Check immediate child only (with support for old depth parameter)
|
||||
if ( bImmediate == true or bImmediate == 1 ) then return Hovered:GetParent() == self end
|
||||
|
||||
return Hovered:HasParent( self )
|
||||
|
||||
end
|
||||
375
lua/includes/extensions/client/panel/animation.lua
Normal file
375
lua/includes/extensions/client/panel/animation.lua
Normal file
@@ -0,0 +1,375 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetTerm
|
||||
Desc: Kill the panel at this time
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetTerm( term )
|
||||
|
||||
self.Term = SysTime() + term
|
||||
self:SetAnimationEnabled( true )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AnimationThinkInternal
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AnimationThinkInternal()
|
||||
|
||||
local systime = SysTime()
|
||||
|
||||
if ( self.Term && self.Term <= systime ) then self:Remove() return end
|
||||
if ( !self.m_AnimList ) then return end -- This can happen if we only have term
|
||||
|
||||
for k, anim in pairs( self.m_AnimList ) do
|
||||
|
||||
if ( systime >= anim.StartTime ) then
|
||||
|
||||
local Fraction = math.TimeFraction( anim.StartTime, anim.EndTime, systime )
|
||||
Fraction = math.Clamp( Fraction, 0, 1 )
|
||||
|
||||
if ( anim.Think ) then
|
||||
|
||||
local Frac = Fraction ^ anim.Ease
|
||||
|
||||
-- Ease of -1 == ease in out
|
||||
if ( anim.Ease < 0 ) then
|
||||
Frac = Fraction ^ ( 1.0 - ( ( Fraction - 0.5 ) ) )
|
||||
elseif ( anim.Ease > 0 && anim.Ease < 1 ) then
|
||||
Frac = 1 - ( ( 1 - Fraction ) ^ ( 1 / anim.Ease ) )
|
||||
end
|
||||
|
||||
anim:Think( self, Frac )
|
||||
end
|
||||
|
||||
if ( Fraction == 1 ) then
|
||||
|
||||
if ( anim.OnEnd ) then anim:OnEnd( self ) end
|
||||
|
||||
self.m_AnimList[k] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetAnimationEnabled
|
||||
Desc: Enables animations on a panel
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetAnimationEnabled( b )
|
||||
|
||||
if ( !b ) then
|
||||
self.AnimationThink = nil
|
||||
return
|
||||
end
|
||||
|
||||
if ( self.AnimationThink ) then return end
|
||||
|
||||
self.AnimationThink = self.AnimationThinkInternal
|
||||
|
||||
end
|
||||
|
||||
function meta:Stop()
|
||||
|
||||
self.m_AnimList = {}
|
||||
|
||||
end
|
||||
|
||||
function meta:Queue()
|
||||
|
||||
self.m_AnimQueue = true
|
||||
|
||||
end
|
||||
|
||||
function meta:AnimTail()
|
||||
|
||||
local last = SysTime()
|
||||
|
||||
for k, anim in pairs( self.m_AnimList ) do
|
||||
last = math.max( last, anim.EndTime )
|
||||
end
|
||||
|
||||
return last
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: NewAnimation
|
||||
Desc: Creates a new animation
|
||||
-----------------------------------------------------------]]
|
||||
function meta:NewAnimation( length, delay, ease, callback )
|
||||
|
||||
if ( delay == nil ) then delay = 0 end
|
||||
if ( ease == nil ) then ease = -1 end
|
||||
|
||||
if ( self.m_AnimQueue ) then
|
||||
|
||||
delay = delay + self:AnimTail()
|
||||
self.m_AnimQueue = false
|
||||
|
||||
else
|
||||
|
||||
delay = delay + SysTime()
|
||||
|
||||
end
|
||||
|
||||
local anim = {
|
||||
EndTime = delay + length,
|
||||
StartTime = delay,
|
||||
Ease = ease,
|
||||
OnEnd = callback
|
||||
}
|
||||
|
||||
self:SetAnimationEnabled( true )
|
||||
if ( self.m_AnimList == nil ) then self.m_AnimList = {} end
|
||||
|
||||
table.insert( self.m_AnimList, anim )
|
||||
|
||||
return anim
|
||||
|
||||
end
|
||||
|
||||
local function MoveThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartPos ) then anim.StartPos = Vector( panel.x, panel.y, 0 ) end
|
||||
local pos = LerpVector( fraction, anim.StartPos, anim.Pos )
|
||||
panel:SetPos( pos.x, pos.y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MoveTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveTo( x, y, length, delay, ease, callback )
|
||||
|
||||
if ( self.x == x && self.y == y ) then return end
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
anim.Pos = Vector( x, y, 0 )
|
||||
anim.Think = MoveThink
|
||||
|
||||
end
|
||||
|
||||
local function SizeThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartSize ) then local w, h = panel:GetSize() anim.StartSize = Vector( w, h, 0 ) end
|
||||
|
||||
local size = LerpVector( fraction, anim.StartSize, anim.Size )
|
||||
|
||||
if ( anim.SizeX && anim.SizeY ) then
|
||||
panel:SetSize( size.x, size.y )
|
||||
elseif ( anim.SizeX ) then
|
||||
panel:SetWide( size.x )
|
||||
else
|
||||
panel:SetTall( size.y )
|
||||
end
|
||||
|
||||
if ( panel:GetDock() > 0 ) then
|
||||
panel:InvalidateParent()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SizeTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SizeTo( w, h, length, delay, ease, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
|
||||
anim.SizeX = w != -1
|
||||
anim.SizeY = h != -1
|
||||
|
||||
if ( !anim.SizeX ) then w = self:GetWide() end
|
||||
if ( !anim.SizeY ) then h = self:GetTall() end
|
||||
|
||||
anim.Size = Vector( w, h, 0 )
|
||||
|
||||
anim.Think = SizeThink
|
||||
return anim
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SlideUp
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SlideUp( length )
|
||||
|
||||
local height = self:GetTall()
|
||||
local anim = self:SizeTo( -1, 0, length )
|
||||
anim.OnEnd = function()
|
||||
self:SetVisible( false )
|
||||
self:SetTall( height )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SlideDown
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SlideDown( length )
|
||||
|
||||
local height = self:GetTall()
|
||||
self:SetVisible( true )
|
||||
self:SetTall( 0 )
|
||||
|
||||
local anim = self:SizeTo( -1, height, length )
|
||||
|
||||
end
|
||||
|
||||
local function ColorThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartColor ) then anim.StartColor = panel:GetColor() end
|
||||
|
||||
panel:SetColor( Color( Lerp( fraction, anim.StartColor.r, anim.Color.r ),
|
||||
Lerp( fraction, anim.StartColor.g, anim.Color.g ),
|
||||
Lerp( fraction, anim.StartColor.b, anim.Color.b ),
|
||||
Lerp( fraction, anim.StartColor.a, anim.Color.a ) ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ColorTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ColorTo( col, length, delay, callback )
|
||||
|
||||
-- We can only use this on specific panel types!
|
||||
if ( !self.SetColor ) then return end
|
||||
if ( !self.GetColor ) then return end
|
||||
|
||||
local anim = self:NewAnimation( length, delay, nil, callback )
|
||||
anim.Color = col
|
||||
anim.Think = ColorThink
|
||||
|
||||
end
|
||||
|
||||
local function AlphaThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartAlpha ) then anim.StartAlpha = panel:GetAlpha() end
|
||||
|
||||
panel:SetAlpha( Lerp( fraction, anim.StartAlpha, anim.Alpha ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: AlphaTo
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AlphaTo( alpha, length, delay, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, nil, callback )
|
||||
anim.Alpha = alpha
|
||||
anim.Think = AlphaThink
|
||||
|
||||
end
|
||||
|
||||
local function MoveByThink( anim, panel, fraction )
|
||||
|
||||
if ( !anim.StartPos ) then
|
||||
anim.StartPos = Vector( panel.x, panel.y, 0 )
|
||||
anim.Pos = anim.StartPos + anim.Pos
|
||||
end
|
||||
|
||||
local pos = LerpVector( fraction, anim.StartPos, anim.Pos )
|
||||
panel:SetPos( pos.x, pos.y )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: MoveBy
|
||||
-----------------------------------------------------------]]
|
||||
function meta:MoveBy( x, y, length, delay, ease, callback )
|
||||
|
||||
local anim = self:NewAnimation( length, delay, ease, callback )
|
||||
anim.Pos = Vector( x, y, 0 )
|
||||
anim.Think = MoveByThink
|
||||
|
||||
end
|
||||
|
||||
-- This code is bad and will run forever, never reaching the targetpos.
|
||||
local function LerpPositions( anim, panel )
|
||||
|
||||
if ( !panel.TargetPos ) then return end
|
||||
|
||||
local Speed = FrameTime() * 100 * anim.Speed
|
||||
local Pos = Vector( panel.x, panel.y, 0 )
|
||||
local Distance = panel.TargetPos - Pos
|
||||
local Length = Distance:Length()
|
||||
|
||||
if ( anim.UseGravity && Length > 1 ) then
|
||||
Speed = Speed * ( Length * 0.1 )
|
||||
else
|
||||
Speed = Speed * 10
|
||||
end
|
||||
|
||||
if ( Length < Speed ) then
|
||||
panel:SetPosReal( panel.TargetPos.x, panel.TargetPos.y )
|
||||
panel.TargetPos = nil
|
||||
return
|
||||
end
|
||||
|
||||
Distance:Normalize()
|
||||
Distance = Pos + ( Distance * Speed )
|
||||
|
||||
panel:SetPosReal( Distance.x, Distance.y )
|
||||
|
||||
end
|
||||
|
||||
local function NewSetPos( self, x, y )
|
||||
|
||||
self.TargetPos = Vector( x, y )
|
||||
|
||||
end
|
||||
|
||||
local function NewGetPos( self )
|
||||
|
||||
return self.TargetPos.x, self.TargetPos.y
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LerpPositions
|
||||
-----------------------------------------------------------]]
|
||||
function meta:LerpPositions( speed, usegravity )
|
||||
|
||||
if ( self.SetPosReal ) then return end
|
||||
|
||||
NewSetPos( self, self:GetPos() )
|
||||
|
||||
self.SetPosReal = self.SetPos
|
||||
self.SetPos = NewSetPos
|
||||
self.GetPosReal = self.GetPos
|
||||
self.GetPos = NewGetPos
|
||||
|
||||
self.LerpAnim = self:NewAnimation( 86400 )
|
||||
self.LerpAnim.Speed = speed
|
||||
self.LerpAnim.UseGravity = usegravity
|
||||
self.LerpAnim.Think = LerpPositions
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- DisableLerp
|
||||
--
|
||||
function meta:DisableLerp()
|
||||
|
||||
self.LerpAnim = nil
|
||||
self.SetPos = self.SetPosReal
|
||||
self.GetPos = self.GetPosReal
|
||||
|
||||
end
|
||||
591
lua/includes/extensions/client/panel/dragdrop.lua
Normal file
591
lua/includes/extensions/client/panel/dragdrop.lua
Normal file
@@ -0,0 +1,591 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
dragndrop = {}
|
||||
|
||||
function dragndrop.Clear()
|
||||
|
||||
dragndrop.m_Receiver = nil
|
||||
dragndrop.m_ReceiverSlot = nil
|
||||
dragndrop.m_HoverStart = nil
|
||||
dragndrop.m_MouseCode = 0
|
||||
dragndrop.m_DragWatch = nil
|
||||
dragndrop.m_MouseX = 0
|
||||
dragndrop.m_MouseY = 0
|
||||
dragndrop.m_DraggingMain = nil
|
||||
dragndrop.m_Dragging = nil
|
||||
dragndrop.m_DropMenu = nil
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.IsDragging()
|
||||
|
||||
if ( dragndrop.m_Dragging != nil ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.HandleDroppedInGame()
|
||||
|
||||
local panel = vgui.GetHoveredPanel()
|
||||
if ( !IsValid( panel ) ) then return end
|
||||
if ( panel:GetClassName() != "CGModBase" ) then return end
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.Drop()
|
||||
|
||||
if ( dragndrop.HandleDroppedInGame() ) then
|
||||
dragndrop.StopDragging()
|
||||
return
|
||||
end
|
||||
|
||||
-- Show the menu
|
||||
if ( dragndrop.m_MouseCode == MOUSE_RIGHT && dragndrop.m_ReceiverSlot && dragndrop.m_ReceiverSlot.Menu ) then
|
||||
|
||||
local x, y = dragndrop.m_Receiver:LocalCursorPos()
|
||||
|
||||
local menu = DermaMenu()
|
||||
menu.OnRemove = function( m ) -- If user clicks outside of the menu - drop the dragging
|
||||
dragndrop.StopDragging()
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_ReceiverSlot.Menu ) do
|
||||
|
||||
menu:AddOption( v, function()
|
||||
|
||||
dragndrop.CallReceiverFunction( true, k, x, y )
|
||||
dragndrop.StopDragging()
|
||||
|
||||
end )
|
||||
|
||||
end
|
||||
|
||||
menu:Open()
|
||||
|
||||
dragndrop.m_DropMenu = menu
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
dragndrop.CallReceiverFunction( true, nil, nil, nil )
|
||||
dragndrop.StopDragging()
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.StartDragging()
|
||||
|
||||
if ( !dragndrop.m_DragWatch:IsSelected() ) then
|
||||
|
||||
dragndrop.m_Dragging = { dragndrop.m_DragWatch }
|
||||
|
||||
else
|
||||
|
||||
local canvas = dragndrop.m_DragWatch:GetSelectionCanvas()
|
||||
dragndrop.m_Dragging = {}
|
||||
|
||||
for k, v in pairs( canvas:GetSelectedChildren() ) do
|
||||
|
||||
if ( !v.m_DragSlot ) then continue end
|
||||
|
||||
table.insert( dragndrop.m_Dragging, v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
v:OnStartDragging()
|
||||
|
||||
end
|
||||
|
||||
dragndrop.m_DraggingMain = dragndrop.m_DragWatch
|
||||
dragndrop.m_DraggingMain:MouseCapture( true )
|
||||
dragndrop.m_DragWatch = nil
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.StopDragging()
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
dragndrop.m_Receiver:DragHoverEnd()
|
||||
dragndrop.m_Receiver = nil
|
||||
end
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging or {} ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
v:OnStopDragging()
|
||||
|
||||
end
|
||||
|
||||
dragndrop.Clear()
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.UpdateReceiver()
|
||||
|
||||
local hovered = vgui.GetHoveredPanel()
|
||||
local receiver = nil
|
||||
local receiverslot = nil
|
||||
|
||||
if ( IsValid( hovered ) ) then
|
||||
receiver, receiverslot = hovered:GetValidReceiverSlot()
|
||||
end
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
|
||||
if ( receiver == dragndrop.m_Receiver ) then return end
|
||||
|
||||
dragndrop.m_Receiver:DragHoverEnd()
|
||||
|
||||
end
|
||||
|
||||
if ( !IsValid( receiver ) ) then
|
||||
dragndrop.m_Receiver = nil
|
||||
dragndrop.m_ReceiverSlot = nil
|
||||
end
|
||||
|
||||
dragndrop.m_Receiver = receiver
|
||||
dragndrop.m_ReceiverSlot = receiverslot
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Return all the dragged panels that match this name
|
||||
--
|
||||
function dragndrop.GetDroppable( name )
|
||||
|
||||
if ( !name ) then return dragndrop.m_Dragging end
|
||||
if ( !dragndrop.m_Dragging ) then return end
|
||||
|
||||
local t = {}
|
||||
for id, pnl in pairs( dragndrop.m_Dragging ) do
|
||||
if ( pnl.m_DragSlot && pnl.m_DragSlot[ name ] ) then table.insert( t, pnl ) end
|
||||
end
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.CallReceiverFunction( bDoDrop, command, mx, my )
|
||||
|
||||
if ( !dragndrop.m_ReceiverSlot ) then return end
|
||||
if ( !IsValid( dragndrop.m_Receiver ) ) then return end
|
||||
|
||||
local x, y = dragndrop.m_Receiver:LocalCursorPos()
|
||||
if ( mx ) then x = mx end
|
||||
if ( my ) then y = my end
|
||||
|
||||
if ( dragndrop.m_ReceiverSlot.Func ) then
|
||||
|
||||
local droppable = dragndrop.GetDroppable( dragndrop.m_ReceiverSlot.Name )
|
||||
|
||||
dragndrop.m_ReceiverSlot.Func( dragndrop.m_Receiver, droppable, bDoDrop, command, x, y )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function dragndrop.Think()
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
--
|
||||
-- We're dragging but no mouse buttons are down..
|
||||
-- So force the drop whereever it is!
|
||||
--
|
||||
--[[if ( dragndrop.m_Dragging != nil && !input.IsMouseDown( MOUSE_LEFT ) && !input.IsMouseDown( MOUSE_RIGHT ) ) then
|
||||
dragndrop.m_Dragging:DragMouseRelease( dragndrop.m_MouseCode )
|
||||
return
|
||||
end]]
|
||||
|
||||
--
|
||||
-- We're holding down a panel, watch for start of dragging
|
||||
--
|
||||
if ( IsValid( dragndrop.m_DragWatch ) ) then
|
||||
|
||||
local dist = math.abs( dragndrop.m_MouseX - gui.MouseX() ) + math.abs( dragndrop.m_MouseY - gui.MouseY() )
|
||||
if ( dist > 20 ) then
|
||||
dragndrop.StartDragging()
|
||||
return
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( dragndrop.m_Dragging != nil ) then
|
||||
|
||||
dragndrop.HoverThink()
|
||||
dragndrop.UpdateReceiver()
|
||||
|
||||
if ( IsValid( dragndrop.m_Receiver ) ) then
|
||||
dragndrop.CallReceiverFunction( false )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "DrawOverlay", "DragNDropPaint", function()
|
||||
|
||||
if ( dragndrop.m_Dragging == nil ) then return end
|
||||
if ( dragndrop.m_DraggingMain == nil ) then return end
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
local hold_offset_x = 65535
|
||||
local hold_offset_y = 65535
|
||||
|
||||
-- Find the top, left most panel
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
hold_offset_x = math.min( hold_offset_x, v.x )
|
||||
hold_offset_y = math.min( hold_offset_y, v.y )
|
||||
|
||||
end
|
||||
|
||||
local wasEnabled = DisableClipping( true )
|
||||
|
||||
local Alpha = 0.7
|
||||
if ( IsValid( dragndrop.m_Hovered ) ) then Alpha = 0.8 end
|
||||
surface.SetAlphaMultiplier( Alpha )
|
||||
|
||||
local ox = gui.MouseX() - hold_offset_x + 8
|
||||
local oy = gui.MouseY() - hold_offset_y + 8
|
||||
|
||||
for k, v in pairs( dragndrop.m_Dragging ) do
|
||||
|
||||
if ( !IsValid( v ) ) then continue end
|
||||
|
||||
local dist = 512 - v:Distance( dragndrop.m_DraggingMain )
|
||||
|
||||
if ( dist < 0 ) then continue end
|
||||
|
||||
dist = dist / 512
|
||||
surface.SetAlphaMultiplier( Alpha * dist )
|
||||
|
||||
v.PaintingDragging = true
|
||||
v:PaintAt( ox + v.x - v:GetWide() / 2, oy + v.y - v:GetTall() / 2 ) -- fill the gap between the top left corner and the mouse position
|
||||
v.PaintingDragging = nil
|
||||
|
||||
end
|
||||
|
||||
surface.SetAlphaMultiplier( 1.0 )
|
||||
|
||||
DisableClipping( wasEnabled )
|
||||
|
||||
end )
|
||||
hook.Add( "Think", "DragNDropThink", dragndrop.Think )
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
--
|
||||
--
|
||||
-- Panel Drag n Drop Extensions
|
||||
--
|
||||
--
|
||||
--
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
--
|
||||
-- Make this panel droppable
|
||||
--
|
||||
function meta:Droppable( name )
|
||||
|
||||
self.m_DragSlot = self.m_DragSlot or {}
|
||||
|
||||
self.m_DragSlot[ name ] = {}
|
||||
|
||||
return self.m_DragSlot[ name ]
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Make this pannel a drop target
|
||||
--
|
||||
function meta:Receiver( name, func, menu )
|
||||
|
||||
self.m_ReceiverSlot = self.m_ReceiverSlot or {}
|
||||
|
||||
self.m_ReceiverSlot[ name ] = {}
|
||||
self.m_ReceiverSlot[ name ].Name = name
|
||||
self.m_ReceiverSlot[ name ].Func = func
|
||||
self.m_ReceiverSlot[ name ].Menu = menu
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Drag parent means that when we start to
|
||||
-- drag this panel, we'll really start
|
||||
-- dragging the defined parent
|
||||
--
|
||||
function meta:SetDragParent( parent )
|
||||
self.m_pDragParent = parent
|
||||
end
|
||||
|
||||
function meta:GetValidReceiverSlot()
|
||||
|
||||
if ( self.m_ReceiverSlot ) then
|
||||
|
||||
-- Find matching slot..
|
||||
for k, v in pairs( self.m_ReceiverSlot ) do
|
||||
|
||||
if ( !dragndrop.m_DraggingMain.m_DragSlot ) then continue end
|
||||
|
||||
local slot = dragndrop.m_DraggingMain.m_DragSlot[ k ]
|
||||
if ( !slot ) then continue end
|
||||
|
||||
return self, v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( !IsValid( self:GetParent() ) ) then
|
||||
return false
|
||||
end
|
||||
|
||||
return self:GetParent():GetValidReceiverSlot()
|
||||
|
||||
end
|
||||
|
||||
function meta:IsDraggable()
|
||||
|
||||
return self.m_DragSlot != nil
|
||||
|
||||
end
|
||||
|
||||
function meta:IsDragging()
|
||||
|
||||
if ( !self.m_DragSlot ) then return false end
|
||||
|
||||
return self.Dragging
|
||||
|
||||
end
|
||||
|
||||
function meta:DroppedOn( pnl )
|
||||
-- For override.
|
||||
end
|
||||
|
||||
function meta:OnDrop()
|
||||
|
||||
-- We're being dropped on something
|
||||
-- we can create a new panel here and return it, so that instead of
|
||||
-- dropping us - it drops the new panel instead! We remain where we are!
|
||||
|
||||
-- By default we return ourself
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
function meta:OnStartDragging()
|
||||
|
||||
self.Dragging = true
|
||||
self:InvalidateLayout()
|
||||
|
||||
if ( self:IsSelectable() ) then
|
||||
|
||||
local canvas = self:GetSelectionCanvas()
|
||||
|
||||
if ( IsValid( canvas ) && !self:IsSelected() ) then
|
||||
canvas:UnselectAll()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:OnStopDragging()
|
||||
self.Dragging = false
|
||||
end
|
||||
|
||||
function meta:DragMousePress( mcode )
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
if ( dragndrop.IsDragging() ) then dragndrop.StopDragging() return end
|
||||
|
||||
if ( IsValid( self.m_pDragParent ) and self.m_pDragParent ~= self ) then
|
||||
return self.m_pDragParent:DragMousePress( mcode )
|
||||
end
|
||||
|
||||
if ( !self.m_DragSlot ) then return end
|
||||
|
||||
dragndrop.Clear()
|
||||
dragndrop.m_MouseCode = mcode
|
||||
dragndrop.m_DragWatch = self
|
||||
dragndrop.m_MouseX = gui.MouseX()
|
||||
dragndrop.m_MouseY = gui.MouseY()
|
||||
|
||||
end
|
||||
|
||||
function meta:DragClick( mcode )
|
||||
|
||||
self:MouseCapture( true )
|
||||
-- Clicking one mouse button while dragging with another!
|
||||
-- Return true to stop us clicking and selecting stuff below..
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function meta:DragMouseRelease( mcode )
|
||||
|
||||
if ( IsValid( dragndrop.m_DropMenu ) ) then return end
|
||||
|
||||
-- This wasn't the button we clicked with - so don't release drag
|
||||
if ( dragndrop.IsDragging() && dragndrop.m_MouseCode != mcode ) then
|
||||
|
||||
return self:DragClick( mcode )
|
||||
|
||||
end
|
||||
|
||||
if ( !dragndrop.IsDragging() ) then
|
||||
dragndrop.Clear()
|
||||
return false
|
||||
end
|
||||
|
||||
dragndrop.Drop()
|
||||
|
||||
-- Todo.. we should only do this if we enabled it!
|
||||
if ( gui.EnableScreenClicker ) then
|
||||
gui.EnableScreenClicker( false )
|
||||
end
|
||||
|
||||
self:MouseCapture( false )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
function meta:SetDropTarget( x, y, w, h )
|
||||
|
||||
if ( !self.m_bDrawingPaintOver ) then
|
||||
self.m_OldPaintOver = self.PaintOver
|
||||
self.m_bDrawingPaintOver = true
|
||||
end
|
||||
|
||||
self.PaintOver = function()
|
||||
|
||||
if ( self.m_OldPaintOver ) then
|
||||
self:m_OldPaintOver()
|
||||
end
|
||||
|
||||
self:DrawDragHover( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Drag Hover
|
||||
--
|
||||
-- These functions are used for things like trees
|
||||
-- So that when you hover over the tree while dragging something
|
||||
-- it will open up the tree. This works regardless of whether the
|
||||
-- is droppable or not.
|
||||
--
|
||||
-- Implement DragHoverClick in your panel class to get this functionality
|
||||
--
|
||||
function meta:DragHover( HoverTime )
|
||||
|
||||
--
|
||||
-- Call DragHoverClick if we've been hovering for 0.1 seconds..
|
||||
--
|
||||
if ( HoverTime < 0.1 ) then dragndrop.m_bHoverClick = false end
|
||||
if ( HoverTime > 0.1 && !dragndrop.m_bHoverClick ) then
|
||||
|
||||
self:DragHoverClick( HoverTime )
|
||||
dragndrop.m_bHoverClick = true
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:DrawDragHover( x, y, w, h )
|
||||
|
||||
DisableClipping( true )
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 100 )
|
||||
surface.DrawRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 220, 255, 230 )
|
||||
surface.DrawOutlinedRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 100, 255, 50 )
|
||||
surface.DrawOutlinedRect( x - 1, y - 1, w + 2, h + 2 )
|
||||
|
||||
DisableClipping( false )
|
||||
|
||||
end
|
||||
|
||||
function meta:DragHoverEnd()
|
||||
|
||||
if ( !self.m_bDrawingPaintOver ) then return end
|
||||
|
||||
self.PaintOver = self.m_OldPaintOver
|
||||
self.m_bDrawingPaintOver = false
|
||||
|
||||
end
|
||||
|
||||
function meta:DragHoverClick( HoverTime )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--
|
||||
--
|
||||
-- This is called to open stuff when you're hovering over it.
|
||||
--
|
||||
--
|
||||
|
||||
local LastHoverThink = nil
|
||||
local LastHoverChangeTime = 0
|
||||
local LastX = 0
|
||||
local LastY = 0
|
||||
|
||||
function dragndrop.HoverThink()
|
||||
|
||||
local hovered = vgui.GetHoveredPanel()
|
||||
local x = gui.MouseX()
|
||||
local y = gui.MouseY()
|
||||
|
||||
-- Hovering a different panel
|
||||
if ( LastHoverThink != hovered or x != LastX or y != LastY ) then
|
||||
|
||||
LastHoverChangeTime = SysTime()
|
||||
LastHoverThink = hovered
|
||||
|
||||
end
|
||||
|
||||
-- Hovered panel might do stuff when we're hovering it
|
||||
-- so give it a chance to do that now.
|
||||
if ( IsValid( LastHoverThink ) ) then
|
||||
|
||||
LastX = x
|
||||
LastY = y
|
||||
LastHoverThink:DragHover( SysTime() - LastHoverChangeTime )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
139
lua/includes/extensions/client/panel/scriptedpanels.lua
Normal file
139
lua/includes/extensions/client/panel/scriptedpanels.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local PanelFactory = {}
|
||||
|
||||
local panel_metatable = FindMetaTable( "Panel" )
|
||||
|
||||
baseclass.Set( "Panel", panel_metatable )
|
||||
baseclass.Set( "Label", panel_metatable )
|
||||
baseclass.Set( "EditablePanel", panel_metatable )
|
||||
|
||||
-- Keep the old function
|
||||
vgui.CreateX = vgui.Create
|
||||
|
||||
function vgui.GetControlTable( classname )
|
||||
return PanelFactory[ classname ]
|
||||
end
|
||||
|
||||
function vgui.Exists( classname )
|
||||
return PanelFactory[ classname ] != nil
|
||||
end
|
||||
|
||||
function vgui.Create( classname, parent, name )
|
||||
|
||||
-- Is this a user-created panel?
|
||||
if ( PanelFactory[ classname ] ) then
|
||||
|
||||
local metatable = PanelFactory[ classname ]
|
||||
|
||||
local panel = vgui.Create( metatable.Base, parent, name or classname )
|
||||
if ( !panel ) then
|
||||
Error( "Tried to create panel with invalid base '" .. metatable.Base .. "'\n" );
|
||||
end
|
||||
|
||||
table.Merge( panel:GetTable(), metatable )
|
||||
panel.BaseClass = PanelFactory[ metatable.Base ]
|
||||
panel.ClassName = classname
|
||||
|
||||
-- Call the Init function if we have it
|
||||
if ( panel.Init ) then
|
||||
panel:Init()
|
||||
end
|
||||
|
||||
panel:Prepare()
|
||||
|
||||
return panel
|
||||
|
||||
end
|
||||
|
||||
return vgui.CreateX( classname, parent, name or classname )
|
||||
|
||||
end
|
||||
|
||||
function vgui.CreateFromTable( metatable, parent, name )
|
||||
|
||||
if ( !istable( metatable ) ) then return nil end
|
||||
|
||||
local panel = vgui.Create( metatable.Base, parent, name )
|
||||
|
||||
table.Merge( panel:GetTable(), metatable )
|
||||
panel.BaseClass = PanelFactory[ metatable.Base ]
|
||||
|
||||
-- Call the Init function if we have it
|
||||
if ( panel.Init ) then
|
||||
panel:Init()
|
||||
end
|
||||
|
||||
panel:Prepare()
|
||||
|
||||
return panel
|
||||
|
||||
end
|
||||
|
||||
function vgui.Register( classname, mtable, base )
|
||||
|
||||
-- Remove the global
|
||||
PANEL = nil
|
||||
|
||||
-- Default base is Panel
|
||||
mtable.Base = base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
PanelFactory[ classname ] = mtable
|
||||
baseclass.Set( classname, mtable )
|
||||
|
||||
local mt = {}
|
||||
mt.__index = function( t, k )
|
||||
|
||||
if ( PanelFactory[ mtable.Base ] && PanelFactory[ mtable.Base ][k] ) then return PanelFactory[ mtable.Base ][k] end
|
||||
return panel_metatable[k]
|
||||
|
||||
end
|
||||
|
||||
setmetatable( mtable, mt )
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
|
||||
function vgui.RegisterTable( mtable, base )
|
||||
|
||||
-- Remove the global
|
||||
PANEL = nil
|
||||
|
||||
mtable.Base = base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
|
||||
function vgui.RegisterFile( filename )
|
||||
|
||||
local OldPanel = PANEL
|
||||
|
||||
PANEL = {}
|
||||
|
||||
-- The included file should fill the PANEL global.
|
||||
include( filename )
|
||||
|
||||
local mtable = PANEL
|
||||
PANEL = OldPanel
|
||||
|
||||
mtable.Base = mtable.Base or "Panel"
|
||||
mtable.Init = mtable.Init or function() end
|
||||
|
||||
return mtable
|
||||
|
||||
end
|
||||
259
lua/includes/extensions/client/panel/selections.lua
Normal file
259
lua/includes/extensions/client/panel/selections.lua
Normal file
@@ -0,0 +1,259 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
local StartX = 0
|
||||
local StartY = 0
|
||||
local SelectionCanvas = nil
|
||||
|
||||
local meta = FindMetaTable( "Panel" )
|
||||
|
||||
function meta:SetSelectionCanvas( bSet )
|
||||
|
||||
self.m_bSelectionCanvas = bSet
|
||||
self:SetMouseInputEnabled( true )
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelectionCanvas()
|
||||
|
||||
return self.m_bSelectionCanvas
|
||||
|
||||
end
|
||||
|
||||
function meta:SetSelectable( bSet )
|
||||
|
||||
self.m_bSelectable = bSet
|
||||
|
||||
end
|
||||
|
||||
function meta:ToggleSelection()
|
||||
|
||||
self:SetSelected( !self.m_bSelected )
|
||||
|
||||
end
|
||||
|
||||
function meta:UnselectAll()
|
||||
|
||||
self:SetSelected( false )
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
v:UnselectAll()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
function meta:SetSelected( bSet )
|
||||
|
||||
if ( self.m_bSelected == bSet ) then return end
|
||||
|
||||
self.m_bSelected = bSet
|
||||
|
||||
if ( self.ApplySchemeSettings ) then
|
||||
self:ApplySchemeSettings()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelected( bSet )
|
||||
|
||||
if ( !self:IsSelectable() ) then return false end
|
||||
return self.m_bSelected == true
|
||||
|
||||
end
|
||||
|
||||
function meta:IsSelectable()
|
||||
|
||||
return self.m_bSelectable == true
|
||||
|
||||
end
|
||||
|
||||
local function GetSelectionRect()
|
||||
|
||||
if ( !SelectionCanvas ) then
|
||||
debug.Trace()
|
||||
return
|
||||
end
|
||||
|
||||
local CurX, CurY = SelectionCanvas:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
|
||||
local x = math.min( CurX, StartX )
|
||||
local y = math.min( CurY, StartY )
|
||||
|
||||
local w = math.abs( CurX - StartX )
|
||||
local h = math.abs( CurY - StartY )
|
||||
|
||||
return x, y, w, h
|
||||
|
||||
end
|
||||
|
||||
function meta:DrawSelections()
|
||||
|
||||
if ( !self.m_bSelectable ) then return end
|
||||
if ( !self.m_bSelected ) then return end
|
||||
|
||||
local w, h = self:GetSize()
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 100 )
|
||||
surface.DrawRect( 0, 0, w, h )
|
||||
|
||||
end
|
||||
|
||||
local function PaintSelectionBox( self )
|
||||
|
||||
if ( !IsValid( SelectionCanvas ) ) then return end
|
||||
local x, y, w, h = GetSelectionRect()
|
||||
|
||||
surface.SetDrawColor( 255, 0, 255, 50 )
|
||||
surface.DrawRect( x, y, w, h )
|
||||
|
||||
surface.SetDrawColor( 255, 200, 255, 200 )
|
||||
surface.DrawOutlinedRect( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
function meta:GetSelectionCanvas()
|
||||
|
||||
if ( !self.m_bSelectionCanvas ) then
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( IsValid( parent ) ) then
|
||||
return parent:GetSelectionCanvas()
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
return self
|
||||
|
||||
end
|
||||
|
||||
|
||||
function meta:StartBoxSelection()
|
||||
|
||||
if ( !self.m_bSelectionCanvas ) then
|
||||
|
||||
local parent = self:GetParent()
|
||||
if ( IsValid( parent ) ) then
|
||||
return parent:StartBoxSelection()
|
||||
end
|
||||
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
self:MouseCapture( true )
|
||||
|
||||
if ( !input.IsShiftDown() && !input.IsControlDown() ) then
|
||||
self:UnselectAll()
|
||||
end
|
||||
|
||||
SelectionCanvas = self
|
||||
|
||||
StartX, StartY = self:ScreenToLocal( gui.MouseX(), gui.MouseY() )
|
||||
|
||||
self.PaintOver_Old = self.PaintOver
|
||||
self.PaintOver = PaintSelectionBox
|
||||
|
||||
end
|
||||
|
||||
function meta:GetChildrenInRect( x, y, w, h )
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
local vw, vh = v:GetSize()
|
||||
|
||||
if ( !self:IsVisible() ) then continue end
|
||||
if ( x > v.x + vw ) then continue end
|
||||
if ( y > v.y + vh ) then continue end
|
||||
if ( v.x > x + w ) then continue end
|
||||
if ( v.y > y + h ) then continue end
|
||||
|
||||
if ( v.m_bSelectable ) then
|
||||
table.insert( tab, v )
|
||||
end
|
||||
|
||||
table.Add( tab, v:GetChildrenInRect( x - v.x, y - v.y, w, h ) )
|
||||
|
||||
end
|
||||
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function meta:GetSelectedChildren()
|
||||
|
||||
local tab = {}
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( v:IsSelected() ) then
|
||||
table.insert( tab, v )
|
||||
end
|
||||
|
||||
table.Add( tab, v:GetSelectedChildren() )
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
function meta:NumSelectedChildren()
|
||||
|
||||
local i = 0
|
||||
|
||||
for k, v in ipairs( self:GetChildren() ) do
|
||||
|
||||
if ( v:IsSelected() ) then
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return i
|
||||
|
||||
end
|
||||
|
||||
function meta:EndBoxSelection()
|
||||
|
||||
if ( SelectionCanvas != self ) then return false end
|
||||
|
||||
self:MouseCapture( false )
|
||||
|
||||
self.PaintOver = self.PaintOver_Old
|
||||
self.PaintOver_Old = nil
|
||||
|
||||
for k, v in ipairs( self:GetChildrenInRect( GetSelectionRect() ) ) do
|
||||
|
||||
-- If player is holding shift, add new planels to existing selections, do not toggle
|
||||
-- This mimics already familiar behavior of Windows Explorer, etc
|
||||
if ( input.IsShiftDown() ) then
|
||||
v:SetSelected( true )
|
||||
else
|
||||
v:ToggleSelection()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
SelectionCanvas = nil
|
||||
StartX, StartY = 0, 0
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
86
lua/includes/extensions/client/player.lua
Normal file
86
lua/includes/extensions/client/player.lua
Normal file
@@ -0,0 +1,86 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( SERVER ) then return end
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
|
||||
|
||||
local playerOptions = {}
|
||||
local bindTranslation = {}
|
||||
bindTranslation["slot1"] = 1
|
||||
bindTranslation["slot2"] = 2
|
||||
bindTranslation["slot3"] = 3
|
||||
bindTranslation["slot4"] = 4
|
||||
bindTranslation["slot5"] = 5
|
||||
bindTranslation["slot6"] = 6
|
||||
bindTranslation["slot7"] = 7
|
||||
bindTranslation["slot8"] = 8
|
||||
bindTranslation["slot9"] = 9
|
||||
bindTranslation["slot0"] = 0
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: PlayerOption
|
||||
Params: <name> <timeout> <input function> <draw function>
|
||||
Desc:
|
||||
-----------------------------------------------------------]]
|
||||
function meta:AddPlayerOption( name, timeout, in_func, draw_func )
|
||||
|
||||
local option = {}
|
||||
option.timeout = timeout
|
||||
option.in_func = in_func
|
||||
option.draw_func = draw_func
|
||||
|
||||
if (timeout != -1) then
|
||||
option.timeout = CurTime() + timeout
|
||||
end
|
||||
|
||||
playerOptions[ name ] = option
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function hook_PlayerOptionInput( pl, bind, down )
|
||||
|
||||
if (!down || !bindTranslation[bind]) then return end
|
||||
|
||||
for k, v in pairs( playerOptions ) do
|
||||
|
||||
if ( v.timeout == -1 || v.timeout > CurTime() ) then
|
||||
|
||||
-- If the function returns true then remove this player option
|
||||
if ( v.in_func( bindTranslation[bind] ) ) then
|
||||
playerOptions[k] = nil
|
||||
end
|
||||
|
||||
return true
|
||||
else
|
||||
playerOptions[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PlayerBindPress", "PlayerOptionInput", hook_PlayerOptionInput )
|
||||
|
||||
local function hook_PlayerOptionDraw()
|
||||
|
||||
for k, v in pairs( playerOptions ) do
|
||||
|
||||
if (v.draw_func) then v.draw_func() end
|
||||
return
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "HUDPaint", "PlayerOptionDraw", hook_PlayerOptionDraw )
|
||||
209
lua/includes/extensions/client/render.lua
Normal file
209
lua/includes/extensions/client/render.lua
Normal file
@@ -0,0 +1,209 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- We don't want this to run in menu state, and render.GetAmbientLightColor doesn't exist in menu state
|
||||
if ( !render || !render.GetAmbientLightColor ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Short aliases for stencil constants
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
STENCIL_NEVER = STENCILCOMPARISONFUNCTION_NEVER
|
||||
STENCIL_LESS = STENCILCOMPARISONFUNCTION_LESS
|
||||
STENCIL_EQUAL = STENCILCOMPARISONFUNCTION_EQUAL
|
||||
STENCIL_LESSEQUAL = STENCILCOMPARISONFUNCTION_LESSEQUAL
|
||||
STENCIL_GREATER = STENCILCOMPARISONFUNCTION_GREATER
|
||||
STENCIL_NOTEQUAL = STENCILCOMPARISONFUNCTION_NOTEQUAL
|
||||
STENCIL_GREATEREQUAL = STENCILCOMPARISONFUNCTION_GREATEREQUAL
|
||||
STENCIL_ALWAYS = STENCILCOMPARISONFUNCTION_ALWAYS
|
||||
|
||||
STENCIL_KEEP = STENCILOPERATION_KEEP
|
||||
STENCIL_ZERO = STENCILOPERATION_ZERO
|
||||
STENCIL_REPLACE = STENCILOPERATION_REPLACE
|
||||
STENCIL_INCRSAT = STENCILOPERATION_INCRSAT
|
||||
STENCIL_DECRSAT = STENCILOPERATION_DECRSAT
|
||||
STENCIL_INVERT = STENCILOPERATION_INVERT
|
||||
STENCIL_INCR = STENCILOPERATION_INCR
|
||||
STENCIL_DECR = STENCILOPERATION_DECR
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ClearRenderTarget
|
||||
Params: <texture> <color>
|
||||
Desc: Clear a render target
|
||||
-----------------------------------------------------------]]
|
||||
function render.ClearRenderTarget( rt, color )
|
||||
|
||||
local OldRT = render.GetRenderTarget();
|
||||
render.SetRenderTarget( rt )
|
||||
render.Clear( color.r, color.g, color.b, color.a )
|
||||
render.SetRenderTarget( OldRT )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SupportsHDR
|
||||
Params:
|
||||
Desc: Return true if the client supports HDR
|
||||
-----------------------------------------------------------]]
|
||||
function render.SupportsHDR( )
|
||||
|
||||
if ( render.GetDXLevel() < 80 ) then return false end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyTexture
|
||||
Params: <texture from> <texture to>
|
||||
Desc: Copy the contents of one texture to another
|
||||
-----------------------------------------------------------]]
|
||||
function render.CopyTexture( from, to )
|
||||
|
||||
local OldRT = render.GetRenderTarget();
|
||||
|
||||
render.SetRenderTarget( from )
|
||||
render.CopyRenderTargetToTexture( to )
|
||||
|
||||
render.SetRenderTarget( OldRT )
|
||||
|
||||
end
|
||||
|
||||
local matColor = Material( "color" )
|
||||
|
||||
function render.SetColorMaterial()
|
||||
render.SetMaterial( matColor )
|
||||
end
|
||||
|
||||
local matColorIgnoreZ = Material( "color_ignorez" )
|
||||
|
||||
function render.SetColorMaterialIgnoreZ()
|
||||
render.SetMaterial( matColorIgnoreZ )
|
||||
end
|
||||
|
||||
local mat_BlurX = Material( "pp/blurx" )
|
||||
local mat_BlurY = Material( "pp/blury" )
|
||||
local tex_Bloom1 = render.GetBloomTex1()
|
||||
|
||||
function render.BlurRenderTarget( rt, sizex, sizey, passes )
|
||||
|
||||
mat_BlurX:SetTexture( "$basetexture", rt )
|
||||
mat_BlurY:SetTexture( "$basetexture", tex_Bloom1 )
|
||||
mat_BlurX:SetFloat( "$size", sizex )
|
||||
mat_BlurY:SetFloat( "$size", sizey )
|
||||
|
||||
for i=1, passes+1 do
|
||||
|
||||
render.SetRenderTarget( tex_Bloom1 )
|
||||
render.SetMaterial( mat_BlurX )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
render.SetRenderTarget( rt )
|
||||
render.SetMaterial( mat_BlurY )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function cam.Start2D()
|
||||
|
||||
return cam.Start( { type = '2D' } )
|
||||
|
||||
end
|
||||
|
||||
function cam.Start3D( pos, ang, fov, x, y, w, h, znear, zfar )
|
||||
|
||||
local tab = {}
|
||||
|
||||
tab.type = '3D';
|
||||
tab.origin = pos
|
||||
tab.angles = ang
|
||||
|
||||
if ( fov != nil ) then tab.fov = fov end
|
||||
|
||||
if ( x != nil && y != nil && w != nil && h != nil ) then
|
||||
|
||||
tab.x = x
|
||||
tab.y = y
|
||||
tab.w = w
|
||||
tab.h = h
|
||||
tab.aspect = ( w / h )
|
||||
|
||||
end
|
||||
|
||||
if ( znear != nil && zfar != nil ) then
|
||||
|
||||
tab.znear = znear
|
||||
tab.zfar = zfar
|
||||
|
||||
end
|
||||
|
||||
return cam.Start( tab )
|
||||
|
||||
end
|
||||
|
||||
local matFSB = Material( "pp/motionblur" )
|
||||
|
||||
function render.DrawTextureToScreen( tex )
|
||||
|
||||
matFSB:SetFloat( "$alpha", 1.0 )
|
||||
matFSB:SetTexture( "$basetexture", tex )
|
||||
|
||||
render.SetMaterial( matFSB )
|
||||
render.DrawScreenQuad()
|
||||
|
||||
end
|
||||
|
||||
function render.DrawTextureToScreenRect( tex, x, y, w, h )
|
||||
|
||||
matFSB:SetFloat( "$alpha", 1.0 )
|
||||
matFSB:SetTexture( "$basetexture", tex )
|
||||
|
||||
render.SetMaterial( matFSB )
|
||||
render.DrawScreenQuadEx( x, y, w, h )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- This isn't very fast. If you're doing something every frame you should find a way to
|
||||
-- cache a ClientsideModel and keep it around! This is fine for rendering to a render
|
||||
-- target once - or something.
|
||||
--
|
||||
|
||||
function render.Model( tbl, ent )
|
||||
|
||||
local inent = ent
|
||||
|
||||
if ( ent == nil ) then
|
||||
ent = ClientsideModel( tbl.model or "error.mdl", RENDERGROUP_OTHER )
|
||||
end
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
ent:SetModel( tbl.model or "error.mdl" )
|
||||
ent:SetNoDraw( true )
|
||||
|
||||
ent:SetPos( tbl.pos or vector_origin )
|
||||
ent:SetAngles( tbl.angle or angle_zero )
|
||||
ent:DrawModel()
|
||||
|
||||
--
|
||||
-- If we created the model, then remove it!
|
||||
--
|
||||
if ( inent != ent ) then
|
||||
ent:Remove()
|
||||
end
|
||||
|
||||
end
|
||||
36
lua/includes/extensions/coroutine.lua
Normal file
36
lua/includes/extensions/coroutine.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- The client needs this file
|
||||
--
|
||||
AddCSLuaFile()
|
||||
|
||||
if ( !coroutine ) then return end
|
||||
|
||||
--
|
||||
-- Name: coroutine.wait
|
||||
-- Desc: Yield's the coroutine for so many seconds before returning.\n\nThis should only be called in a coroutine. This function uses CurTime() - not RealTime().
|
||||
-- Arg1: number|seconds|The number of seconds to wait
|
||||
-- Ret1:
|
||||
--
|
||||
function coroutine.wait( seconds )
|
||||
|
||||
local endtime = CurTime() + seconds
|
||||
while ( true ) do
|
||||
|
||||
if ( endtime < CurTime() ) then return end
|
||||
|
||||
coroutine.yield()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
61
lua/includes/extensions/debug.lua
Normal file
61
lua/includes/extensions/debug.lua
Normal file
@@ -0,0 +1,61 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
if ( !debug ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Trace
|
||||
Desc: Dumps a trace to the console..
|
||||
|
||||
Trace:
|
||||
1: Line 21 "Trace" includes/extensions/debug.lua
|
||||
2: Line 222 "WriteTable" includes/modules/saverestore.lua
|
||||
3: Line 170 "WriteVar" includes/modules/saverestore.lua
|
||||
4: Line 259 "WriteTable" includes/modules/saverestore.lua
|
||||
5: Line 170 "WriteVar" includes/modules/saverestore.lua
|
||||
6: Line 259 "WriteTable" includes/modules/saverestore.lua
|
||||
7: Line 272 "Func" includes/extensions/entity_networkvars.lua
|
||||
8: Line 396 "(null)" includes/modules/saverestore.lua
|
||||
|
||||
This trace shows that the function was called from the engine (line 8) in save restore.
|
||||
Save restore then called something in entity_networkvars for some reason. Then
|
||||
that function called WriteTable(6), which called other functions until it got to the trace
|
||||
in 1 which was called by WriteTable in saverestore.lua
|
||||
|
||||
-----------------------------------------------------------]]
|
||||
function debug.Trace()
|
||||
|
||||
local level = 1
|
||||
|
||||
Msg( "\nTrace:\n" )
|
||||
|
||||
while true do
|
||||
|
||||
local info = debug.getinfo( level, "Sln" )
|
||||
if ( !info ) then break end
|
||||
|
||||
if ( info.what ) == "C" then
|
||||
|
||||
Msg( string.format( "\t%i: C function\t\"%s\"\n", level, info.name ) )
|
||||
|
||||
else
|
||||
|
||||
Msg( string.format( "\t%i: Line %d\t\"%s\"\t\t%s\n", level, info.currentline, info.name, info.short_src ) )
|
||||
|
||||
end
|
||||
|
||||
level = level + 1
|
||||
|
||||
end
|
||||
|
||||
Msg( "\n" )
|
||||
|
||||
end
|
||||
698
lua/includes/extensions/entity.lua
Normal file
698
lua/includes/extensions/entity.lua
Normal file
@@ -0,0 +1,698 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
function meta:GetShouldPlayPickupSound()
|
||||
return self.m_bPlayPickupSound or false
|
||||
end
|
||||
|
||||
function meta:SetShouldPlayPickupSound( bPlaySound )
|
||||
self.m_bPlayPickupSound = tobool( bPlaySound ) or false
|
||||
end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[ key ]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = self:GetTable()
|
||||
if ( tab ) then
|
||||
local tabval = tab[ key ]
|
||||
if ( tabval != nil ) then return tabval end
|
||||
end
|
||||
|
||||
--
|
||||
-- Legacy: sometimes use self.Owner to get the owner.. so lets carry on supporting that stupidness
|
||||
-- This needs to be retired, just like self.Entity was.
|
||||
--
|
||||
if ( key == "Owner" ) then return meta.GetOwner( self ) end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Short cut to add entities to the table
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetVar( name, default )
|
||||
|
||||
local Val = self:GetTable()[ name ]
|
||||
if ( Val == nil ) then return default end
|
||||
|
||||
return Val
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function meta:SetCreator( ply --[[= NULL]] )
|
||||
if ( ply == nil ) then
|
||||
ply = NULL
|
||||
elseif ( !isentity( ply ) ) then
|
||||
error( "bad argument #1 to 'SetCreator' (Entity expected, got " .. type( ply ) .. ")", 2 )
|
||||
end
|
||||
|
||||
self.m_PlayerCreator = ply
|
||||
end
|
||||
|
||||
function meta:GetCreator()
|
||||
return self.m_PlayerCreator or NULL
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Returns true if the entity has constraints attached to it
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsConstrained()
|
||||
|
||||
if ( CLIENT ) then return self:GetNWBool( "IsConstrained" ) end
|
||||
|
||||
local c = self:GetTable().Constraints
|
||||
local bIsConstrained = false
|
||||
|
||||
if ( c ) then
|
||||
|
||||
for k, v in pairs( c ) do
|
||||
if ( IsValid( v ) ) then bIsConstrained = true break end
|
||||
c[ k ] = nil
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:SetNWBool( "IsConstrained", bIsConstrained )
|
||||
return bIsConstrained
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Short cut to set tables on the entity table
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetVar( name, value )
|
||||
|
||||
self:GetTable()[ name ] = value
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CallOnRemove
|
||||
Desc: Call this function when this entity dies.
|
||||
Calls the function like Function( <entity>, <optional args> )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:CallOnRemove( name, func, ... )
|
||||
|
||||
local mytable = self:GetTable()
|
||||
mytable.OnDieFunctions = mytable.OnDieFunctions or {}
|
||||
|
||||
mytable.OnDieFunctions[ name ] = { Name = name, Function = func, Args = { ... } }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RemoveCallOnRemove
|
||||
Desc: Removes the named hook
|
||||
-----------------------------------------------------------]]
|
||||
function meta:RemoveCallOnRemove( name )
|
||||
|
||||
local mytable = self:GetTable()
|
||||
mytable.OnDieFunctions = mytable.OnDieFunctions or {}
|
||||
mytable.OnDieFunctions[ name ] = nil
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Simple mechanism for calling the die functions.
|
||||
-----------------------------------------------------------]]
|
||||
local function DoDieFunction( ent )
|
||||
|
||||
if ( !ent or !ent.OnDieFunctions ) then return end
|
||||
|
||||
for k, v in pairs( ent.OnDieFunctions ) do
|
||||
|
||||
-- Functions aren't saved - so this could be nil if we loaded a game.
|
||||
if ( v && v.Function ) then
|
||||
|
||||
v.Function( ent, unpack( v.Args ) )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "EntityRemoved", "DoDieFunction", DoDieFunction )
|
||||
|
||||
function meta:PhysWake()
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if ( !IsValid( phys ) ) then return end
|
||||
|
||||
phys:Wake()
|
||||
|
||||
end
|
||||
|
||||
local GetColorOriginal4 = meta.GetColor4Part -- Do not use me! I will be removed
|
||||
local GetColorOriginal = meta.GetColor
|
||||
function meta:GetColor()
|
||||
|
||||
-- Backwards comp slower method
|
||||
if ( !GetColorOriginal4 ) then
|
||||
return GetColorOriginal( self )
|
||||
end
|
||||
|
||||
return Color( GetColorOriginal4( self ) )
|
||||
|
||||
end
|
||||
|
||||
local SetColorOriginal4 = meta.SetColor4Part -- Do not use me! I will be removed
|
||||
local SetColorOriginal = meta.SetColor
|
||||
function meta:SetColor( col )
|
||||
|
||||
-- Backwards comp slower method
|
||||
if ( !SetColorOriginal4 ) then
|
||||
return SetColorOriginal( self, col )
|
||||
end
|
||||
|
||||
-- Even more backwards compat
|
||||
if ( !col ) then
|
||||
return SetColorOriginal4( self, 255, 255, 255, 255 )
|
||||
end
|
||||
|
||||
SetColorOriginal4( self, col.r, col.g, col.b, col.a )
|
||||
|
||||
end
|
||||
|
||||
function meta:GetChildBones( bone )
|
||||
|
||||
local bonecount = self:GetBoneCount()
|
||||
if ( bonecount == 0 or bonecount < bone ) then return end
|
||||
|
||||
local bones = {}
|
||||
|
||||
for k = 0, bonecount - 1 do
|
||||
if ( self:GetBoneParent( k ) != bone ) then continue end
|
||||
table.insert( bones, k )
|
||||
end
|
||||
|
||||
return bones
|
||||
|
||||
end
|
||||
|
||||
function DTVar_ReceiveProxyGL( ent, name, id, val )
|
||||
if ( ent.CallDTVarProxies ) then
|
||||
ent:CallDTVarProxies( name, id, val )
|
||||
end
|
||||
end
|
||||
|
||||
function meta:InstallDataTable()
|
||||
|
||||
self.dt = {}
|
||||
local typetable = {}
|
||||
local datatable = {}
|
||||
local keytable = {}
|
||||
local dtmeta = {}
|
||||
local editing = {}
|
||||
|
||||
dtmeta.__index = function ( ent, key )
|
||||
|
||||
local dt = datatable[ key ]
|
||||
if ( dt == nil ) then return end
|
||||
|
||||
return dt.GetFunc( self, dt.index, key )
|
||||
|
||||
end
|
||||
|
||||
dtmeta.__newindex = function( ent, key, value )
|
||||
|
||||
local dt = datatable[ key ]
|
||||
if ( dt == nil ) then return end
|
||||
|
||||
dt.SetFunc( self, dt.index, value )
|
||||
|
||||
end
|
||||
|
||||
local function FindUnusedIndex( typename )
|
||||
|
||||
local tbl = typetable[ typename ]
|
||||
if ( !tbl ) then return 0 end
|
||||
|
||||
for i = 0, 31 do
|
||||
if ( !tbl[i] ) then return i end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.IsDTVarSlotUsed = function( ent, typename, index )
|
||||
|
||||
local tbl = typetable[ typename ]
|
||||
if ( !tbl or !tbl[index] ) then return false end
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
self.DTVar = function( ent, typename, index, name )
|
||||
|
||||
if ( isstring( index ) && !name ) then
|
||||
name = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local SetFunc = ent[ "SetDT" .. typename ]
|
||||
local GetFunc = ent[ "GetDT" .. typename ]
|
||||
|
||||
if ( !SetFunc or !GetFunc ) then
|
||||
MsgN( "Couldn't addvar ", name, " - type ", typename, " is invalid!" )
|
||||
return
|
||||
end
|
||||
|
||||
local data = {
|
||||
index = index,
|
||||
name = name,
|
||||
SetFunc = SetFunc,
|
||||
GetFunc = GetFunc,
|
||||
typename = typename,
|
||||
Notify = {}
|
||||
}
|
||||
|
||||
typetable[ typename ] = typetable[ typename ] or {}
|
||||
typetable[ typename ][ index ] = data
|
||||
datatable[ name ] = data
|
||||
|
||||
return data
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Access to the editing table
|
||||
--
|
||||
self.GetEditingData = function()
|
||||
return editing
|
||||
end
|
||||
|
||||
--
|
||||
-- Adds an editable variable.
|
||||
--
|
||||
self.SetupEditing = function( ent, name, keyname, data )
|
||||
|
||||
if ( !data ) then return end
|
||||
|
||||
if ( !data.title ) then data.title = name end
|
||||
|
||||
editing[ keyname ] = data
|
||||
|
||||
end
|
||||
|
||||
self.SetupKeyValue = function( ent, keyname, kvtype, setfunc, getfunc, other_data )
|
||||
|
||||
keyname = keyname:lower()
|
||||
|
||||
keytable[ keyname ] = {
|
||||
KeyName = keyname,
|
||||
Set = setfunc,
|
||||
Get = getfunc,
|
||||
Type = kvtype
|
||||
}
|
||||
|
||||
if ( other_data ) then
|
||||
|
||||
table.Merge( keytable[ keyname ], other_data )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local CallProxies = function( ent, tbl, name, oldval, newval )
|
||||
|
||||
for i = 1, #tbl do
|
||||
tbl[ i ]( ent, name, oldval, newval )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.CallDTVarProxies = function( ent, typename, index, newVal )
|
||||
|
||||
local t = typetable[ typename ] && typetable[ typename ][ index ] or nil
|
||||
if ( t ) then
|
||||
CallProxies( ent, t.Notify, t.name, t.GetFunc( ent, index ), newVal )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.NetworkVar = function( ent, typename, index, name, other_data )
|
||||
|
||||
if ( isstring( index ) && ( istable( name ) or !name ) ) then
|
||||
other_data = name
|
||||
name = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local t = ent.DTVar( ent, typename, index, name )
|
||||
|
||||
-- Some addons call these on the entity table, and that used to work, so we keep that
|
||||
ent[ "Set" .. name ] = function( selfent, value )
|
||||
CallProxies( ent, t.Notify, name, t.GetFunc( ent, index ), value )
|
||||
t.SetFunc( ent, index, value )
|
||||
end
|
||||
|
||||
ent[ "Get" .. name ] = function( selfent )
|
||||
return t.GetFunc( ent, index )
|
||||
end
|
||||
|
||||
if ( !other_data ) then return end
|
||||
|
||||
-- This KeyName stuff is absolutely unnecessary, there's absolutely no reason for it to exist
|
||||
-- But we cannot remove it now because dupes will break. It should've used the "name" variable
|
||||
if ( other_data.KeyName ) then
|
||||
ent:SetupKeyValue( other_data.KeyName, typename, ent[ "Set" .. name ], ent[ "Get" .. name ], other_data )
|
||||
ent:SetupEditing( name, other_data.KeyName, other_data.Edit )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Add a function that gets called when the variable changes
|
||||
-- Note: this doesn't work on the client yet - which drastically reduces its usefulness.
|
||||
--
|
||||
self.NetworkVarNotify = function( ent, name, func )
|
||||
|
||||
if ( !datatable[ name ] ) then error( "calling NetworkVarNotify on missing network var " .. name ) end
|
||||
|
||||
table.insert( datatable[ name ].Notify, func )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Create an accessor of an element. This is mainly so you can use spare
|
||||
-- network vars (vectors, angles) to network single floats.
|
||||
--
|
||||
self.NetworkVarElement = function( ent, typename, index, element, name, other_data )
|
||||
|
||||
if ( isstring( index ) && isstring( element ) ) then
|
||||
other_data = name
|
||||
name = element
|
||||
element = index
|
||||
index = FindUnusedIndex( typename )
|
||||
elseif ( !index && isstring( name ) ) then
|
||||
index = FindUnusedIndex( typename )
|
||||
end
|
||||
|
||||
local t = ent.DTVar( ent, typename, index, name )
|
||||
t.element = element
|
||||
|
||||
ent[ "Set" .. name ] = function( selfent, value )
|
||||
local old = t.GetFunc( selfent, index )
|
||||
old[ element ] = value
|
||||
t.SetFunc( selfent, index, old )
|
||||
end
|
||||
|
||||
ent[ "Get" .. name ] = function( selfent )
|
||||
return t.GetFunc( selfent, index )[ element ]
|
||||
end
|
||||
|
||||
if ( !other_data ) then return end
|
||||
|
||||
-- This KeyName stuff is absolutely unnecessary, there's absolutely no reason for it to exist
|
||||
-- But we cannot remove it now because dupes will break. It should've used the "name" variable
|
||||
if ( other_data.KeyName ) then
|
||||
ent:SetupKeyValue( other_data.KeyName, "float", ent[ "Set" .. name ], ent[ "Get" .. name ], other_data )
|
||||
ent:SetupEditing( name, other_data.KeyName, other_data.Edit )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self.SetNetworkKeyValue = function( ent, key, value )
|
||||
|
||||
key = key:lower()
|
||||
|
||||
local k = keytable[ key ]
|
||||
if ( !k ) then return end
|
||||
|
||||
local v = util.StringToType( value, k.Type )
|
||||
if ( v == nil ) then return end
|
||||
|
||||
k.Set( ent, v )
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
self.GetNetworkKeyValue = function( ent, key )
|
||||
|
||||
key = key:lower()
|
||||
|
||||
local k = keytable[ key ]
|
||||
if ( !k ) then return end
|
||||
|
||||
return k.Get( ent )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the duplicator system to get the network vars
|
||||
--
|
||||
self.GetNetworkVars = function( ent )
|
||||
|
||||
local dt = {}
|
||||
|
||||
for k, v in pairs( datatable ) do
|
||||
|
||||
-- Don't try to save entities (yet?)
|
||||
if ( v.typename == "Entity" ) then continue end
|
||||
|
||||
if ( v.element ) then
|
||||
dt[ k ] = v.GetFunc( ent, v.index )[ v.element ]
|
||||
else
|
||||
dt[ k ] = v.GetFunc( ent, v.index )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If there's nothing in our table - then return nil.
|
||||
--
|
||||
if ( table.IsEmpty( dt ) ) then return nil end
|
||||
|
||||
return dt
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the duplicator system to restore from network vars
|
||||
--
|
||||
self.RestoreNetworkVars = function( ent, tab )
|
||||
|
||||
if ( !tab ) then return end
|
||||
|
||||
-- Loop this entities data table
|
||||
for k, v in pairs( datatable ) do
|
||||
|
||||
-- If it contains this entry
|
||||
if ( tab[ k ] == nil ) then continue end
|
||||
|
||||
-- Support old saves/dupes with incorrectly saved data
|
||||
if ( v.element && ( isangle( tab[ k ] ) or isvector( tab[ k ] ) ) ) then
|
||||
tab[ k ] = tab[ k ][ v.element ]
|
||||
end
|
||||
|
||||
-- Set it.
|
||||
if ( ent[ "Set" .. k ] ) then
|
||||
ent[ "Set" .. k ]( ent, tab[ k ] )
|
||||
else
|
||||
v.SetFunc( ent, v.index, tab[ k ] )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
setmetatable( self.dt, dtmeta )
|
||||
|
||||
--
|
||||
-- In sandbox the client can edit certain values on certain entities
|
||||
-- we implement this here incase any other gamemodes want to use it
|
||||
-- although it is of course deactivated by default.
|
||||
--
|
||||
|
||||
--
|
||||
-- This function takes a keyname and a value - both strings.
|
||||
--
|
||||
--
|
||||
-- Called serverside it will set the value.
|
||||
--
|
||||
self.EditValue = function( ent, variable, value )
|
||||
|
||||
if ( !isstring( variable ) ) then return end
|
||||
if ( !isstring( value ) ) then return end
|
||||
|
||||
--
|
||||
-- It can be called clientside to send a message to the server
|
||||
-- to request a change of value.
|
||||
--
|
||||
if ( CLIENT ) then
|
||||
|
||||
net.Start( "editvariable" )
|
||||
net.WriteEntity( ent )
|
||||
net.WriteString( variable )
|
||||
net.WriteString( value )
|
||||
net.SendToServer()
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called serverside it simply changes the value
|
||||
--
|
||||
if ( SERVER ) then
|
||||
|
||||
ent:SetNetworkKeyValue( variable, value )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
util.AddNetworkString( "editvariable" )
|
||||
|
||||
net.Receive( "editvariable", function( len, client )
|
||||
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
if ( !isfunction( ent.GetEditingData ) ) then return end
|
||||
if ( ent.AdminOnly && !( client:IsAdmin() or game.SinglePlayer() ) ) then return end
|
||||
|
||||
local key = net.ReadString()
|
||||
|
||||
-- Is this key in our edit table?
|
||||
local editor = ent:GetEditingData()[ key ]
|
||||
if ( !istable( editor ) ) then return end
|
||||
|
||||
local val = net.ReadString()
|
||||
hook.Run( "VariableEdited", ent, client, key, val, editor )
|
||||
|
||||
end )
|
||||
|
||||
function meta:GetUnFreezable()
|
||||
return self.m_bUnFreezable or false
|
||||
end
|
||||
|
||||
function meta:SetUnFreezable( bFreeze )
|
||||
self.m_bUnFreezable = tobool( bFreeze ) or false
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Networked var proxies
|
||||
--
|
||||
function meta:SetNetworked2VarProxy( name, func )
|
||||
|
||||
if ( !self.NWVarProxies ) then
|
||||
self.NWVarProxies = {}
|
||||
end
|
||||
|
||||
self.NWVarProxies[ name ] = func
|
||||
|
||||
end
|
||||
|
||||
function meta:GetNetworked2VarProxy( name )
|
||||
|
||||
if ( self.NWVarProxies ) then
|
||||
local func = self.NWVarProxies[ name ]
|
||||
if ( isfunction( func ) ) then
|
||||
return func
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
meta.SetNW2VarProxy = meta.SetNetworked2VarProxy
|
||||
meta.GetNW2VarProxy = meta.GetNetworked2VarProxy
|
||||
|
||||
hook.Add( "EntityNetworkedVarChanged", "NetworkedVars", function( ent, name, oldValue, newValue )
|
||||
|
||||
if ( ent.NWVarProxies ) then
|
||||
local func = ent.NWVarProxies[ name ]
|
||||
|
||||
if ( isfunction( func ) ) then
|
||||
func( ent, name, oldValue, newValue )
|
||||
end
|
||||
end
|
||||
|
||||
end )
|
||||
|
||||
--
|
||||
-- Vehicle Extensions
|
||||
--
|
||||
local vehicle = FindMetaTable( "Vehicle" )
|
||||
|
||||
--
|
||||
-- We steal some DT slots by default for vehicles
|
||||
-- to control the third person view. You should use
|
||||
-- these functions if you want to play with them because
|
||||
-- they might eventually be moved into the engine - so manually
|
||||
-- editing the DT values will stop working.
|
||||
--
|
||||
function vehicle:SetVehicleClass( s )
|
||||
|
||||
self:SetDTString( 3, s )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetVehicleClass()
|
||||
|
||||
return self:GetDTString( 3 )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:SetThirdPersonMode( b )
|
||||
|
||||
self:SetDTBool( 3, b )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetThirdPersonMode()
|
||||
|
||||
return self:GetDTBool( 3 )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:SetCameraDistance( dist )
|
||||
|
||||
self:SetDTFloat( 3, dist )
|
||||
|
||||
end
|
||||
|
||||
function vehicle:GetCameraDistance()
|
||||
|
||||
return self:GetDTFloat( 3 )
|
||||
|
||||
end
|
||||
58
lua/includes/extensions/ents.lua
Normal file
58
lua/includes/extensions/ents.lua
Normal file
@@ -0,0 +1,58 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function ents.FindByClassAndParent( classname, entity )
|
||||
|
||||
if ( !IsValid( entity ) ) then return end
|
||||
|
||||
local list = ents.FindByClass( classname )
|
||||
if ( !list ) then return end
|
||||
|
||||
local out = {}
|
||||
for k, v in ipairs( list ) do
|
||||
|
||||
if ( !IsValid(v) ) then continue end
|
||||
|
||||
local p = v:GetParent()
|
||||
if ( !IsValid(p) ) then continue end
|
||||
if ( p != entity ) then continue end
|
||||
|
||||
table.insert( out, v )
|
||||
|
||||
end
|
||||
|
||||
if ( #out == 0 ) then return end
|
||||
|
||||
return out
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
local inext = ipairs({})
|
||||
local EntityCache = nil
|
||||
|
||||
function ents.Iterator()
|
||||
|
||||
if ( EntityCache == nil ) then EntityCache = ents.GetAll() end
|
||||
|
||||
return inext, EntityCache, 0
|
||||
|
||||
end
|
||||
|
||||
local function InvalidateEntityCache( ent )
|
||||
|
||||
EntityCache = nil
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "OnEntityCreated", "ents.Iterator", InvalidateEntityCache )
|
||||
hook.Add( "EntityRemoved", "ents.Iterator", InvalidateEntityCache )
|
||||
49
lua/includes/extensions/file.lua
Normal file
49
lua/includes/extensions/file.lua
Normal file
@@ -0,0 +1,49 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
function file.Read( filename, path )
|
||||
|
||||
if ( path == true ) then path = "GAME" end
|
||||
if ( path == nil || path == false ) then path = "DATA" end
|
||||
|
||||
local f = file.Open( filename, "rb", path )
|
||||
if ( !f ) then return end
|
||||
|
||||
local str = f:Read( f:Size() )
|
||||
|
||||
f:Close()
|
||||
|
||||
if ( !str ) then str = "" end
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
function file.Write( filename, contents )
|
||||
|
||||
local f = file.Open( filename, "wb", "DATA" )
|
||||
if ( !f ) then return end
|
||||
|
||||
f:Write( contents )
|
||||
f:Close()
|
||||
|
||||
end
|
||||
|
||||
function file.Append( filename, contents )
|
||||
|
||||
local f = file.Open( filename, "ab", "DATA" )
|
||||
if ( !f ) then return end
|
||||
|
||||
f:Write( contents )
|
||||
f:Close()
|
||||
|
||||
end
|
||||
64
lua/includes/extensions/game.lua
Normal file
64
lua/includes/extensions/game.lua
Normal file
@@ -0,0 +1,64 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local AmmoTypes = {}
|
||||
|
||||
--
|
||||
-- Called by modders to add a new ammo type.
|
||||
-- Ammo types aren't something you can add on the fly. You have one
|
||||
-- opportunity during loadtime. The ammo types should also be IDENTICAL on
|
||||
-- server and client.
|
||||
-- If they're not you will receive errors and maybe even crashes.
|
||||
--
|
||||
--
|
||||
-- game.AddAmmoType(
|
||||
-- {
|
||||
-- name = "customammo",
|
||||
-- dmgtype = DMG_BULLET,
|
||||
-- tracer = TRACER_LINE_AND_WHIZ,
|
||||
-- plydmg = 20,
|
||||
-- npcdmg = 20,
|
||||
-- force = 100,
|
||||
-- minsplash = 10,
|
||||
-- maxsplash = 100
|
||||
-- })
|
||||
--
|
||||
function game.AddAmmoType( tbl )
|
||||
if ( !isstring( tbl.name ) ) then
|
||||
ErrorNoHalt( "bad argument #1 to 'AddAmmoType' ('name' key expected a string, got " .. type( tbl.name ) .. ")\n" )
|
||||
return
|
||||
end
|
||||
|
||||
local name = string.lower( tbl.name )
|
||||
|
||||
for id, ammo in ipairs( AmmoTypes ) do
|
||||
if ( name == string.lower( ammo.name ) ) then
|
||||
AmmoTypes[ id ] = tbl
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
table.insert( AmmoTypes, tbl )
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by the engine to retrive the ammo types.
|
||||
-- You should never have to call this manually.
|
||||
--
|
||||
function game.BuildAmmoTypes()
|
||||
--
|
||||
-- Sort the table by name here to assure that the ammo types
|
||||
-- are inserted in the same order on both server and client
|
||||
--
|
||||
table.SortByMember( AmmoTypes, "name", true )
|
||||
|
||||
return AmmoTypes
|
||||
end
|
||||
310
lua/includes/extensions/math.lua
Normal file
310
lua/includes/extensions/math.lua
Normal file
@@ -0,0 +1,310 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
include( "math/ease.lua" )
|
||||
|
||||
math.tau = 2 * math.pi
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DistanceSqr( low, high )
|
||||
Desc: Squared Distance between two 2d points, use this instead of math.Distance as it is more cpu efficient.
|
||||
------------------------------------------------------------]]
|
||||
function math.DistanceSqr( x1, y1, x2, y2 )
|
||||
local xd = x2 - x1
|
||||
local yd = y2 - y1
|
||||
return xd * xd + yd * yd
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Distance( low, high )
|
||||
Desc: Distance between two 2d points
|
||||
------------------------------------------------------------]]
|
||||
function math.Distance( x1, y1, x2, y2 )
|
||||
local xd = x2 - x1
|
||||
local yd = y2 - y1
|
||||
return math.sqrt( xd * xd + yd * yd )
|
||||
end
|
||||
math.Dist = math.Distance -- Backwards compatibility
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: BinToInt( bin )
|
||||
Desc: Convert a binary string to an integer number
|
||||
------------------------------------------------------------]]
|
||||
function math.BinToInt( bin )
|
||||
return tonumber( bin, 2 )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IntToBin( int )
|
||||
Desc: Convert an integer number to a binary string (the string len will be a multiple of three)
|
||||
------------------------------------------------------------]]
|
||||
local intbin = {
|
||||
["0"] = "000", ["1"] = "001", ["2"] = "010", ["3"] = "011",
|
||||
["4"] = "100", ["5"] = "101", ["6"] = "110", ["7"] = "111"
|
||||
}
|
||||
|
||||
function math.IntToBin( int )
|
||||
local str = string.gsub( string.format( "%o", int ), "(.)", function ( d ) return intbin[ d ] end )
|
||||
return str
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Clamp( in, low, high )
|
||||
Desc: Clamp value between 2 values
|
||||
------------------------------------------------------------]]
|
||||
function math.Clamp( _in, low, high )
|
||||
return math.min( math.max( _in, low ), high )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Rand( low, high )
|
||||
Desc: Random number between low and high
|
||||
-----------------------------------------------------------]]
|
||||
function math.Rand( low, high )
|
||||
return low + ( high - low ) * math.random()
|
||||
end
|
||||
|
||||
math.Max = math.max
|
||||
math.Min = math.min
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: EaseInOut(fProgress, fEaseIn, fEaseOut)
|
||||
Desc: Provided by garry from the facewound source and converted
|
||||
to Lua by me :p
|
||||
Usage: math.EaseInOut(0.1, 0.5, 0.5) - all parameters should be between 0 and 1
|
||||
-----------------------------------------------------------]]
|
||||
function math.EaseInOut( fProgress, fEaseIn, fEaseOut )
|
||||
|
||||
if ( fEaseIn == nil ) then fEaseIn = 0 end
|
||||
if ( fEaseOut == nil ) then fEaseOut = 1 end
|
||||
|
||||
if ( fProgress == 0 or fProgress == 1 ) then return fProgress end
|
||||
|
||||
local fSumEase = fEaseIn + fEaseOut
|
||||
|
||||
if ( fSumEase == 0 ) then return fProgress end
|
||||
if ( fSumEase > 1 ) then
|
||||
fEaseIn = fEaseIn / fSumEase
|
||||
fEaseOut = fEaseOut / fSumEase
|
||||
end
|
||||
|
||||
local fProgressCalc = 1 / ( 2 - fEaseIn - fEaseOut )
|
||||
|
||||
if ( fProgress < fEaseIn ) then
|
||||
return ( ( fProgressCalc / fEaseIn ) * fProgress * fProgress )
|
||||
elseif ( fProgress < 1 - fEaseOut ) then
|
||||
return ( fProgressCalc * ( 2 * fProgress - fEaseIn ) )
|
||||
else
|
||||
fProgress = 1 - fProgress
|
||||
return ( 1 - ( fProgressCalc / fEaseOut ) * fProgress * fProgress )
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function KNOT( i, tinc ) return ( i - 3 ) * tinc end
|
||||
|
||||
function math.calcBSplineN( i, k, t, tinc )
|
||||
|
||||
if ( k == 1 ) then
|
||||
|
||||
if ( ( KNOT( i, tinc ) <= t ) and ( t < KNOT( i + 1, tinc ) ) ) then
|
||||
|
||||
return 1
|
||||
|
||||
else
|
||||
|
||||
return 0
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
local ft = ( t - KNOT( i, tinc ) ) * math.calcBSplineN( i, k - 1, t, tinc )
|
||||
local fb = KNOT( i + k - 1, tinc ) - KNOT( i, tinc )
|
||||
|
||||
local st = ( KNOT( i + k, tinc ) - t ) * math.calcBSplineN( i + 1, k - 1, t, tinc )
|
||||
local sb = KNOT( i + k, tinc ) - KNOT( i + 1, tinc )
|
||||
|
||||
local first = 0
|
||||
local second = 0
|
||||
|
||||
if ( fb > 0 ) then
|
||||
|
||||
first = ft / fb
|
||||
|
||||
end
|
||||
if ( sb > 0 ) then
|
||||
|
||||
second = st / sb
|
||||
|
||||
end
|
||||
|
||||
return first + second
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function math.BSplinePoint( tDiff, tPoints, tMax )
|
||||
|
||||
local Q = Vector( 0, 0, 0 )
|
||||
local tinc = tMax / ( #tPoints - 3 )
|
||||
|
||||
tDiff = tDiff + tinc
|
||||
|
||||
for idx, pt in pairs( tPoints ) do
|
||||
|
||||
local n = math.calcBSplineN( idx, 4, tDiff, tinc )
|
||||
Q = Q + ( n * pt )
|
||||
|
||||
end
|
||||
|
||||
return Q
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Cubic hermite spline
|
||||
p0, p1 - points; m0, m1 - tangets; t - fraction along the curve (0-1)
|
||||
-----------------------------------------------------------]]
|
||||
function math.CHSpline( t, p0, m0, p1, m1 )
|
||||
|
||||
if ( t >= 1 ) then return p1 end
|
||||
if ( t <= 0 ) then return p0 end
|
||||
|
||||
local t2 = t * t
|
||||
local t3 = t * t2
|
||||
|
||||
return p0 * ( 2 * t3 - 3 * t2 + 1 ) +
|
||||
m0 * ( t3 - 2 * t2 + t ) +
|
||||
p1 * ( -2 * t3 + 3 * t2 ) +
|
||||
m1 * ( t3 - t2 )
|
||||
|
||||
end
|
||||
|
||||
-- Round to the nearest integer
|
||||
function math.Round( num, idp )
|
||||
|
||||
local mult = 10 ^ ( idp or 0 )
|
||||
return math.floor( num * mult + 0.5 ) / mult
|
||||
|
||||
end
|
||||
|
||||
-- Rounds towards zero
|
||||
function math.Truncate( num, idp )
|
||||
|
||||
local mult = 10 ^ ( idp or 0 )
|
||||
local FloorOrCeil = num < 0 and math.ceil or math.floor
|
||||
|
||||
return FloorOrCeil( num * mult ) / mult
|
||||
|
||||
end
|
||||
|
||||
function math.Approach( cur, target, inc )
|
||||
|
||||
inc = math.abs( inc )
|
||||
|
||||
if ( cur < target ) then
|
||||
|
||||
return math.min( cur + inc, target )
|
||||
|
||||
elseif ( cur > target ) then
|
||||
|
||||
return math.max( cur - inc, target )
|
||||
|
||||
end
|
||||
|
||||
return target
|
||||
|
||||
end
|
||||
|
||||
function math.NormalizeAngle( a )
|
||||
return ( a + 180 ) % 360 - 180
|
||||
end
|
||||
|
||||
function math.AngleDifference( a, b )
|
||||
|
||||
local diff = math.NormalizeAngle( a - b )
|
||||
|
||||
if ( diff < 180 ) then
|
||||
return diff
|
||||
end
|
||||
|
||||
return diff - 360
|
||||
|
||||
end
|
||||
|
||||
function math.ApproachAngle( cur, target, inc )
|
||||
|
||||
local diff = math.AngleDifference( target, cur )
|
||||
|
||||
return math.Approach( cur, cur + diff, inc )
|
||||
|
||||
end
|
||||
|
||||
function math.TimeFraction( Start, End, Current )
|
||||
return ( Current - Start ) / ( End - Start )
|
||||
end
|
||||
|
||||
function math.Remap( value, inMin, inMax, outMin, outMax )
|
||||
return outMin + ( ( ( value - inMin ) / ( inMax - inMin ) ) * ( outMax - outMin ) )
|
||||
end
|
||||
|
||||
-- Snaps the provided number to the nearest multiple
|
||||
function math.SnapTo( num, multiple )
|
||||
return math.floor( num / multiple + 0.5 ) * multiple
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CubicBezier( frac, p0, p1, p2, p3 )
|
||||
Desc: Lerp point between points with cubic bezier
|
||||
-----------------------------------------------------------]]
|
||||
function math.CubicBezier( frac, p0, p1, p2, p3 )
|
||||
local frac2 = frac * frac
|
||||
local inv = 1 - frac
|
||||
local inv2 = inv * inv
|
||||
|
||||
return inv2 * inv * p0 + 3 * inv2 * frac * p1 + 3 * inv * frac2 * p2 + frac2 * frac * p3
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: QuadraticBezier( frac, p0, p1, p2 )
|
||||
Desc: Lerp point between points with quadratic bezier
|
||||
-----------------------------------------------------------]]
|
||||
function math.QuadraticBezier( frac, p0, p1, p2 )
|
||||
local frac2 = frac * frac
|
||||
local inv = 1 - frac
|
||||
local inv2 = inv * inv
|
||||
|
||||
return inv2 * p0 + 2 * inv * frac * p1 + frac2 * p2
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Factorial( num )
|
||||
Desc: Calculate the factorial value of num
|
||||
-----------------------------------------------------------]]
|
||||
function math.Factorial( num )
|
||||
|
||||
if ( num < 0 ) then
|
||||
return nil
|
||||
elseif ( num < 2 ) then
|
||||
return 1
|
||||
end
|
||||
|
||||
local res = 1
|
||||
|
||||
for i = 2, num do
|
||||
res = res * i
|
||||
end
|
||||
|
||||
return res
|
||||
|
||||
end
|
||||
201
lua/includes/extensions/math/ease.lua
Normal file
201
lua/includes/extensions/math/ease.lua
Normal file
@@ -0,0 +1,201 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
module("math.ease", package.seeall)
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Source code of functions
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
-- https://github.com/Facepunch/garrysmod/pull/1755
|
||||
-- https://web.archive.org/web/20201212082306/https://easings.net/
|
||||
-- https://web.archive.org/web/20201218211606/https://raw.githubusercontent.com/ai/easings.net/master/src/easings.yml
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Easing constants
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
local c1 = 1.70158
|
||||
local c3 = c1 + 1
|
||||
local c2 = c1 * 1.525
|
||||
local c4 = ( 2 * math.pi ) / 3
|
||||
local c5 = ( 2 * math.pi ) / 4.5
|
||||
local n1 = 7.5625
|
||||
local d1 = 2.75
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
To reduce _G lookups, we'll localize some commonly
|
||||
used functions in this extension
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
local pi = math.pi
|
||||
local cos = math.cos
|
||||
local sin = math.sin
|
||||
local sqrt = math.sqrt
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Easing functions
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
function InSine( x )
|
||||
return 1 - cos( ( x * pi ) / 2 )
|
||||
end
|
||||
|
||||
function OutSine( x )
|
||||
return sin( ( x * pi ) / 2 )
|
||||
end
|
||||
|
||||
function InOutSine( x )
|
||||
return -( cos( pi * x ) - 1 ) / 2
|
||||
end
|
||||
|
||||
function InQuad( x )
|
||||
return x ^ 2
|
||||
end
|
||||
|
||||
function OutQuad( x )
|
||||
return 1 - ( 1 - x ) * ( 1 - x )
|
||||
end
|
||||
|
||||
function InOutQuad( x )
|
||||
return x < 0.5 && 2 * x ^ 2 || 1 - ( ( -2 * x + 2 ) ^ 2 ) / 2
|
||||
end
|
||||
|
||||
function InCubic( x )
|
||||
return x ^ 3
|
||||
end
|
||||
|
||||
function OutCubic( x )
|
||||
return 1 - ( ( 1 - x ) ^ 3 )
|
||||
end
|
||||
|
||||
function InOutCubic( x )
|
||||
return x < 0.5 && 4 * x ^ 3 || 1 - ( ( -2 * x + 2 ) ^ 3 ) / 2
|
||||
end
|
||||
|
||||
function InQuart( x )
|
||||
return x ^ 4
|
||||
end
|
||||
|
||||
function OutQuart( x )
|
||||
return 1 - ( ( 1 - x ) ^ 4 )
|
||||
end
|
||||
|
||||
function InOutQuart( x )
|
||||
return x < 0.5 && 8 * x ^ 4 || 1 - ( ( -2 * x + 2 ) ^ 4 ) / 2
|
||||
end
|
||||
|
||||
function InQuint( x )
|
||||
return x ^ 5
|
||||
end
|
||||
|
||||
function OutQuint( x )
|
||||
return 1 - ( ( 1 - x ) ^ 5 )
|
||||
end
|
||||
|
||||
function InOutQuint( x )
|
||||
return x < 0.5 && 16 * x ^ 5 || 1 - ( ( -2 * x + 2 ) ^ 5 ) / 2
|
||||
end
|
||||
|
||||
function InExpo( x )
|
||||
return x == 0 && 0 || ( 2 ^ ( 10 * x - 10 ) )
|
||||
end
|
||||
|
||||
function OutExpo( x )
|
||||
return x == 1 && 1 || 1 - ( 2 ^ ( -10 * x ) )
|
||||
end
|
||||
|
||||
function InOutExpo( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| x < 0.5 && ( 2 ^ ( 20 * x - 10 ) ) / 2
|
||||
|| ( 2 - ( 2 ^ ( -20 * x + 10 ) ) ) / 2
|
||||
end
|
||||
|
||||
function InCirc( x )
|
||||
return 1 - sqrt( 1 - ( x ^ 2 ) )
|
||||
end
|
||||
|
||||
function OutCirc( x )
|
||||
return sqrt( 1 - ( ( x - 1 ) ^ 2 ) )
|
||||
end
|
||||
|
||||
function InOutCirc( x )
|
||||
return x < 0.5
|
||||
&& ( 1 - sqrt( 1 - ( ( 2 * x ) ^ 2 ) ) ) / 2
|
||||
|| ( sqrt( 1 - ( ( -2 * x + 2 ) ^ 2 ) ) + 1 ) / 2
|
||||
end
|
||||
|
||||
function InBack( x )
|
||||
return c3 * x ^ 3 - c1 * x ^ 2
|
||||
end
|
||||
|
||||
function OutBack( x )
|
||||
return 1 + c3 * ( ( x - 1 ) ^ 3 ) + c1 * ( ( x - 1 ) ^ 2 )
|
||||
end
|
||||
|
||||
function InOutBack( x )
|
||||
return x < 0.5
|
||||
&& ( ( ( 2 * x ) ^ 2 ) * ( ( c2 + 1 ) * 2 * x - c2 ) ) / 2
|
||||
|| ( ( ( 2 * x - 2 ) ^ 2 ) * ( ( c2 + 1 ) * ( x * 2 - 2 ) + c2 ) + 2 ) / 2
|
||||
end
|
||||
|
||||
function InElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| -( 2 ^ ( 10 * x - 10 ) ) * sin( ( x * 10 - 10.75 ) * c4 )
|
||||
end
|
||||
|
||||
function OutElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| ( 2 ^ ( -10 * x ) ) * sin( ( x * 10 - 0.75 ) * c4 ) + 1
|
||||
end
|
||||
|
||||
function InOutElastic( x )
|
||||
return x == 0
|
||||
&& 0
|
||||
|| x == 1
|
||||
&& 1
|
||||
|| x < 0.5
|
||||
&& -( ( 2 ^ ( 20 * x - 10 ) ) * sin( ( 20 * x - 11.125 ) * c5 ) ) / 2
|
||||
|| ( ( 2 ^ ( -20 * x + 10 ) ) * sin( ( 20 * x - 11.125 ) * c5 ) ) / 2 + 1
|
||||
end
|
||||
|
||||
function InBounce( x )
|
||||
return 1 - OutBounce( 1 - x )
|
||||
end
|
||||
|
||||
function OutBounce( x )
|
||||
if ( x < 1 / d1 ) then
|
||||
return n1 * x ^ 2
|
||||
elseif ( x < 2 / d1 ) then
|
||||
x = x - ( 1.5 / d1 )
|
||||
return n1 * x ^ 2 + 0.75
|
||||
elseif ( x < 2.5 / d1 ) then
|
||||
x = x - ( 2.25 / d1 )
|
||||
return n1 * x ^ 2 + 0.9375
|
||||
else
|
||||
x = x - ( 2.625 / d1 )
|
||||
return n1 * x ^ 2 + 0.984375
|
||||
end
|
||||
end
|
||||
|
||||
function InOutBounce( x )
|
||||
return x < 0.5
|
||||
&& ( 1 - OutBounce( 1 - 2 * x ) ) / 2
|
||||
|| ( 1 + OutBounce( 2 * x - 1 ) ) / 2
|
||||
end
|
||||
268
lua/includes/extensions/motionsensor.lua
Normal file
268
lua/includes/extensions/motionsensor.lua
Normal file
@@ -0,0 +1,268 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
--
|
||||
-- Should never really happen.
|
||||
--
|
||||
motionsensor = motionsensor or {}
|
||||
|
||||
|
||||
--
|
||||
-- These bones are used to draw the debug
|
||||
-- kinect skeleton. You just need to loop through
|
||||
-- and draw a line between each of these bones.
|
||||
--
|
||||
motionsensor.DebugBones =
|
||||
{
|
||||
-- Torso
|
||||
{ SENSORBONE.HEAD, SENSORBONE.SHOULDER },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SHOULDER_LEFT },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SHOULDER_RIGHT },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.SPINE },
|
||||
{ SENSORBONE.SHOULDER, SENSORBONE.HIP },
|
||||
{ SENSORBONE.HIP, SENSORBONE.HIP_LEFT },
|
||||
{ SENSORBONE.HIP, SENSORBONE.HIP_RIGHT },
|
||||
|
||||
-- Left Arm
|
||||
{ SENSORBONE.SHOULDER_LEFT, SENSORBONE.ELBOW_LEFT },
|
||||
{ SENSORBONE.ELBOW_LEFT, SENSORBONE.WRIST_LEFT },
|
||||
{ SENSORBONE.WRIST_LEFT, SENSORBONE.HAND_LEFT },
|
||||
|
||||
-- Right Arm
|
||||
{ SENSORBONE.SHOULDER_RIGHT, SENSORBONE.ELBOW_RIGHT },
|
||||
{ SENSORBONE.ELBOW_RIGHT, SENSORBONE.WRIST_RIGHT },
|
||||
{ SENSORBONE.WRIST_RIGHT, SENSORBONE.HAND_RIGHT },
|
||||
|
||||
-- left leg
|
||||
{ SENSORBONE.HIP_LEFT, SENSORBONE.KNEE_LEFT },
|
||||
{ SENSORBONE.KNEE_LEFT, SENSORBONE.ANKLE_LEFT },
|
||||
{ SENSORBONE.ANKLE_LEFT, SENSORBONE.FOOT_LEFT },
|
||||
|
||||
-- right leg
|
||||
{ SENSORBONE.HIP_RIGHT, SENSORBONE.KNEE_RIGHT },
|
||||
{ SENSORBONE.KNEE_RIGHT, SENSORBONE.ANKLE_RIGHT },
|
||||
{ SENSORBONE.ANKLE_RIGHT, SENSORBONE.FOOT_RIGHT },
|
||||
}
|
||||
|
||||
motionsensor.ChooseBuilderFromEntity = function( ent )
|
||||
|
||||
local builders = list.Get( "SkeletonConvertor" )
|
||||
|
||||
for k, v in pairs( builders ) do
|
||||
|
||||
if ( v:IsApplicable( ent ) ) then return k end
|
||||
|
||||
end
|
||||
|
||||
return "ValveBiped"
|
||||
|
||||
end
|
||||
|
||||
motionsensor.ProcessAngle = function( translator, sensor, pos, ang, special_vectors, boneid, v )
|
||||
|
||||
local a = nil
|
||||
local b = nil
|
||||
local up = special_vectors["up"]
|
||||
|
||||
--
|
||||
-- Using a vector from another angle.
|
||||
-- If the angle isn't processed yet return
|
||||
-- we will be added to the list to process again.
|
||||
--
|
||||
if ( v.up_up ) then
|
||||
if ( !ang[ v.up_up ] ) then return end
|
||||
up = ang[ v.up_up ]:Up()
|
||||
end
|
||||
|
||||
if ( v.up_dn ) then
|
||||
if ( !ang[ v.up_dn ] ) then return end
|
||||
up = ang[ v.up_dn ]:Up() * -1
|
||||
end
|
||||
|
||||
if ( v.up_fwd ) then
|
||||
if ( !ang[ v.up_fwd ] ) then return end
|
||||
up = ang[ v.up_fwd ]:Forward()
|
||||
end
|
||||
|
||||
if ( v.up_lft ) then
|
||||
if ( !ang[ v.up_lft ] ) then return end
|
||||
up = ang[ v.up_lft ]:Right() * -1
|
||||
end
|
||||
|
||||
if ( v.up_rgt ) then
|
||||
if ( !ang[ v.up_rgt ] ) then return end
|
||||
up = ang[ v.up_rgt ]:Right()
|
||||
end
|
||||
|
||||
--
|
||||
-- From -> To vectors
|
||||
--
|
||||
if ( v.from_sensor ) then a = sensor[ v.from_sensor ] end
|
||||
if ( v.to_sensor ) then b = sensor[ v.to_sensor ] end
|
||||
if ( v.from ) then a = pos[ v.from ] end
|
||||
if ( v.to ) then b = pos[ v.to ] end
|
||||
|
||||
--
|
||||
-- We can offer special vectors to define 'up'
|
||||
--
|
||||
if ( isstring( v.up ) ) then
|
||||
up = special_vectors[ v.up ]
|
||||
end
|
||||
|
||||
if ( a == nil or b == nil or up == nil ) then return end
|
||||
|
||||
ang[ boneid ] = ( a - b ):GetNormal():AngleEx( up:GetNormal() );
|
||||
|
||||
if ( v.adjust ) then
|
||||
ang[ boneid ] = ang[ boneid ] + v.adjust
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Processes the AnglesTable from a skeleton constructor
|
||||
--
|
||||
motionsensor.ProcessAnglesTable = function( translator, sensor, pos, rotation )
|
||||
|
||||
if ( !translator.AnglesTable ) then return {} end
|
||||
|
||||
local ang = {}
|
||||
|
||||
local special_vectors = {}
|
||||
special_vectors["right"] = rotation:Right()
|
||||
special_vectors["left"] = special_vectors["right"] * -1
|
||||
special_vectors["up"] = rotation:Up()
|
||||
special_vectors["down"] = special_vectors["up"] * -1
|
||||
special_vectors["forward"] = special_vectors["down"]:Cross( special_vectors["right"] )
|
||||
special_vectors["backward"] = special_vectors["forward"] * -1
|
||||
|
||||
special_vectors["hips_left"] = ( sensor[SENSORBONE.HIP_RIGHT] - sensor[SENSORBONE.HIP_LEFT] ):GetNormal()
|
||||
special_vectors["hips_up"] = ( sensor[SENSORBONE.HIP] - sensor[SENSORBONE.SHOULDER] ):GetNormal()
|
||||
special_vectors["hips_back"] = special_vectors["hips_up"]:Cross( special_vectors["hips_left"] )
|
||||
special_vectors["hips_fwd"] = special_vectors["hips_back"] * -1
|
||||
|
||||
special_vectors["chest_lft"] = ( sensor[SENSORBONE.SHOULDER_RIGHT] - sensor[SENSORBONE.SHOULDER_LEFT] ):GetNormal()
|
||||
special_vectors["chest_rgt"] = special_vectors["chest_lft"] * -1
|
||||
special_vectors["chest_up"] = ( sensor[SENSORBONE.SPINE] - sensor[SENSORBONE.SHOULDER] ):GetNormal()
|
||||
special_vectors["chest_dn"] = special_vectors["chest_up"] * -1
|
||||
special_vectors["chest_bck"] = special_vectors["chest_up"]:Cross( special_vectors["chest_lft"] )
|
||||
special_vectors["chest_fwd"] = special_vectors["chest_bck"] * -1
|
||||
|
||||
special_vectors["head_up"] = ( sensor[SENSORBONE.SHOULDER] - sensor[SENSORBONE.HEAD] ):GetNormal()
|
||||
special_vectors["head_back"] = special_vectors["head_up"]:Cross( special_vectors["chest_lft"] )
|
||||
|
||||
local reprocess = {}
|
||||
|
||||
for k, v in pairs( translator.AnglesTable ) do
|
||||
|
||||
table.insert( reprocess, k )
|
||||
|
||||
end
|
||||
|
||||
for iPasses = 1, 5 do
|
||||
|
||||
local cur_process = reprocess
|
||||
reprocess = {}
|
||||
|
||||
for k, v in pairs( cur_process ) do
|
||||
|
||||
if ( !motionsensor.ProcessAngle( translator, sensor, pos, ang, special_vectors, v, translator.AnglesTable[v] ) ) then
|
||||
table.insert( reprocess, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( table.IsEmpty( reprocess ) ) then
|
||||
--DebugInfo( 0, iPasses .. " Passes" )
|
||||
return ang
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If we got here then we're doing something wrong.
|
||||
-- It should have out'ed before completing 5 passes.
|
||||
--
|
||||
DebugInfo( 0, "motionsensor.ProcessAnglesTable: 4+ passes!" )
|
||||
return ang
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Processes the PositionTable from a skeleton constructor
|
||||
--
|
||||
motionsensor.ProcessPositionTable = function( translator, sensor )
|
||||
|
||||
if ( !translator.PositionTable ) then return {} end
|
||||
|
||||
local pos = {}
|
||||
|
||||
for k, v in pairs( translator.PositionTable ) do
|
||||
|
||||
-- A number means get value straight from the sensor
|
||||
if ( isnumber( v ) ) then pos[ k ] = sensor[ v ] end
|
||||
|
||||
if ( istable( v ) and v.type == "lerp" ) then
|
||||
|
||||
pos[ k ] = LerpVector( v.value, sensor[ v.from ], sensor[ v.to ] )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return pos
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called to build the skeleton
|
||||
--
|
||||
motionsensor.BuildSkeleton = function( translator, player, rotation )
|
||||
|
||||
--
|
||||
-- The kinect animations are recorded on the skunt, so rotate towards the player
|
||||
--
|
||||
rotation:RotateAroundAxis( rotation:Up(), -90 )
|
||||
|
||||
--
|
||||
-- Pre-get and rotate all the player positions
|
||||
--
|
||||
local sensor = {}
|
||||
for i = 0, 19 do
|
||||
sensor[ i ] = player:MotionSensorPos( i )
|
||||
sensor[ i ]:Rotate( rotation )
|
||||
end
|
||||
|
||||
if ( translator.PrePosition ) then
|
||||
translator:PrePosition( sensor )
|
||||
end
|
||||
|
||||
--
|
||||
-- Fill out the position table..
|
||||
--
|
||||
local pos = motionsensor.ProcessPositionTable( translator, sensor )
|
||||
|
||||
--
|
||||
-- Fill out the angles
|
||||
--
|
||||
local ang = motionsensor.ProcessAnglesTable( translator, sensor, pos, rotation )
|
||||
|
||||
--
|
||||
-- Allow the bone builder to make any last minute changes
|
||||
--
|
||||
translator:Complete( player, sensor, rotation, pos, ang )
|
||||
|
||||
return pos, ang, sensor
|
||||
|
||||
end
|
||||
|
||||
260
lua/includes/extensions/net.lua
Normal file
260
lua/includes/extensions/net.lua
Normal file
@@ -0,0 +1,260 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- This is just enough for the entity index. This however is not perfect
|
||||
-- as the entity at given index may have changed during transport.
|
||||
-- If this becomes a problem, inclusion of entity's serial will also be necessary
|
||||
local MAX_EDICT_BITS = 13
|
||||
|
||||
TYPE_COLOR = 255
|
||||
|
||||
net.Receivers = {}
|
||||
|
||||
--
|
||||
-- Set up a function to receive network messages
|
||||
--
|
||||
function net.Receive( name, func )
|
||||
|
||||
net.Receivers[ name:lower() ] = func
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- A message has been received from the network..
|
||||
--
|
||||
function net.Incoming( len, client )
|
||||
|
||||
local i = net.ReadHeader()
|
||||
local strName = util.NetworkIDToString( i )
|
||||
|
||||
if ( !strName ) then return end
|
||||
|
||||
local func = net.Receivers[ strName:lower() ]
|
||||
if ( !func ) then return end
|
||||
|
||||
--
|
||||
-- len includes the 16 bit int which told us the message name
|
||||
--
|
||||
len = len - 16
|
||||
|
||||
func( len, client )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Read/Write a boolean to the stream
|
||||
--
|
||||
net.WriteBool = net.WriteBit
|
||||
|
||||
function net.ReadBool()
|
||||
|
||||
return net.ReadBit() == 1
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Read/Write an entity to the stream
|
||||
--
|
||||
function net.WriteEntity( ent )
|
||||
|
||||
if ( !IsValid( ent ) ) then
|
||||
net.WriteUInt( 0, MAX_EDICT_BITS )
|
||||
else
|
||||
net.WriteUInt( ent:EntIndex(), MAX_EDICT_BITS )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadEntity()
|
||||
|
||||
local i = net.ReadUInt( MAX_EDICT_BITS )
|
||||
if ( !i ) then return end
|
||||
|
||||
return Entity( i )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Read/Write a player to the stream
|
||||
--
|
||||
function net.WritePlayer( ply )
|
||||
|
||||
if ( !IsValid( ply ) || !ply:IsPlayer() ) then
|
||||
net.WriteUInt( 0, 8 )
|
||||
else
|
||||
net.WriteUInt( ply:EntIndex(), 8 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadPlayer()
|
||||
|
||||
local i = net.ReadUInt( 8 )
|
||||
if ( !i ) then return end
|
||||
|
||||
local ply = Entity( i )
|
||||
return ply
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Read/Write a color to/from the stream
|
||||
--
|
||||
function net.WriteColor( col, writeAlpha )
|
||||
if ( writeAlpha == nil ) then writeAlpha = true end
|
||||
|
||||
assert( IsColor( col ), "net.WriteColor: color expected, got ".. type( col ) )
|
||||
|
||||
local r, g, b, a = col:Unpack()
|
||||
net.WriteUInt( r, 8 )
|
||||
net.WriteUInt( g, 8 )
|
||||
net.WriteUInt( b, 8 )
|
||||
|
||||
if ( writeAlpha ) then
|
||||
net.WriteUInt( a, 8 )
|
||||
end
|
||||
end
|
||||
|
||||
function net.ReadColor( readAlpha )
|
||||
if ( readAlpha == nil ) then readAlpha = true end
|
||||
|
||||
local r, g, b =
|
||||
net.ReadUInt( 8 ),
|
||||
net.ReadUInt( 8 ),
|
||||
net.ReadUInt( 8 )
|
||||
|
||||
local a = 255
|
||||
if ( readAlpha ) then a = net.ReadUInt( 8 ) end
|
||||
|
||||
return Color( r, g, b, a )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Write a whole table to the stream
|
||||
-- This is less optimal than writing each
|
||||
-- item indivdually and in a specific order
|
||||
-- because it adds type information before each var
|
||||
--
|
||||
function net.WriteTable( tab, seq )
|
||||
|
||||
if ( seq ) then
|
||||
|
||||
local len = #tab
|
||||
net.WriteUInt( len, 32 )
|
||||
|
||||
for i = 1, len do
|
||||
|
||||
net.WriteType( tab[ i ] )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
net.WriteType( k )
|
||||
net.WriteType( v )
|
||||
|
||||
end
|
||||
|
||||
-- End of table
|
||||
net.WriteType( nil )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function net.ReadTable( seq )
|
||||
|
||||
local tab = {}
|
||||
|
||||
if ( seq ) then
|
||||
|
||||
for i = 1, net.ReadUInt( 32 ) do
|
||||
|
||||
tab[ i ] = net.ReadType()
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
while true do
|
||||
|
||||
local k = net.ReadType()
|
||||
if ( k == nil ) then break end
|
||||
|
||||
tab[ k ] = net.ReadType()
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tab
|
||||
|
||||
end
|
||||
|
||||
net.WriteVars =
|
||||
{
|
||||
[TYPE_NIL] = function ( t, v ) net.WriteUInt( t, 8 ) end,
|
||||
[TYPE_STRING] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteString( v ) end,
|
||||
[TYPE_NUMBER] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteDouble( v ) end,
|
||||
[TYPE_TABLE] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteTable( v ) end,
|
||||
[TYPE_BOOL] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteBool( v ) end,
|
||||
[TYPE_ENTITY] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteEntity( v ) end,
|
||||
[TYPE_VECTOR] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteVector( v ) end,
|
||||
[TYPE_ANGLE] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteAngle( v ) end,
|
||||
[TYPE_MATRIX] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteMatrix( v ) end,
|
||||
[TYPE_COLOR] = function ( t, v ) net.WriteUInt( t, 8 ) net.WriteColor( v ) end,
|
||||
}
|
||||
|
||||
function net.WriteType( v )
|
||||
local typeid = nil
|
||||
|
||||
if IsColor( v ) then
|
||||
typeid = TYPE_COLOR
|
||||
else
|
||||
typeid = TypeID( v )
|
||||
end
|
||||
|
||||
local wv = net.WriteVars[ typeid ]
|
||||
if ( wv ) then return wv( typeid, v ) end
|
||||
|
||||
error( "net.WriteType: Couldn't write " .. type( v ) .. " (type " .. typeid .. ")" )
|
||||
|
||||
end
|
||||
|
||||
net.ReadVars =
|
||||
{
|
||||
[TYPE_NIL] = function () return nil end,
|
||||
[TYPE_STRING] = function () return net.ReadString() end,
|
||||
[TYPE_NUMBER] = function () return net.ReadDouble() end,
|
||||
[TYPE_TABLE] = function () return net.ReadTable() end,
|
||||
[TYPE_BOOL] = function () return net.ReadBool() end,
|
||||
[TYPE_ENTITY] = function () return net.ReadEntity() end,
|
||||
[TYPE_VECTOR] = function () return net.ReadVector() end,
|
||||
[TYPE_ANGLE] = function () return net.ReadAngle() end,
|
||||
[TYPE_MATRIX] = function () return net.ReadMatrix() end,
|
||||
[TYPE_COLOR] = function () return net.ReadColor() end,
|
||||
}
|
||||
|
||||
function net.ReadType( typeid )
|
||||
|
||||
typeid = typeid or net.ReadUInt( 8 )
|
||||
|
||||
local rv = net.ReadVars[ typeid ]
|
||||
if ( rv ) then return rv() end
|
||||
|
||||
error( "net.ReadType: Couldn't read type " .. typeid )
|
||||
|
||||
end
|
||||
339
lua/includes/extensions/player.lua
Normal file
339
lua/includes/extensions/player.lua
Normal file
@@ -0,0 +1,339 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
local entity = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[key]
|
||||
if ( val ~= nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity metatable
|
||||
--
|
||||
local entval = entity[key]
|
||||
if ( entval ~= nil ) then return entval end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = entity.GetTable( self )
|
||||
if ( tab ) then
|
||||
return tab[ key ]
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
if ( !sql.TableExists( "playerpdata" ) ) then
|
||||
|
||||
sql.Query( "CREATE TABLE IF NOT EXISTS playerpdata ( infoid TEXT NOT NULL PRIMARY KEY, value TEXT );" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: DebugInfo
|
||||
Desc: Prints debug information for the player
|
||||
( this is just an example )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:DebugInfo()
|
||||
|
||||
Msg( "Name: " .. self:Name() .. "\n" )
|
||||
Msg( "Pos: " .. tostring( self:GetPos() ) .. "\n" )
|
||||
|
||||
end
|
||||
|
||||
-- Helpful aliases
|
||||
meta.GetName = meta.Nick
|
||||
meta.Name = meta.Nick
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: ConCommand
|
||||
Desc: Overrides the default ConCommand function
|
||||
-----------------------------------------------------------]]
|
||||
if ( CLIENT ) then
|
||||
|
||||
local SendConCommand = meta.ConCommand
|
||||
local CommandList = nil
|
||||
|
||||
function meta:ConCommand( command, bSkipQueue )
|
||||
|
||||
if ( bSkipQueue or IsConCommandBlocked( command ) ) then
|
||||
SendConCommand( self, command )
|
||||
else
|
||||
CommandList = CommandList or {}
|
||||
table.insert( CommandList, command )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local function SendQueuedConsoleCommands()
|
||||
|
||||
if ( !CommandList ) then return end
|
||||
|
||||
local BytesSent = 0
|
||||
|
||||
for k, v in pairs( CommandList ) do
|
||||
|
||||
SendConCommand( LocalPlayer(), v )
|
||||
CommandList[ k ] = nil
|
||||
|
||||
-- Only send x bytes per tick
|
||||
BytesSent = BytesSent + v:len()
|
||||
if ( BytesSent > 128 ) then
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- Turn the table into a nil so we can return easy
|
||||
if ( table.IsEmpty( CommandList ) ) then
|
||||
|
||||
CommandList = nil
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "Tick", "SendQueuedConsoleCommands", SendQueuedConsoleCommands )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetPData
|
||||
Saves persist data for this player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetPData( name, default )
|
||||
|
||||
-- First try looking up using the new key
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( key ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then
|
||||
|
||||
-- Not found? Look using the old key
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then return default end
|
||||
|
||||
end
|
||||
|
||||
return val
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
SetPData
|
||||
Set persistant data
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetPData( name, value )
|
||||
|
||||
-- Remove old value
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) )
|
||||
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
return sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( " .. SQLStr( key ) .. ", " .. SQLStr( value ) .. " )" ) ~= false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
RemovePData
|
||||
Remove persistant data
|
||||
-----------------------------------------------------------]]
|
||||
function meta:RemovePData( name )
|
||||
|
||||
-- First old key
|
||||
local oldkey = Format( "%s[%s]", self:UniqueID(), name )
|
||||
local removed = sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) ) ~= false
|
||||
|
||||
-- Then new key
|
||||
local key = Format( "%s[%s]", self:SteamID64(), name )
|
||||
local removed2 = sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( key ) ) ~= false
|
||||
|
||||
return removed or removed2
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- If they have their preferred default weapon then switch to it
|
||||
--
|
||||
function meta:SwitchToDefaultWeapon()
|
||||
|
||||
local weapon = self:GetInfo( "cl_defaultweapon" )
|
||||
|
||||
if ( self:HasWeapon( weapon ) ) then
|
||||
self:SelectWeapon( weapon )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Can use flashlight?
|
||||
--
|
||||
function meta:AllowFlashlight( bAble ) self.m_bFlashlight = bAble end
|
||||
function meta:CanUseFlashlight() return self.m_bFlashlight == true end
|
||||
|
||||
-- A function to set up player hands, so coders don't have to copy all the code everytime.
|
||||
-- Call this in PlayerSpawn hook
|
||||
function meta:SetupHands( ply )
|
||||
|
||||
local oldhands = self:GetHands()
|
||||
if ( IsValid( oldhands ) ) then
|
||||
oldhands:Remove()
|
||||
end
|
||||
|
||||
local hands = ents.Create( "gmod_hands" )
|
||||
if ( IsValid( hands ) ) then
|
||||
hands:DoSetup( self, ply )
|
||||
hands:Spawn()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Those functions have been removed from the engine since AddFlag and RemoveFlag
|
||||
-- made them obsolete, but we'll keep a Lua version of them for backward compatibility
|
||||
--
|
||||
if ( SERVER ) then
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Freeze
|
||||
Freezes or unfreezes the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:Freeze( b )
|
||||
|
||||
if ( b ) then
|
||||
self:AddFlags( FL_FROZEN )
|
||||
else
|
||||
self:RemoveFlags( FL_FROZEN )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GodEnable
|
||||
Enables godmode on the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GodEnable()
|
||||
|
||||
self:AddFlags( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GodDisable
|
||||
Disables godmode on the player
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GodDisable()
|
||||
|
||||
self:RemoveFlags( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
IsFrozen
|
||||
Returns true if the player is frozen
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsFrozen()
|
||||
|
||||
return self:IsFlagSet( FL_FROZEN )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
HasGodMode
|
||||
Returns true if the player is in godmode
|
||||
-----------------------------------------------------------]]
|
||||
function meta:HasGodMode()
|
||||
|
||||
return self:IsFlagSet( FL_GODMODE )
|
||||
|
||||
end
|
||||
|
||||
-- These are totally in the wrong place.
|
||||
function player.GetByAccountID( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:AccountID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetByUniqueID( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:UniqueID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetBySteamID( ID )
|
||||
ID = string.upper( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:SteamID() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function player.GetBySteamID64( ID )
|
||||
ID = tostring( ID )
|
||||
local players = player.GetAll()
|
||||
for i = 1, #players do
|
||||
if ( players[i]:SteamID64() == ID ) then
|
||||
return players[i]
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local inext = ipairs( {} )
|
||||
local PlayerCache = nil
|
||||
|
||||
function player.Iterator()
|
||||
|
||||
if ( PlayerCache == nil ) then PlayerCache = player.GetAll() end
|
||||
|
||||
return inext, PlayerCache, 0
|
||||
|
||||
end
|
||||
|
||||
local function InvalidatePlayerCache( ent )
|
||||
|
||||
if ( ent:IsPlayer() ) then PlayerCache = nil end
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "OnEntityCreated", "player.Iterator", InvalidatePlayerCache )
|
||||
hook.Add( "EntityRemoved", "player.Iterator", InvalidatePlayerCache )
|
||||
139
lua/includes/extensions/player_auth.lua
Normal file
139
lua/includes/extensions/player_auth.lua
Normal file
@@ -0,0 +1,139 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local meta = FindMetaTable( "Player" )
|
||||
if ( not meta ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsAdmin
|
||||
Desc: Returns if a player is an admin.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsAdmin()
|
||||
|
||||
if ( self:IsSuperAdmin() ) then return true end
|
||||
if ( self:IsUserGroup( "admin" ) ) then return true end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsSuperAdmin
|
||||
Desc: Returns if a player is a superadmin.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsSuperAdmin()
|
||||
|
||||
return self:IsUserGroup( "superadmin" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsUserGroup
|
||||
Desc: Returns if a player is in the specified usergroup.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:IsUserGroup( name )
|
||||
|
||||
if ( not self:IsValid() ) then return false end
|
||||
|
||||
return self:GetUserGroup() == name
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetUserGroup
|
||||
Desc: Returns the player's usergroup.
|
||||
-----------------------------------------------------------]]
|
||||
function meta:GetUserGroup()
|
||||
|
||||
return self:GetNWString( "UserGroup", "user" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
This is the meat and spunk of the player auth system
|
||||
-----------------------------------------------------------]]
|
||||
|
||||
if ( not SERVER ) then return end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetUserGroup
|
||||
Desc: Sets the player's usergroup. ( Serverside Only )
|
||||
-----------------------------------------------------------]]
|
||||
function meta:SetUserGroup( name )
|
||||
|
||||
self:SetNWString( "UserGroup", name )
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- SteamIds table..
|
||||
-- STEAM_0:1:7099:
|
||||
-- name = garry
|
||||
-- group = superadmin
|
||||
|
||||
local SteamIDs = {}
|
||||
|
||||
local function LoadUsersFile()
|
||||
|
||||
local txt = file.Read( "settings/users.txt", "MOD" )
|
||||
if ( not txt ) then MsgN( "Failed to load settings/users.txt!" ) return end
|
||||
|
||||
-- Load the users file
|
||||
local UsersKV = util.KeyValuesToTable( txt )
|
||||
if ( not UsersKV ) then MsgN( "Failed to parse settings/users.txt!" ) return end
|
||||
|
||||
SteamIDs = {}
|
||||
|
||||
-- Extract the data into the SteamIDs table
|
||||
for key, tab in pairs( UsersKV ) do
|
||||
for name, steamid in pairs( tab ) do
|
||||
SteamIDs[ steamid ] = {}
|
||||
SteamIDs[ steamid ].name = name
|
||||
SteamIDs[ steamid ].group = key
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
LoadUsersFile()
|
||||
|
||||
function util.GetUserGroups()
|
||||
|
||||
return SteamIDs
|
||||
|
||||
end
|
||||
|
||||
hook.Add( "PlayerInitialSpawn", "PlayerAuthSpawn", function( ply )
|
||||
|
||||
local steamid = ply:SteamID()
|
||||
|
||||
if ( game.SinglePlayer() or ply:IsListenServerHost() ) then
|
||||
ply:SetUserGroup( "superadmin" )
|
||||
return
|
||||
end
|
||||
|
||||
if ( SteamIDs[ steamid ] == nil ) then
|
||||
ply:SetUserGroup( "user" )
|
||||
return
|
||||
end
|
||||
|
||||
-- Admin SteamID need to be fully authenticated by Steam!
|
||||
if ( ply.IsFullyAuthenticated and not ply:IsFullyAuthenticated() ) then
|
||||
ply:ChatPrint( string.format( "Hey '%s' - Your SteamID wasn't fully authenticated, so your usergroup has not been set to '%s'.", SteamIDs[ steamid ].name, SteamIDs[ steamid ].group ) )
|
||||
ply:ChatPrint( "Try restarting Steam." )
|
||||
return
|
||||
end
|
||||
|
||||
ply:SetUserGroup( SteamIDs[ steamid ].group )
|
||||
ply:ChatPrint( string.format( "Hey '%s' - You're in the '%s' group on this server.", SteamIDs[ steamid ].name, SteamIDs[ steamid ].group ) )
|
||||
|
||||
end )
|
||||
461
lua/includes/extensions/string.lua
Normal file
461
lua/includes/extensions/string.lua
Normal file
@@ -0,0 +1,461 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
local string = string
|
||||
local math = math
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.ToTable( string )
|
||||
-----------------------------------------------------------]]
|
||||
function string.ToTable( input )
|
||||
local tbl = {}
|
||||
|
||||
-- For numbers, as some addons do this..
|
||||
local str = tostring( input )
|
||||
|
||||
for i = 1, #str do
|
||||
tbl[i] = string.sub( str, i, i )
|
||||
end
|
||||
|
||||
return tbl
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.JavascriptSafe( string )
|
||||
Desc: Takes a string and escapes it for insertion in to a JavaScript string
|
||||
-----------------------------------------------------------]]
|
||||
local javascript_escape_replacements = {
|
||||
["\\"] = "\\\\",
|
||||
["\0"] = "\\x00" ,
|
||||
["\b"] = "\\b" ,
|
||||
["\t"] = "\\t" ,
|
||||
["\n"] = "\\n" ,
|
||||
["\v"] = "\\v" ,
|
||||
["\f"] = "\\f" ,
|
||||
["\r"] = "\\r" ,
|
||||
["\""] = "\\\"",
|
||||
["\'"] = "\\\'",
|
||||
["`"] = "\\`",
|
||||
["$"] = "\\$",
|
||||
["{"] = "\\{",
|
||||
["}"] = "\\}"
|
||||
}
|
||||
|
||||
function string.JavascriptSafe( str )
|
||||
|
||||
str = string.gsub( str, ".", javascript_escape_replacements )
|
||||
|
||||
-- U+2028 and U+2029 are treated as line separators in JavaScript, handle separately as they aren't single-byte
|
||||
str = string.gsub( str, "\226\128\168", "\\\226\128\168" )
|
||||
str = string.gsub( str, "\226\128\169", "\\\226\128\169" )
|
||||
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: string.PatternSafe( string )
|
||||
Desc: Takes a string and escapes it for insertion in to a Lua pattern
|
||||
-----------------------------------------------------------]]
|
||||
local pattern_escape_replacements = {
|
||||
["("] = "%(",
|
||||
[")"] = "%)",
|
||||
["."] = "%.",
|
||||
["%"] = "%%",
|
||||
["+"] = "%+",
|
||||
["-"] = "%-",
|
||||
["*"] = "%*",
|
||||
["?"] = "%?",
|
||||
["["] = "%[",
|
||||
["]"] = "%]",
|
||||
["^"] = "%^",
|
||||
["$"] = "%$",
|
||||
["\0"] = "%z"
|
||||
}
|
||||
|
||||
function string.PatternSafe( str )
|
||||
return ( string.gsub( str, ".", pattern_escape_replacements ) )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: explode(seperator ,string)
|
||||
Desc: Takes a string and turns it into a table
|
||||
Usage: string.explode( " ", "Seperate this string")
|
||||
-----------------------------------------------------------]]
|
||||
local totable = string.ToTable
|
||||
local string_sub = string.sub
|
||||
local string_find = string.find
|
||||
local string_len = string.len
|
||||
function string.Explode( separator, str, withpattern )
|
||||
if ( separator == "" ) then return totable( str ) end
|
||||
if ( withpattern == nil ) then withpattern = false end
|
||||
|
||||
local ret = {}
|
||||
local current_pos = 1
|
||||
|
||||
for i = 1, string_len( str ) do
|
||||
local start_pos, end_pos = string_find( str, separator, current_pos, not withpattern )
|
||||
if ( not start_pos ) then break end
|
||||
ret[ i ] = string_sub( str, current_pos, start_pos - 1 )
|
||||
current_pos = end_pos + 1
|
||||
end
|
||||
|
||||
ret[ #ret + 1 ] = string_sub( str, current_pos )
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
function string.Split( str, delimiter )
|
||||
return string.Explode( delimiter, str )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Implode( seperator, Table)
|
||||
Desc: Takes a table and turns it into a string
|
||||
Usage: string.Implode( " ", { "This", "Is", "A", "Table" } )
|
||||
-----------------------------------------------------------]]
|
||||
function string.Implode( seperator, Table ) return
|
||||
table.concat( Table, seperator )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetExtensionFromFilename( path )
|
||||
Desc: Returns extension from path
|
||||
Usage: string.GetExtensionFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetExtensionFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return nil end
|
||||
if ( c == "." ) then return string.sub( path, i + 1 ) end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: StripExtension( path )
|
||||
-----------------------------------------------------------]]
|
||||
function string.StripExtension( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return path end
|
||||
if ( c == "." ) then return string.sub( path, 1, i - 1 ) end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPathFromFilename( path )
|
||||
Desc: Returns path from filepath
|
||||
Usage: string.GetPathFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetPathFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return string.sub( path, 1, i ) end
|
||||
end
|
||||
|
||||
return ""
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetFileFromFilename( path )
|
||||
Desc: Returns file with extension from path
|
||||
Usage: string.GetFileFromFilename("garrysmod/lua/modules/string.lua")
|
||||
-----------------------------------------------------------]]
|
||||
function string.GetFileFromFilename( path )
|
||||
for i = #path, 1, -1 do
|
||||
local c = string.sub( path, i, i )
|
||||
if ( c == "/" or c == "\\" ) then return string.sub( path, i + 1 ) end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
--[[-----------------------------------------------------------------
|
||||
Name: FormattedTime( TimeInSeconds, Format )
|
||||
Desc: Given a time in seconds, returns formatted time
|
||||
If 'Format' is not specified the function returns a table
|
||||
conatining values for hours, mins, secs, ms
|
||||
|
||||
Examples: string.FormattedTime( 123.456, "%02i:%02i:%02i") ==> "02:03:45"
|
||||
string.FormattedTime( 123.456, "%02i:%02i") ==> "02:03"
|
||||
string.FormattedTime( 123.456, "%2i:%02i") ==> " 2:03"
|
||||
string.FormattedTime( 123.456 ) ==> { h = 0, m = 2, s = 3, ms = 45 }
|
||||
-------------------------------------------------------------------]]
|
||||
function string.FormattedTime( seconds, format )
|
||||
if ( not seconds ) then seconds = 0 end
|
||||
local hours = math.floor( seconds / 3600 )
|
||||
local minutes = math.floor( ( seconds / 60 ) % 60 )
|
||||
local millisecs = ( seconds - math.floor( seconds ) ) * 100
|
||||
seconds = math.floor( seconds % 60 )
|
||||
|
||||
if ( format ) then
|
||||
return string.format( format, minutes, seconds, millisecs )
|
||||
else
|
||||
return { h = hours, m = minutes, s = seconds, ms = millisecs }
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Old time functions
|
||||
-----------------------------------------------------------]]
|
||||
function string.ToMinutesSecondsMilliseconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i:%02i" ) end
|
||||
function string.ToMinutesSeconds( TimeInSeconds ) return string.FormattedTime( TimeInSeconds, "%02i:%02i" ) end
|
||||
|
||||
local function pluralizeString( str, quantity )
|
||||
return str .. ( ( quantity ~= 1 ) and "s" or "" )
|
||||
end
|
||||
|
||||
function string.NiceTime( seconds )
|
||||
|
||||
if ( seconds == nil ) then return "a few seconds" end
|
||||
|
||||
if ( seconds < 60 ) then
|
||||
local t = math.floor( seconds )
|
||||
return t .. pluralizeString( " second", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 ) then
|
||||
local t = math.floor( seconds / 60 )
|
||||
return t .. pluralizeString( " minute", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 ) then
|
||||
local t = math.floor( seconds / (60 * 60) )
|
||||
return t .. pluralizeString( " hour", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 * 7 ) then
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 ) )
|
||||
return t .. pluralizeString( " day", t )
|
||||
end
|
||||
|
||||
if ( seconds < 60 * 60 * 24 * 365 ) then
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 * 7 ) )
|
||||
return t .. pluralizeString( " week", t )
|
||||
end
|
||||
|
||||
local t = math.floor( seconds / ( 60 * 60 * 24 * 365 ) )
|
||||
return t .. pluralizeString( " year", t )
|
||||
|
||||
end
|
||||
|
||||
function string.Left( str, num ) return string.sub( str, 1, num ) end
|
||||
function string.Right( str, num ) return string.sub( str, -num ) end
|
||||
|
||||
function string.Replace( str, tofind, toreplace )
|
||||
local tbl = string.Explode( tofind, str )
|
||||
if ( tbl[ 1 ] ) then return table.concat( tbl, toreplace ) end
|
||||
return str
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Trim( s )
|
||||
Desc: Removes leading and trailing spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.Trim( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^" .. char .. "*(.-)" .. char .. "*$" ) or s
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TrimRight( s )
|
||||
Desc: Removes trailing spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.TrimRight( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^(.-)" .. char .. "*$" ) or s
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: TrimLeft( s )
|
||||
Desc: Removes leading spaces from a string.
|
||||
Optionally pass char to trim that character from the ends instead of space
|
||||
-----------------------------------------------------------]]
|
||||
function string.TrimLeft( s, char )
|
||||
if ( char ) then char = string.PatternSafe( char ) else char = "%s" end
|
||||
return string.match( s, "^" .. char .. "*(.+)$" ) or s
|
||||
end
|
||||
|
||||
function string.NiceSize( size )
|
||||
|
||||
size = tonumber( size )
|
||||
|
||||
if ( size <= 0 ) then return "0" end
|
||||
if ( size < 1000 ) then return size .. " Bytes" end
|
||||
if ( size < 1000 * 1000 ) then return math.Round( size / 1000, 2 ) .. " KB" end
|
||||
if ( size < 1000 * 1000 * 1000 ) then return math.Round( size / ( 1000 * 1000 ), 2 ) .. " MB" end
|
||||
|
||||
return math.Round( size / ( 1000 * 1000 * 1000 ), 2 ) .. " GB"
|
||||
|
||||
end
|
||||
|
||||
-- Note: These use Lua index numbering, not what you'd expect
|
||||
-- ie they start from 1, not 0.
|
||||
|
||||
function string.SetChar( s, k, v )
|
||||
|
||||
return string.sub( s, 0, k - 1 ) .. v .. string.sub( s, k + 1 )
|
||||
|
||||
end
|
||||
|
||||
function string.GetChar( s, k )
|
||||
|
||||
return string.sub( s, k, k )
|
||||
|
||||
end
|
||||
|
||||
local meta = getmetatable( "" )
|
||||
|
||||
function meta:__index( key )
|
||||
|
||||
local val = string[ key ]
|
||||
if ( val ~= nil ) then
|
||||
return val
|
||||
elseif ( tonumber( key ) ) then
|
||||
return string.sub( self, key, key )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function string.StartsWith( str, start )
|
||||
|
||||
return string.sub( str, 1, string.len( start ) ) == start
|
||||
|
||||
end
|
||||
string.StartWith = string.StartsWith
|
||||
|
||||
function string.EndsWith( str, endStr )
|
||||
|
||||
return endStr == "" or string.sub( str, -string.len( endStr ) ) == endStr
|
||||
|
||||
end
|
||||
|
||||
function string.FromColor( color )
|
||||
|
||||
return Format( "%i %i %i %i", color.r, color.g, color.b, color.a )
|
||||
|
||||
end
|
||||
|
||||
function string.ToColor( str )
|
||||
|
||||
local r, g, b, a = string.match( str, "(%d+) (%d+) (%d+) (%d+)" )
|
||||
|
||||
local col = Color( 255, 255, 255, 255 )
|
||||
col.r = tonumber( r ) or 255
|
||||
col.g = tonumber( g ) or 255
|
||||
col.b = tonumber( b ) or 255
|
||||
col.a = tonumber( a ) or 255
|
||||
|
||||
return col
|
||||
|
||||
end
|
||||
|
||||
function string.Comma( number, str )
|
||||
|
||||
if ( str ~= nil and not isstring( str ) ) then
|
||||
error( "bad argument #2 to 'string.Comma' (string expected, got " .. type( str ) .. ")" )
|
||||
elseif ( str ~= nil and string.match( str, "%d" ) ~= nil ) then
|
||||
error( "bad argument #2 to 'string.Comma' (non-numerical values expected, got " .. str .. ")" )
|
||||
end
|
||||
|
||||
local replace = str == nil and "%1,%2" or "%1" .. str .. "%2"
|
||||
|
||||
if ( isnumber( number ) ) then
|
||||
number = string.format( "%f", number )
|
||||
number = string.match( number, "^(.-)%.?0*$" ) -- Remove trailing zeros
|
||||
end
|
||||
|
||||
local index = -1
|
||||
while index ~= 0 do number, index = string.gsub( number, "^(-?%d+)(%d%d%d)", replace ) end
|
||||
|
||||
return number
|
||||
|
||||
end
|
||||
|
||||
function string.Interpolate( str, lookuptable )
|
||||
|
||||
return ( string.gsub( str, "{([_%a][_%w]*)}", lookuptable ) )
|
||||
|
||||
end
|
||||
|
||||
function string.CardinalToOrdinal( cardinal )
|
||||
|
||||
local basedigit = cardinal % 10
|
||||
|
||||
if ( basedigit == 1 ) then
|
||||
if ( cardinal % 100 == 11 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "st"
|
||||
elseif ( basedigit == 2 ) then
|
||||
if ( cardinal % 100 == 12 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "nd"
|
||||
elseif ( basedigit == 3 ) then
|
||||
if ( cardinal % 100 == 13 ) then
|
||||
return cardinal .. "th"
|
||||
end
|
||||
|
||||
return cardinal .. "rd"
|
||||
end
|
||||
|
||||
return cardinal .. "th"
|
||||
|
||||
end
|
||||
|
||||
function string.NiceName( name )
|
||||
|
||||
name = name:Replace( "_", " " )
|
||||
|
||||
-- Try to split text into words, where words would start with single uppercase character
|
||||
local newParts = {}
|
||||
for id, str in ipairs( string.Explode( " ", name ) ) do
|
||||
local wordStart = 1
|
||||
for i = 2, str:len() do
|
||||
local c = str[ i ]
|
||||
if ( c:upper() == c ) then
|
||||
local toAdd = str:sub( wordStart, i - 1 )
|
||||
if ( toAdd:upper() == toAdd ) then continue end
|
||||
table.insert( newParts, toAdd )
|
||||
wordStart = i
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.insert( newParts, str:sub( wordStart, str:len() ) )
|
||||
end
|
||||
|
||||
-- Capitalize
|
||||
--[[
|
||||
for i, word in ipairs( newParts ) do
|
||||
if ( #word == 1 ) then
|
||||
newParts[i] = string.upper( word )
|
||||
else
|
||||
newParts[i] = string.upper( string.sub( word, 1, 1 ) ) .. string.sub( word, 2 )
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat( newParts, " " )]]
|
||||
|
||||
local ret = table.concat( newParts, " " )
|
||||
ret = string.upper( string.sub( ret, 1, 1 ) ) .. string.sub( ret, 2 )
|
||||
return ret
|
||||
|
||||
end
|
||||
815
lua/includes/extensions/table.lua
Normal file
815
lua/includes/extensions/table.lua
Normal file
@@ -0,0 +1,815 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
function table.Pack( ... )
|
||||
return { ... }, select( "#", ... )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Inherit( t, base )
|
||||
Desc: Copies any missing data from base to t
|
||||
-----------------------------------------------------------]]
|
||||
function table.Inherit( t, base )
|
||||
|
||||
for k, v in pairs( base ) do
|
||||
if ( t[ k ] == nil ) then t[ k ] = v end
|
||||
end
|
||||
|
||||
t[ "BaseClass" ] = base
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Copy(t, lookup_table)
|
||||
Desc: Taken straight from http://lua-users.org/wiki/PitLibTablestuff
|
||||
and modified to the new Lua 5.1 code by me.
|
||||
Original function by PeterPrade!
|
||||
-----------------------------------------------------------]]
|
||||
function table.Copy( t, lookup_table )
|
||||
if ( t == nil ) then return nil end
|
||||
|
||||
local copy = {}
|
||||
setmetatable( copy, debug.getmetatable( t ) )
|
||||
for i, v in pairs( t ) do
|
||||
if ( !istable( v ) ) then
|
||||
copy[ i ] = v
|
||||
else
|
||||
lookup_table = lookup_table or {}
|
||||
lookup_table[ t ] = copy
|
||||
if ( lookup_table[ v ] ) then
|
||||
copy[ i ] = lookup_table[ v ] -- we already copied this table. reuse the copy.
|
||||
else
|
||||
copy[ i ] = table.Copy( v, lookup_table ) -- not yet copied. copy it.
|
||||
end
|
||||
end
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Empty( tab )
|
||||
Desc: Empty a table
|
||||
-----------------------------------------------------------]]
|
||||
function table.Empty( tab )
|
||||
for k, v in pairs( tab ) do
|
||||
tab[ k ] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsEmpty( tab )
|
||||
Desc: Returns whether a table has iterable items in it, useful for non-sequential tables
|
||||
-----------------------------------------------------------]]
|
||||
function table.IsEmpty( tab )
|
||||
return next( tab ) == nil
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: CopyFromTo( FROM, TO )
|
||||
Desc: Make TO exactly the same as FROM - but still the same table.
|
||||
-----------------------------------------------------------]]
|
||||
function table.CopyFromTo( from, to )
|
||||
|
||||
-- Erase values from table TO
|
||||
table.Empty( to )
|
||||
|
||||
-- Copy values over
|
||||
table.Merge( to, from )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: Merge
|
||||
Desc: xx
|
||||
-----------------------------------------------------------]]
|
||||
function table.Merge( dest, source, forceOverride )
|
||||
|
||||
for k, v in pairs( source ) do
|
||||
if ( !forceOverride and istable( v ) and istable( dest[ k ] ) ) then
|
||||
-- don't overwrite one table with another
|
||||
-- instead merge them recurisvely
|
||||
table.Merge( dest[ k ], v )
|
||||
else
|
||||
dest[ k ] = v
|
||||
end
|
||||
end
|
||||
|
||||
return dest
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: HasValue
|
||||
Desc: Returns whether the value is in given table
|
||||
-----------------------------------------------------------]]
|
||||
function table.HasValue( t, val )
|
||||
for k, v in pairs( t ) do
|
||||
if ( v == val ) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Add( dest, source )
|
||||
Desc: Unlike merge this adds the two tables together and discards keys.
|
||||
-----------------------------------------------------------]]
|
||||
function table.Add( dest, source )
|
||||
-- The tables should be different otherwise this will just freeze the whole game
|
||||
if ( dest == source ) then return dest end
|
||||
|
||||
-- At least one of them needs to be a table or this whole thing will fall on its ass
|
||||
if ( !istable( source ) ) then return dest end
|
||||
if ( !istable( dest ) ) then dest = {} end
|
||||
|
||||
for k, v in pairs( source ) do
|
||||
table.insert( dest, v )
|
||||
end
|
||||
|
||||
return dest
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortDesc( table )
|
||||
Desc: Like Lua's default sort, but descending
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortDesc( t )
|
||||
return table.sort( t, function( a, b ) return a > b end )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortByKey( table )
|
||||
Desc: Returns a table sorted numerically by Key value
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortByKey( t, desc )
|
||||
|
||||
local temp = {}
|
||||
|
||||
for key, _ in pairs( t ) do table.insert( temp, key ) end
|
||||
if ( desc ) then
|
||||
table.sort( temp, function( a, b ) return t[ a ] < t[ b ] end )
|
||||
else
|
||||
table.sort( temp, function( a, b ) return t[ a ] > t[ b ] end )
|
||||
end
|
||||
|
||||
return temp
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Count( table )
|
||||
Desc: Returns the number of keys in a table
|
||||
-----------------------------------------------------------]]
|
||||
function table.Count( t )
|
||||
local i = 0
|
||||
for k in pairs( t ) do i = i + 1 end
|
||||
return i
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Random( table )
|
||||
Desc: Return a random key
|
||||
-----------------------------------------------------------]]
|
||||
function table.Random( t )
|
||||
local rk = math.random( 1, table.Count( t ) )
|
||||
local i = 1
|
||||
for k, v in pairs( t ) do
|
||||
if ( i == rk ) then return v, k end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Shuffle( table )
|
||||
Desc: Performs an inline Fisher-Yates shuffle on the table in O(n) time
|
||||
-----------------------------------------------------------]]
|
||||
function table.Shuffle( t )
|
||||
local n = #t
|
||||
for i = 1, n - 1 do
|
||||
local j = math.random( i, n )
|
||||
t[ i ], t[ j ] = t[ j ], t[ i ]
|
||||
end
|
||||
end
|
||||
|
||||
--[[----------------------------------------------------------------------
|
||||
Name: table.IsSequential( table )
|
||||
Desc: Returns true if the tables
|
||||
keys are sequential
|
||||
-------------------------------------------------------------------------]]
|
||||
function table.IsSequential( t )
|
||||
local i = 1
|
||||
for key, value in pairs( t ) do
|
||||
if ( t[ i ] == nil ) then return false end
|
||||
i = i + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.ToString( table,name,nice )
|
||||
Desc: Convert a simple table to a string
|
||||
table = the table you want to convert (table)
|
||||
name = the name of the table (string)
|
||||
nice = whether to add line breaks and indents (bool)
|
||||
-----------------------------------------------------------]]
|
||||
local function MakeTable( t, nice, indent, done )
|
||||
local str = ""
|
||||
done = done or {}
|
||||
indent = indent or 0
|
||||
|
||||
local idt = ""
|
||||
if ( nice ) then idt = string.rep( "\t", indent ) end
|
||||
|
||||
local nl, tab = "", ""
|
||||
if ( nice ) then nl, tab = "\n", "\t" end
|
||||
|
||||
local sequential = table.IsSequential( t )
|
||||
|
||||
for key, value in pairs( t ) do
|
||||
|
||||
str = str .. idt .. tab .. tab
|
||||
|
||||
if !sequential then
|
||||
if ( isnumber( key ) or isbool( key ) ) then
|
||||
key = "[" .. tostring( key ) .. "]" .. tab .. "="
|
||||
else
|
||||
key = tostring( key ) .. tab .. "="
|
||||
end
|
||||
else
|
||||
key = ""
|
||||
end
|
||||
|
||||
if ( istable( value ) and !done[ value ] ) then
|
||||
|
||||
if ( IsColor( value ) ) then
|
||||
done[ value ] = true
|
||||
value = "Color(" .. value.r .. "," .. value.g .. "," .. value.b .. "," .. value.a .. ")"
|
||||
str = str .. key .. tab .. value .. "," .. nl
|
||||
else
|
||||
done[ value ] = true
|
||||
str = str .. key .. tab .. '{' .. nl .. MakeTable( value, nice, indent + 1, done )
|
||||
str = str .. idt .. tab .. tab .. tab .. tab .. "}," .. nl
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
if ( isstring( value ) ) then
|
||||
value = '"' .. tostring( value ) .. '"'
|
||||
elseif ( isvector( value ) ) then
|
||||
value = "Vector(" .. value.x .. "," .. value.y .. "," .. value.z .. ")"
|
||||
elseif ( isangle( value ) ) then
|
||||
value = "Angle(" .. value.pitch .. "," .. value.yaw .. "," .. value.roll .. ")"
|
||||
else
|
||||
value = tostring( value )
|
||||
end
|
||||
|
||||
str = str .. key .. tab .. value .. "," .. nl
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
return str
|
||||
end
|
||||
|
||||
function table.ToString( t, n, nice )
|
||||
local nl, tab = "", ""
|
||||
if ( nice ) then nl, tab = "\n", "\t" end
|
||||
|
||||
local str = ""
|
||||
if ( n ) then str = n .. tab .. "=" .. tab end
|
||||
return str .. "{" .. nl .. MakeTable( t, nice ) .. "}"
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.Sanitise( table )
|
||||
Desc: Converts a table containing vectors, angles, bools so it can be converted to and from keyvalues
|
||||
-----------------------------------------------------------]]
|
||||
function table.Sanitise( t, done )
|
||||
|
||||
done = done or {}
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs ( t ) do
|
||||
|
||||
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
|
||||
|
||||
done[ v ] = true
|
||||
tbl[ k ] = table.Sanitise( v, done )
|
||||
|
||||
else
|
||||
|
||||
if ( isvector( v ) ) then
|
||||
|
||||
local x, y, z = v.x, v.y, v.z
|
||||
if y == 0 then y = nil end
|
||||
if z == 0 then z = nil end
|
||||
tbl[ k ] = { __type = "Vector", x = x, y = y, z = z }
|
||||
|
||||
elseif ( isangle( v ) ) then
|
||||
|
||||
local p, y, r = v.pitch, v.yaw, v.roll
|
||||
if p == 0 then p = nil end
|
||||
if y == 0 then y = nil end
|
||||
if r == 0 then r = nil end
|
||||
tbl[ k ] = { __type = "Angle", p = p, y = y, r = r }
|
||||
|
||||
elseif ( IsColor( v ) ) then
|
||||
|
||||
local r, g, b, a = v.r, v.g, v.b, v.a
|
||||
if r == 255 then r = nil end
|
||||
if g == 255 then g = nil end
|
||||
if b == 255 then b = nil end
|
||||
if a == 255 then a = nil end
|
||||
tbl[ k ] = { __type = "Color", r = r, g = g, b = b, a = a }
|
||||
|
||||
elseif ( isbool( v ) ) then
|
||||
|
||||
tbl[ k ] = { __type = "Bool", tostring( v ) }
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = tostring( v )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tbl
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.DeSanitise( table )
|
||||
Desc: Converts a Sanitised table back
|
||||
-----------------------------------------------------------]]
|
||||
function table.DeSanitise( t, done )
|
||||
|
||||
done = done or {}
|
||||
local tbl = {}
|
||||
|
||||
for k, v in pairs ( t ) do
|
||||
|
||||
if ( istable( v ) and !IsColor( v ) and !done[ v ] ) then
|
||||
|
||||
done[ v ] = true
|
||||
|
||||
if ( v.__type ) then
|
||||
|
||||
if ( v.__type == "Vector" ) then
|
||||
|
||||
tbl[ k ] = Vector( v.x or 0, v.y, v.z )
|
||||
|
||||
elseif ( v.__type == "Angle" ) then
|
||||
|
||||
tbl[ k ] = Angle( v.p or 0, v.y, v.r )
|
||||
|
||||
elseif ( v.__type == "Color" ) then
|
||||
|
||||
tbl[ k ] = Color( v.r or 255, v.g or 255, v.b or 255, v.a or 255 )
|
||||
|
||||
elseif ( v.__type == "Bool" ) then
|
||||
|
||||
tbl[ k ] = ( v[ 1 ] == "true" )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = table.DeSanitise( v, done )
|
||||
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
tbl[ k ] = v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return tbl
|
||||
|
||||
end
|
||||
|
||||
function table.ForceInsert( t, v )
|
||||
|
||||
if ( t == nil ) then t = {} end
|
||||
|
||||
table.insert( t, v )
|
||||
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.SortByMember( table )
|
||||
Desc: Sorts table by named member
|
||||
-----------------------------------------------------------]]
|
||||
function table.SortByMember( tab, memberName, bAsc )
|
||||
|
||||
local TableMemberSort = function( a, b, MemberName, bReverse )
|
||||
|
||||
--
|
||||
-- All this error checking kind of sucks, but really is needed
|
||||
--
|
||||
if ( !istable( a ) ) then return !bReverse end
|
||||
if ( !istable( b ) ) then return bReverse end
|
||||
if ( !a[ MemberName ] ) then return !bReverse end
|
||||
if ( !b[ MemberName ] ) then return bReverse end
|
||||
|
||||
if ( isstring( a[ MemberName ] ) ) then
|
||||
|
||||
if ( bReverse ) then
|
||||
return a[ MemberName ]:lower() < b[ MemberName ]:lower()
|
||||
else
|
||||
return a[ MemberName ]:lower() > b[ MemberName ]:lower()
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( bReverse ) then
|
||||
return a[ MemberName ] < b[ MemberName ]
|
||||
else
|
||||
return a[ MemberName ] > b[ MemberName ]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
table.sort( tab, function( a, b ) return TableMemberSort( a, b, memberName, bAsc or false ) end )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.LowerKeyNames( table )
|
||||
Desc: Lowercase the keynames of all tables
|
||||
-----------------------------------------------------------]]
|
||||
function table.LowerKeyNames( tab )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
|
||||
-- Recurse
|
||||
if ( istable( v ) ) then
|
||||
v = table.LowerKeyNames( v )
|
||||
end
|
||||
|
||||
OutTable[ k ] = v
|
||||
|
||||
if ( isstring( k ) ) then
|
||||
|
||||
OutTable[ k ] = nil
|
||||
OutTable[ string.lower( k ) ] = v
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.CollapseKeyValue( table )
|
||||
Desc: Collapses a table with keyvalue structure
|
||||
-----------------------------------------------------------]]
|
||||
function table.CollapseKeyValue( Table )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( Table ) do
|
||||
|
||||
local Val = v.Value
|
||||
|
||||
if ( istable( Val ) ) then
|
||||
Val = table.CollapseKeyValue( Val )
|
||||
end
|
||||
|
||||
OutTable[ v.Key ] = Val
|
||||
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: table.ClearKeys( table, bSaveKey )
|
||||
Desc: Clears the keys, converting to a numbered format
|
||||
-----------------------------------------------------------]]
|
||||
function table.ClearKeys( Table, bSaveKey )
|
||||
|
||||
local OutTable = {}
|
||||
|
||||
for k, v in pairs( Table ) do
|
||||
if ( bSaveKey ) then
|
||||
v.__key = k
|
||||
end
|
||||
table.insert( OutTable, v )
|
||||
end
|
||||
|
||||
return OutTable
|
||||
|
||||
end
|
||||
|
||||
local function keyValuePairs( state )
|
||||
|
||||
state.Index = state.Index + 1
|
||||
|
||||
local keyValue = state.KeyValues[ state.Index ]
|
||||
if ( !keyValue ) then return end
|
||||
|
||||
return keyValue.key, keyValue.val
|
||||
|
||||
end
|
||||
|
||||
local function toKeyValues( tbl )
|
||||
|
||||
local result = {}
|
||||
|
||||
for k, v in pairs( tbl ) do
|
||||
table.insert( result, { key = k, val = v } )
|
||||
end
|
||||
|
||||
return result
|
||||
|
||||
end
|
||||
|
||||
local function getKeys( tbl )
|
||||
|
||||
local keys = {}
|
||||
|
||||
for k in pairs( tbl ) do
|
||||
table.insert( keys, k )
|
||||
end
|
||||
|
||||
return keys
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by TABLE KEY
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairs( pTable, Desc )
|
||||
|
||||
local keys = getKeys( pTable )
|
||||
|
||||
if ( Desc ) then
|
||||
table.sort( keys, function( a, b )
|
||||
return a > b
|
||||
end )
|
||||
else
|
||||
table.sort( keys, function( a, b )
|
||||
return a < b
|
||||
end )
|
||||
end
|
||||
|
||||
local i, key
|
||||
return function()
|
||||
i, key = next( keys, i )
|
||||
return key, pTable[key]
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by VALUE
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairsByValue( pTable, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
if ( Desc ) then
|
||||
table.sort( sortedTbl, function( a, b ) return a.val > b.val end )
|
||||
else
|
||||
table.sort( sortedTbl, function( a, b ) return a.val < b.val end )
|
||||
end
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
Sorted by Member Value (All table entries must be a table!)
|
||||
-----------------------------------------------------------]]
|
||||
function SortedPairsByMemberValue( pTable, pValueName, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
for k, v in pairs( sortedTbl ) do
|
||||
v.member = v.val[ pValueName ]
|
||||
end
|
||||
|
||||
table.SortByMember( sortedTbl, "member", !Desc )
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
A Pairs function
|
||||
-----------------------------------------------------------]]
|
||||
function RandomPairs( pTable, Desc )
|
||||
|
||||
local sortedTbl = toKeyValues( pTable )
|
||||
|
||||
for k, v in pairs( sortedTbl ) do
|
||||
v.rand = math.random( 1, 1000000 )
|
||||
end
|
||||
|
||||
-- descending/ascending for a random order, really?
|
||||
if ( Desc ) then
|
||||
table.sort( sortedTbl, function( a, b ) return a.rand > b.rand end )
|
||||
else
|
||||
table.sort( sortedTbl, function( a, b ) return a.rand < b.rand end )
|
||||
end
|
||||
|
||||
return keyValuePairs, { Index = 0, KeyValues = sortedTbl }
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
GetFirstKey
|
||||
-----------------------------------------------------------]]
|
||||
function table.GetFirstKey( t )
|
||||
local k, _ = next( t )
|
||||
return k
|
||||
end
|
||||
|
||||
function table.GetFirstValue( t )
|
||||
local _, v = next( t )
|
||||
return v
|
||||
end
|
||||
|
||||
function table.GetLastKey( t )
|
||||
local k, _ = next( t, table.Count( t ) - 1 )
|
||||
return k
|
||||
end
|
||||
|
||||
function table.GetLastValue( t )
|
||||
local _, v = next( t, table.Count( t ) - 1 )
|
||||
return v
|
||||
end
|
||||
|
||||
function table.FindNext( tab, val )
|
||||
local bfound = false
|
||||
for k, v in pairs( tab ) do
|
||||
if ( bfound ) then return v end
|
||||
if ( val == v ) then bfound = true end
|
||||
end
|
||||
|
||||
return table.GetFirstValue( tab )
|
||||
end
|
||||
|
||||
function table.FindPrev( tab, val )
|
||||
|
||||
local last = table.GetLastValue( tab )
|
||||
for k, v in pairs( tab ) do
|
||||
if ( val == v ) then return last end
|
||||
last = v
|
||||
end
|
||||
|
||||
return last
|
||||
|
||||
end
|
||||
|
||||
function table.GetWinningKey( tab )
|
||||
|
||||
local highest = -math.huge
|
||||
local winner = nil
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
if ( v > highest ) then
|
||||
winner = k
|
||||
highest = v
|
||||
end
|
||||
end
|
||||
|
||||
return winner
|
||||
|
||||
end
|
||||
|
||||
function table.KeyFromValue( tbl, val )
|
||||
for key, value in pairs( tbl ) do
|
||||
if ( value == val ) then return key end
|
||||
end
|
||||
end
|
||||
|
||||
function table.RemoveByValue( tbl, val )
|
||||
|
||||
local key = table.KeyFromValue( tbl, val )
|
||||
if ( !key ) then return false end
|
||||
|
||||
if ( isnumber( key ) ) then
|
||||
table.remove( tbl, key )
|
||||
else
|
||||
tbl[ key ] = nil
|
||||
end
|
||||
|
||||
return key
|
||||
|
||||
end
|
||||
|
||||
function table.KeysFromValue( tbl, val )
|
||||
local res = {}
|
||||
for key, value in pairs( tbl ) do
|
||||
if ( value == val ) then res[ #res + 1 ] = key end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function table.MemberValuesFromKey( tab, key )
|
||||
local res = {}
|
||||
for k, v in pairs( tab ) do
|
||||
if ( istable( v ) and v[ key ] != nil ) then res[ #res + 1 ] = v[ key ] end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function table.Reverse( tbl )
|
||||
|
||||
local len = #tbl
|
||||
local ret = {}
|
||||
|
||||
for i = len, 1, -1 do
|
||||
ret[ len - i + 1 ] = tbl[ i ]
|
||||
end
|
||||
|
||||
return ret
|
||||
|
||||
end
|
||||
|
||||
function table.ForEach( tab, funcname )
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
funcname( k, v )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function table.GetKeys( tab )
|
||||
|
||||
local keys = {}
|
||||
local id = 1
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
keys[ id ] = k
|
||||
id = id + 1
|
||||
end
|
||||
|
||||
return keys
|
||||
|
||||
end
|
||||
|
||||
function table.Flip( tab )
|
||||
|
||||
local res = {}
|
||||
|
||||
for k, v in pairs( tab ) do
|
||||
res[ v ] = k
|
||||
end
|
||||
|
||||
return res
|
||||
|
||||
end
|
||||
|
||||
-- Polyfill for table.move on 32-bit
|
||||
-- Don't forget to remove this when it's no longer necessary
|
||||
if ( !table.move ) then
|
||||
function table.move( sourceTbl, from, to, dest, destTbl )
|
||||
|
||||
if ( !istable( sourceTbl ) ) then error( "bad argument #1 to 'move' (table expected, got " .. type( sourceTbl ) .. ")" ) end
|
||||
if ( !isnumber( from ) ) then error( "bad argument #2 to 'move' (number expected, got " .. type( from ) .. ")" ) end
|
||||
if ( !isnumber( to ) ) then error( "bad argument #3 to 'move' (number expected, got " .. type( to ) .. ")" ) end
|
||||
if ( !isnumber( dest ) ) then error( "bad argument #4 to 'move' (number expected, got " .. type( dest ) .. ")" ) end
|
||||
if ( destTbl != nil ) then
|
||||
if ( !istable( destTbl ) ) then error( "bad argument #5 to 'move' (table expected, got " .. type( destTbl ) .. ")" ) end
|
||||
else
|
||||
destTbl = sourceTbl
|
||||
end
|
||||
|
||||
local buffer = { unpack( sourceTbl, from, to ) }
|
||||
|
||||
dest = math.floor( dest - 1 )
|
||||
for i, v in ipairs( buffer ) do
|
||||
destTbl[ dest + i ] = v
|
||||
end
|
||||
|
||||
return destTbl
|
||||
|
||||
end
|
||||
end
|
||||
420
lua/includes/extensions/util.lua
Normal file
420
lua/includes/extensions/util.lua
Normal file
@@ -0,0 +1,420 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !util ) then return end
|
||||
|
||||
if ( CLIENT ) then
|
||||
include( "util/worldpicker.lua" )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsValidPhysicsObject
|
||||
Params: <ent> <num>
|
||||
Desc: Returns true if physics object is valid, false if not
|
||||
-----------------------------------------------------------]]
|
||||
function util.IsValidPhysicsObject( ent, num )
|
||||
|
||||
-- Make sure the entity is valid
|
||||
if ( !ent or ( !ent:IsValid() and !ent:IsWorld() ) ) then return false end
|
||||
|
||||
-- This is to stop attaching to walking NPCs.
|
||||
-- Although this is possible and `works', it can severly reduce the
|
||||
-- performance of the server.. Plus they don't pay attention to constraints
|
||||
-- anyway - so we're not really losing anything.
|
||||
|
||||
local MoveType = ent:GetMoveType()
|
||||
if ( !ent:IsWorld() and MoveType != MOVETYPE_VPHYSICS and !( ent:GetModel() and ent:GetModel():StartsWith( "*" ) ) ) then return false end
|
||||
|
||||
local Phys = ent:GetPhysicsObjectNum( num )
|
||||
return IsValid( Phys )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPlayerTrace( ply, dir )
|
||||
Desc: Returns a generic trace table for the player
|
||||
(dir is optional, defaults to the player's aim)
|
||||
-----------------------------------------------------------]]
|
||||
function util.GetPlayerTrace( ply, dir )
|
||||
|
||||
dir = dir or ply:GetAimVector()
|
||||
|
||||
local trace = {}
|
||||
|
||||
trace.start = ply:EyePos()
|
||||
trace.endpos = trace.start + ( dir * ( 4096 * 8 ) )
|
||||
trace.filter = ply
|
||||
|
||||
return trace
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: QuickTrace( origin, offset, filter )
|
||||
Desc: Quick trace
|
||||
-----------------------------------------------------------]]
|
||||
function util.QuickTrace( origin, dir, filter )
|
||||
|
||||
local trace = {}
|
||||
|
||||
trace.start = origin
|
||||
trace.endpos = origin + dir
|
||||
trace.filter = filter
|
||||
|
||||
return util.TraceLine( trace )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: tobool( in )
|
||||
Desc: Turn variable into bool
|
||||
-----------------------------------------------------------]]
|
||||
util.tobool = tobool
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: LocalToWorld( ent, lpos, bone )
|
||||
Desc: Convert the local position on an entity to world pos
|
||||
-----------------------------------------------------------]]
|
||||
function util.LocalToWorld( ent, lpos, bone )
|
||||
|
||||
bone = bone or 0
|
||||
if ( ent:EntIndex() == 0 ) then
|
||||
return lpos
|
||||
else
|
||||
if ( IsValid( ent:GetPhysicsObjectNum( bone ) ) ) then
|
||||
return ent:GetPhysicsObjectNum( bone ):LocalToWorld( lpos )
|
||||
else
|
||||
return ent:LocalToWorld( lpos )
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Returns year, month, day and hour, minute, second in a formatted string.
|
||||
-----------------------------------------------------------]]
|
||||
function util.DateStamp()
|
||||
|
||||
local t = os.date( '*t' )
|
||||
return t.year .. "-" .. t.month .. "-" .. t.day .. " " .. Format( "%02i-%02i-%02i", t.hour, t.min, t.sec )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Convert a string to a certain type
|
||||
-----------------------------------------------------------]]
|
||||
function util.StringToType( str, typename )
|
||||
|
||||
typename = typename:lower()
|
||||
|
||||
if ( typename == "vector" ) then return Vector( str ) end
|
||||
if ( typename == "angle" ) then return Angle( str ) end
|
||||
if ( typename == "float" || typename == "number" ) then return tonumber( str ) end
|
||||
if ( typename == "int" ) then local v = tonumber( str ) return v and math.Round( v ) or nil end
|
||||
if ( typename == "bool" || typename == "boolean" ) then return tobool( str ) end
|
||||
if ( typename == "string" ) then return tostring( str ) end
|
||||
if ( typename == "entity" ) then return Entity( str ) end
|
||||
|
||||
MsgN( "util.StringToType: unknown type \"", typename, "\"!" )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Convert a type to a (nice, but still parsable) string
|
||||
--
|
||||
function util.TypeToString( v )
|
||||
|
||||
local iD = TypeID( v )
|
||||
|
||||
if ( iD == TYPE_VECTOR or iD == TYPE_ANGLE ) then
|
||||
return string.format( "%.2f %.2f %.2f", v:Unpack() )
|
||||
end
|
||||
|
||||
if ( iD == TYPE_NUMBER ) then
|
||||
return util.NiceFloat( v )
|
||||
end
|
||||
|
||||
return tostring( v )
|
||||
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Formats a float by stripping off extra 0's and .'s
|
||||
--
|
||||
-- 0.00 -> 0
|
||||
-- 0.10 -> 0.1
|
||||
-- 1.00 -> 1
|
||||
-- 1.49 -> 1.49
|
||||
-- 5.90 -> 5.9
|
||||
--
|
||||
function util.NiceFloat( f )
|
||||
|
||||
local str = string.format( "%f", f )
|
||||
|
||||
str = str:TrimRight( "0" )
|
||||
str = str:TrimRight( "." )
|
||||
|
||||
return str
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
--
|
||||
-- Timer
|
||||
--
|
||||
--
|
||||
local T =
|
||||
{
|
||||
--
|
||||
-- Resets the timer to nothing
|
||||
--
|
||||
Reset = function( self )
|
||||
|
||||
self.endtime = nil
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Starts the timer, call with end time
|
||||
--
|
||||
Start = function( self, time )
|
||||
|
||||
self.endtime = CurTime() + time
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Returns true if the timer has been started
|
||||
--
|
||||
Started = function( self )
|
||||
|
||||
return self.endtime != nil
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Returns true if the time has elapsed
|
||||
--
|
||||
Elapsed = function( self )
|
||||
|
||||
return self.endtime == nil or self.endtime <= CurTime()
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
T.__index = T
|
||||
|
||||
--
|
||||
-- Create a new timer object
|
||||
--
|
||||
function util.Timer( startdelay )
|
||||
|
||||
startdelay = startdelay or 0
|
||||
|
||||
local t = {}
|
||||
setmetatable( t, T )
|
||||
t.endtime = CurTime() + startdelay
|
||||
return t
|
||||
|
||||
end
|
||||
|
||||
|
||||
local function PopStack( self, num )
|
||||
|
||||
if ( num == nil ) then
|
||||
num = 1
|
||||
elseif ( num < 0 ) then
|
||||
error( string.format( "attempted to pop %d elements in stack, expected >= 0", num ), 3 )
|
||||
else
|
||||
num = math.floor( num )
|
||||
end
|
||||
|
||||
local len = self[ 0 ]
|
||||
|
||||
if ( num > len ) then
|
||||
error( string.format( "attempted to pop %u element%s in stack of length %u", num, num == 1 and "" or "s", len ), 3 )
|
||||
end
|
||||
|
||||
return num, len
|
||||
|
||||
end
|
||||
|
||||
local STACK =
|
||||
{
|
||||
Push = function( self, obj )
|
||||
local len = self[ 0 ] + 1
|
||||
self[ len ] = obj
|
||||
self[ 0 ] = len
|
||||
end,
|
||||
|
||||
Pop = function( self, num )
|
||||
local len
|
||||
num, len = PopStack( self, num )
|
||||
|
||||
if ( num == 0 ) then
|
||||
return nil
|
||||
end
|
||||
|
||||
local newlen = len - num
|
||||
self[ 0 ] = newlen
|
||||
|
||||
newlen = newlen + 1
|
||||
local ret = self[ newlen ]
|
||||
|
||||
-- Pop up to the last element
|
||||
for i = len, newlen, -1 do
|
||||
self[ i ] = nil
|
||||
end
|
||||
|
||||
return ret
|
||||
end,
|
||||
|
||||
PopMulti = function( self, num )
|
||||
local len
|
||||
num, len = PopStack( self, num )
|
||||
|
||||
if ( num == 0 ) then
|
||||
return {}
|
||||
end
|
||||
|
||||
local newlen = len - num
|
||||
self[ 0 ] = newlen
|
||||
|
||||
local ret = {}
|
||||
local retpos = 0
|
||||
|
||||
-- Pop each element and add it to the table
|
||||
-- Iterate in reverse since the stack is internally stored
|
||||
-- with 1 being the bottom element and len being the top
|
||||
-- But the return will have 1 as the top element
|
||||
for i = len, newlen + 1, -1 do
|
||||
retpos = retpos + 1
|
||||
ret[ retpos ] = self[ i ]
|
||||
|
||||
self[ i ] = nil
|
||||
end
|
||||
|
||||
return ret
|
||||
end,
|
||||
|
||||
Top = function( self )
|
||||
local len = self[ 0 ]
|
||||
|
||||
if ( len == 0 ) then
|
||||
return nil
|
||||
end
|
||||
|
||||
return self[ len ]
|
||||
end,
|
||||
|
||||
Size = function( self )
|
||||
return self[ 0 ]
|
||||
end
|
||||
}
|
||||
|
||||
STACK.__index = STACK
|
||||
|
||||
function util.Stack()
|
||||
return setmetatable( { [ 0 ] = 0 }, STACK )
|
||||
end
|
||||
|
||||
-- Helper for the following functions. This is not ideal but we cannot change this because it will break existing addons.
|
||||
local function GetUniqueID( sid )
|
||||
return util.CRC( "gm_" .. sid .. "_gm" )
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: GetPData( steamid, name, default )
|
||||
Desc: Gets the persistant data from a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.GetPData( steamid, name, default )
|
||||
|
||||
-- First try looking up using the new key
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
local val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( key ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then
|
||||
|
||||
-- Not found? Look using the old key
|
||||
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
||||
val = sql.QueryValue( "SELECT value FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) .. " LIMIT 1" )
|
||||
if ( val == nil ) then return default end
|
||||
|
||||
end
|
||||
|
||||
return val
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: SetPData( steamid, name, value )
|
||||
Desc: Sets the persistant data of a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.SetPData( steamid, name, value )
|
||||
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
sql.Query( "REPLACE INTO playerpdata ( infoid, value ) VALUES ( " .. SQLStr( key ) .. ", " .. SQLStr( value ) .. " )" )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: RemovePData( steamid, name )
|
||||
Desc: Removes the persistant data from a player by steamid
|
||||
-----------------------------------------------------------]]
|
||||
function util.RemovePData( steamid, name )
|
||||
|
||||
-- First the old key
|
||||
local oldkey = Format( "%s[%s]", GetUniqueID( steamid ), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( oldkey ) )
|
||||
|
||||
-- Then the new key. util.SteamIDTo64 is not ideal, but nothing we can do about it now
|
||||
local key = Format( "%s[%s]", util.SteamIDTo64( steamid ), name )
|
||||
sql.Query( "DELETE FROM playerpdata WHERE infoid = " .. SQLStr( key ) )
|
||||
|
||||
end
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Name: IsBinaryModuleInstalled( name )
|
||||
Desc: Returns whether a binary module with the given name is present on disk
|
||||
-----------------------------------------------------------]]
|
||||
local suffix = ( { "osx64", "osx", "linux64", "linux", "win64", "win32" } )[
|
||||
( system.IsWindows() and 4 or 0 )
|
||||
+ ( system.IsLinux() and 2 or 0 )
|
||||
+ ( jit.arch == "x86" and 1 or 0 )
|
||||
+ 1
|
||||
]
|
||||
local fmt = "lua/bin/gm" .. ( ( CLIENT and !MENU_DLL ) and "cl" or "sv" ) .. "_%s_%s.dll"
|
||||
function util.IsBinaryModuleInstalled( name )
|
||||
if ( !isstring( name ) ) then
|
||||
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string expected, got " .. type( name ) .. ")" )
|
||||
elseif ( #name == 0 ) then
|
||||
error( "bad argument #1 to 'IsBinaryModuleInstalled' (string cannot be empty)" )
|
||||
end
|
||||
|
||||
if ( file.Exists( string.format( fmt, name, suffix ), "MOD" ) ) then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Edge case - on Linux 32-bit x86-64 branch, linux32 is also supported as a suffix
|
||||
if ( jit.versionnum != 20004 and jit.arch == "x86" and system.IsLinux() ) then
|
||||
return file.Exists( string.format( fmt, name, "linux32" ), "MOD" )
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
66
lua/includes/extensions/util/worldpicker.lua
Normal file
66
lua/includes/extensions/util/worldpicker.lua
Normal file
@@ -0,0 +1,66 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
--
|
||||
--
|
||||
-- worldpicker is for picking an entity from the game while you have the GUI open.
|
||||
-- Calling util.worldpicker.Start( func ) will hide all GUI and let you pick an entity from
|
||||
-- the game world. Once selected it will call your passed function with the trace.
|
||||
--
|
||||
-- It's used in the icon editor
|
||||
--
|
||||
--
|
||||
|
||||
local bDoing = false
|
||||
local fnAction = nil
|
||||
|
||||
util.worldpicker = {
|
||||
--
|
||||
-- Start world picking
|
||||
--
|
||||
Start = function( func )
|
||||
|
||||
bDoing = true
|
||||
fnAction = func
|
||||
gui.EnableScreenClicker( true )
|
||||
|
||||
end,
|
||||
|
||||
--
|
||||
-- Finish world picking - you shouldn't have to call this (called from hook below)
|
||||
--
|
||||
Finish = function( tr )
|
||||
|
||||
bDoing = false
|
||||
fnAction( tr )
|
||||
gui.EnableScreenClicker( false )
|
||||
|
||||
end,
|
||||
|
||||
Active = function() return bDoing end
|
||||
}
|
||||
|
||||
hook.Add( "VGUIMousePressAllowed", "WorldPickerMouseDisable", function( code )
|
||||
|
||||
if ( !bDoing ) then return false end
|
||||
|
||||
local dir = gui.ScreenToVector( input.GetCursorPos() )
|
||||
local tr = util.TraceLine( {
|
||||
start = LocalPlayer():GetShootPos(),
|
||||
endpos = LocalPlayer():GetShootPos() + dir * 32768,
|
||||
filter = LocalPlayer()
|
||||
} )
|
||||
|
||||
util.worldpicker.Finish( tr )
|
||||
|
||||
-- Don't register this click
|
||||
return true
|
||||
|
||||
end )
|
||||
22
lua/includes/extensions/vector.lua
Normal file
22
lua/includes/extensions/vector.lua
Normal file
@@ -0,0 +1,22 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
local meta = FindMetaTable( "Vector" )
|
||||
|
||||
-- Nothing in here, still leaving this file here just in case
|
||||
|
||||
--[[---------------------------------------------------------
|
||||
Converts Vector To Color - alpha precision lost, must reset
|
||||
-----------------------------------------------------------]]
|
||||
function meta:ToColor( )
|
||||
|
||||
return Color( self.x * 255, self.y * 255, self.z * 255 )
|
||||
|
||||
end
|
||||
55
lua/includes/extensions/weapon.lua
Normal file
55
lua/includes/extensions/weapon.lua
Normal file
@@ -0,0 +1,55 @@
|
||||
--[[
|
||||
| This file was obtained through the combined efforts
|
||||
| of Madbluntz & Plymouth Antiquarian Society.
|
||||
|
|
||||
| Credits: lifestorm, Gregory Wayne Rossel JR.,
|
||||
| Maloy, DrPepper10 @ RIP, Atle!
|
||||
|
|
||||
| Visit for more: https://plymouth.thetwilightzone.ru/
|
||||
--]]
|
||||
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local meta = FindMetaTable( "Weapon" )
|
||||
local entity = FindMetaTable( "Entity" )
|
||||
|
||||
-- Return if there's nothing to add on to
|
||||
if ( !meta ) then return end
|
||||
|
||||
--
|
||||
-- Entity index accessor. This used to be done in engine, but it's done in Lua now because it's faster
|
||||
--
|
||||
function meta:__index( key )
|
||||
|
||||
--
|
||||
-- Search the metatable. We can do this without dipping into C, so we do it first.
|
||||
--
|
||||
local val = meta[key]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity metatable
|
||||
--
|
||||
local val = entity[key]
|
||||
if ( val != nil ) then return val end
|
||||
|
||||
--
|
||||
-- Search the entity table
|
||||
--
|
||||
local tab = entity.GetTable( self )
|
||||
if ( tab != nil ) then
|
||||
local val = tab[ key ]
|
||||
if ( val != nil ) then return val end
|
||||
end
|
||||
|
||||
--
|
||||
-- Legacy: sometimes use self.Owner to get the owner.. so lets carry on supporting that stupidness
|
||||
-- This needs to be retired, just like self.Entity was.
|
||||
--
|
||||
if ( key == "Owner" ) then return entity.GetOwner( self ) end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user