Initial commit

This commit is contained in:
2026-03-15 14:54:49 +03:00
commit 64f8029c06
4027 changed files with 254888 additions and 0 deletions

View File

@@ -0,0 +1,325 @@
--[[---------------------------------------------------------
Get the real frame time, instead of the
host_timescale linked frametime. This is for things
like GUI effects. NOT FOR REAL IN GAME STUFF(!!!)
-----------------------------------------------------------]]
local FrameTime = 0
local LastQuery = 0
function RealFrameTime() return FrameTime end
local function RealFrameTimeThink()
FrameTime = math.Clamp( SysTime() - LastQuery, 0, 0.1 )
LastQuery = SysTime()
end
hook.Add( "Think", "RealFrameTime", RealFrameTimeThink ) -- Think is called after every frame on the client.
-- Make Portal 2 materials work out of the box
matproxy.Add( {
name = "FizzlerVortex",
init = function( self, mat, values )
end,
bind = function( self, mat, ent )
mat:SetFloat( "$flow_color_intensity", 1 )
-- Less than ideal, but serves as an example
--[[local entities = {}
for k, v in pairs( ents.FindInSphere( ent:GetPos(), ent:BoundingRadius() ) ) do
if ( v == ent || v:GetMoveType() != MOVETYPE_VPHYSICS ) then continue end
table.insert( entities, v )
end
table.sort( entities, function( a, b ) return a:GetPos():Distance( ent:GetPos() ) < b:GetPos():Distance( ent:GetPos() ) end )
if ( entities[ 1 ] ) then
mat:SetFloat( "$FLOW_VORTEX1", 1 )
mat:SetVector( "$FLOW_VORTEX_POS1", entities[ 1 ]:GetPos() )
else
mat:SetFloat( "$FLOW_VORTEX1", 0 )
end
if ( entities[ 2 ] ) then
mat:SetFloat( "$FLOW_VORTEX2", 1 )
mat:SetVector( "$FLOW_VORTEX_POS2", entities[ 2 ]:GetPos() )
else
mat:SetFloat( "$FLOW_VORTEX2", 0 )
end]]
end
} )
local function RenderSpawnIcon_Prop( model, pos, middle, size )
if ( size < 900 ) then
size = size * ( 1 - ( size / 900 ) )
else
size = size * ( 1 - ( size / 4096 ) )
end
size = math.Clamp( size, 5, 1000 )
local ViewAngle = Angle( 25, 220, 0 )
local ViewPos = pos + ViewAngle:Forward() * size * -15
local view = {}
view.fov = 4 + size * 0.04
view.origin = ViewPos + middle
view.znear = 1
view.zfar = ViewPos:Distance( pos ) + size * 2
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_Ragdoll( model, pos, middle, size )
local at = model:GetAttachment( model:LookupAttachment( "eyes" ) )
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
local ViewAngle = at.Ang + Angle( -10, 160, 0 )
local ViewPos = at.Pos + ViewAngle:Forward() * -60 + ViewAngle:Up() * -2
local view = {}
view.fov = 10
view.origin = ViewPos
view.znear = 0.1
view.zfar = 100
view.angles = ViewAngle
return view
end
--
-- For some TF2 ragdolls which do not have "eye" attachments
--
local function RenderSpawnIcon_Ragdoll_Head( model, pos, middle, size )
local at = model:GetAttachment( model:LookupAttachment( "head" ) )
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
local ViewAngle = at.Ang + Angle( -10, 160, 0 )
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -7 + ViewAngle:Right() * 1.5
local view = {}
view.fov = 10
view.origin = ViewPos
view.znear = 0.1
view.zfar = 100
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_Ragdoll_Facemask( model, pos, middle, size )
local at = model:GetAttachment( model:LookupAttachment( "facemask" ) )
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
local ViewAngle = at.Ang
ViewAngle:RotateAroundAxis( ViewAngle:Right(), -10 )
ViewAngle:RotateAroundAxis( ViewAngle:Up(), 160 )
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -2 + ViewAngle:Right() * -1
local view = {}
view.fov = 10
view.origin = ViewPos
view.znear = 0.1
view.zfar = 100
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_Ragdoll_Forward( model, pos, middle, size )
local at = model:GetAttachment( model:LookupAttachment( "forward" ) )
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
local ViewAngle = at.Ang + Angle( 10, -20, 0 )
local ViewPos = at.Pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * -1 + ViewAngle:Right() * 2.5
local view = {}
view.fov = 10
view.origin = ViewPos
view.znear = 0.1
view.zfar = 100
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_DOD( model, pos, middle, size )
local ViewAngle = Angle( 0, 160, 0 )
local ViewPos = pos + ViewAngle:Forward() * -67 + ViewAngle:Up() * 30 + ViewAngle:Right() * 2.5
local view = {}
view.fov = 10
view.origin = ViewPos + middle
view.znear = 1
view.zfar = ViewPos:Distance( pos ) + size * 2
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_CS( model, pos, middle, size )
local ViewAngle = Angle( 0, 160, 0 )
local ViewPos = pos + ViewAngle:Forward() * -70 + ViewAngle:Up() * 32.4 + ViewAngle:Right() * 1.5
local view = {}
view.fov = 10
view.origin = ViewPos + middle
view.znear = 1
view.zfar = ViewPos:Distance( pos ) + size * 2
view.angles = ViewAngle
return view
end
local function RenderSpawnIcon_Special( model, pos, middle, size, x, y, z )
local ViewAngle = Angle( 15, 140, 0 )
local ViewPos = pos + ViewAngle:Forward() * x + ViewAngle:Up() * y + ViewAngle:Right() * z
local view = {}
view.fov = 20
view.origin = ViewPos + middle
view.znear = 1
view.zfar = ViewPos:Distance( pos ) + size * 2
view.angles = ViewAngle
return view
end
SpawniconGenFunctions = {}
function PositionSpawnIcon( model, pos, noAngles )
local mn, mx = model:GetRenderBounds()
local middle = ( mn + mx ) * 0.5
local size = 0
size = math.max( size, math.abs( mn.x ) + math.abs( mx.x ) )
size = math.max( size, math.abs( mn.y ) + math.abs( mx.y ) )
size = math.max( size, math.abs( mn.z ) + math.abs( mx.z ) )
model:SetPos( pos )
if ( !noAngles ) then model:SetAngles( angle_zero ) end
local ModelName = model:GetModel()
ModelName = string.Replace( ModelName, "--", "/" )
ModelName = string.Replace( ModelName, "\\", "/" )
ModelName = string.Replace( ModelName, "//", "/" )
ModelName = string.Replace( ModelName, "\\\\", "/" )
local fnc = SpawniconGenFunctions[ ModelName ]
if ( fnc ) then return fnc( model, pos, middle, size ) end
if ( model:LookupAttachment( "eyes" ) > 0 ) then
return RenderSpawnIcon_Ragdoll( model, pos, middle, size )
end
if ( model:LookupAttachment( "head" ) > 0 ) then
return RenderSpawnIcon_Ragdoll_Head( model, pos, middle, size )
end
-- CS:GO Player Models
if ( model:LookupAttachment( "facemask" ) > 0 ) then
return RenderSpawnIcon_Ragdoll_Facemask( model, pos, middle, size )
end
-- CS:GO Hostages
if ( model:LookupAttachment( "forward" ) > 0 ) then
return RenderSpawnIcon_Ragdoll_Forward( model, pos, middle, size )
end
return RenderSpawnIcon_Prop( model, pos, middle, size )
end
-- DOD Player Models
SpawniconGenFunctions[ "models/player/american_assault.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/american_mg.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/american_rifleman.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/american_rocket.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/american_sniper.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/american_support.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_assault.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_mg.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_rifleman.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_rocket.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_sniper.mdl" ] = RenderSpawnIcon_DOD
SpawniconGenFunctions[ "models/player/german_support.mdl" ] = RenderSpawnIcon_DOD
-- CS Player Models
SpawniconGenFunctions[ "models/player/ct_gign.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/ct_sas.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/ct_urban.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/ct_gsg9.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/t_leet.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/t_phoenix.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/t_arctic.mdl" ] = RenderSpawnIcon_CS
SpawniconGenFunctions[ "models/player/t_guerilla.mdl" ] = RenderSpawnIcon_CS
-- L4D Models
SpawniconGenFunctions[ "models/infected/witch.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -40, 25, 0 ) end
SpawniconGenFunctions[ "models/infected/smoker.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -60, 33, 10 ) end
SpawniconGenFunctions[ "models/infected/hunter.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 26, 2 ) end
SpawniconGenFunctions[ "models/infected/hulk.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -70, 30, 11 ) end
SpawniconGenFunctions[ "models/infected/boomer.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 27, 0 ) end
SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] = function ( model, pos, middle, size )
local at = model:GetAttachment( model:LookupAttachment( "forward" ) )
if ( !at ) then at = { Pos = model:GetPos(), Ang = model:GetAngles() } end
local ViewAngle = at.Ang + Angle( 180, 180, 0 ) + Angle( 10, -85, -85 )
local ViewPos = at.Pos + ViewAngle:Forward() * -76 + ViewAngle:Up() * -1.5 + ViewAngle:Right() * 0
return { fov = 10, origin = ViewPos, znear = 0.1, zfar = 200, angles = ViewAngle }
end
SpawniconGenFunctions[ "models/infected/common_female_nurse01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_female_rural01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_test.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_morph_test.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] -- Bad start animation
SpawniconGenFunctions[ "models/infected/common_male_fallen_survivor.mdl" ] = SpawniconGenFunctions[ "models/infected/common_female01.mdl" ] -- Bad start animation
SpawniconGenFunctions[ "models/infected/common_male_baggagehandler_01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_male_pilot.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_male_rural01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_male_suit.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_military_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_police_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_patient_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_surgeon_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ] -- Bad start animation
SpawniconGenFunctions[ "models/infected/common_tsaagent_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
SpawniconGenFunctions[ "models/infected/common_worker_male01.mdl" ] = SpawniconGenFunctions[ "models/infected/common_male01.mdl" ]
-- ZPS Zombies
SpawniconGenFunctions[ "models/zombies/zombie0/zombie0.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
SpawniconGenFunctions[ "models/zombies/zombie1/zombie1.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
SpawniconGenFunctions[ "models/zombies/zombie2/zombie2.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
SpawniconGenFunctions[ "models/zombies/zombie3/zombie3.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
SpawniconGenFunctions[ "models/zombies/zombie4/zombie4.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
SpawniconGenFunctions[ "models/zombies/zombie5/zombie5.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -100, 17, 10 ) end
-- L4D2
SpawniconGenFunctions[ "models/infected/boomette.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 28, 0 ) end
SpawniconGenFunctions[ "models/infected/charger.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -70, 14, 20 ) end
SpawniconGenFunctions[ "models/infected/jockey.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -50, 0, 7 ) end
SpawniconGenFunctions[ "models/infected/spitter.mdl" ] = function( a, b, c, d ) return RenderSpawnIcon_Special( a, b, c, d, -1, 0, -70 ) end -- as good as deleted
SpawniconGenFunctions[ "models/infected/hulk_dlc3.mdl" ] = SpawniconGenFunctions[ "models/infected/hulk.mdl" ]

427
lua/includes/util/color.lua Normal file
View File

@@ -0,0 +1,427 @@
local COLOR = {}
COLOR.__index = COLOR
--[[---------------------------------------------------------
Register our metatable to make it accessible using FindMetaTable
-----------------------------------------------------------]]
RegisterMetaTable( "Color", COLOR )
--[[---------------------------------------------------------
To easily create a color table
-----------------------------------------------------------]]
function Color( r, g, b, a )
return setmetatable( {
r = math.min( tonumber( r ), 255 ),
g = math.min( tonumber( g ), 255 ),
b = math.min( tonumber( b ), 255 ),
a = math.min( tonumber( a or 255 ), 255 )
}, COLOR )
end
--[[---------------------------------------------------------
Change the alpha of a color
-----------------------------------------------------------]]
function ColorAlpha( c, a )
return Color( c.r, c.g, c.b, a )
end
--[[---------------------------------------------------------
Checks if the given variable is a color object
-----------------------------------------------------------]]
function IsColor( obj )
return getmetatable( obj ) == COLOR
end
--[[---------------------------------------------------------
Different color represntations
-----------------------------------------------------------]]
function HSVToColor( h, s, v )
h = h % 360
local c = v * s
local x = c * ( 1 - math.abs( ( h / 60 ) % 2 - 1 ) )
local m = v - c
local r, g, b
if ( h < 60 ) then
r, g, b = c, x, 0
elseif ( h < 120 ) then
r, g, b = x, c, 0
elseif ( h < 180 ) then
r, g, b = 0, c, x
elseif ( h < 240 ) then
r, g, b = 0, x, c
elseif ( h < 300 ) then
r, g, b = x, 0, c
else
r, g, b = c, 0, x
end
return Color(
math.Clamp( math.floor( ( r + m ) * 255 ), 0, 255 ),
math.Clamp( math.floor( ( g + m ) * 255 ), 0, 255 ),
math.Clamp( math.floor( ( b + m ) * 255 ), 0, 255 )
)
end
function HSLToColor( h, s, l )
h = h % 360
local c = ( 1 - math.abs( 2 * l - 1 ) ) * s
local x = c * ( 1 - math.abs( ( h / 60 ) % 2 - 1 ) )
local m = l - c / 2
local r, g, b
if ( h < 60 ) then
r, g, b = c, x, 0
elseif ( h < 120 ) then
r, g, b = x, c, 0
elseif ( h < 180 ) then
r, g, b = 0, c, x
elseif ( h < 240 ) then
r, g, b = 0, x, c
elseif ( h < 300 ) then
r, g, b = x, 0, c
else
r, g, b = c, 0, x
end
return Color(
math.Clamp( math.floor( ( r + m ) * 255 ), 0, 255 ),
math.Clamp( math.floor( ( g + m ) * 255 ), 0, 255 ),
math.Clamp( math.floor( ( b + m ) * 255 ), 0, 255 )
)
end
function HWBToColor( h, w, b )
local v = 1 - b
local s = 0
if ( v > 0 ) then
s = 1 - w / v
end
return HSVToColor( h, s, v )
end
local hex_to_dec = {}
for code = 48, 57 do hex_to_dec[ code ] = code - 48 end -- '0''9'
for code = 65, 70 do hex_to_dec[ code ] = code - 55 end -- 'A''F'
for code = 97, 102 do hex_to_dec[ code ] = code - 87 end -- 'a''f'
function HexToColor( hex )
local idx = string.byte( hex, 1 ) == 35 and 2 or 1 -- '#' check without allocation
local len = #hex - ( idx - 1 )
if ( len == 3 or len == 4 ) then
local r, g, b, a = string.byte( hex, idx, idx + len - 1 )
r = hex_to_dec[ r ]
g = hex_to_dec[ g ]
b = hex_to_dec[ b ]
a = a and hex_to_dec[ a ] or 15
if !( r and g and b and a ) then
return error( "invalid hex input: " .. hex )
end
return Color( r * 16 + r, g * 16 + g, b * 16 + b, a * 16 + a )
elseif ( len == 6 or len == 8 ) then
local r1, r2, g1, g2, b1, b2, a1, a2 = string.byte( hex, idx, idx + len - 1 )
r1, r2 = hex_to_dec[ r1 ], hex_to_dec[ r2 ]
g1, g2 = hex_to_dec[ g1 ], hex_to_dec[ g2 ]
b1, b2 = hex_to_dec[ b1 ], hex_to_dec[ b2 ]
a1, a2 = a1 and hex_to_dec[ a1 ] or 15, a2 and hex_to_dec[ a2 ] or 15
if !( r1 and r2 and g1 and g2 and b1 and b2 and a1 and a2 ) then
return error( "invalid hex input: " .. hex )
end
return Color( r1 * 16 + r2, g1 * 16 + g2, b1 * 16 + b2, a1 * 16 + a2 )
end
return error( "invalid hex input: " .. hex )
end
--[[---------------------------------------------------------
Returns color as a string
-----------------------------------------------------------]]
function COLOR:__tostring()
return string.format( "%d %d %d %d", self.r, self.g, self.b, self.a )
end
--[[---------------------------------------------------------
Compares two colors
-----------------------------------------------------------]]
function COLOR:__eq( c )
return self.r == c.r and self.g == c.g and self.b == c.b and self.a == c.a
end
--[[---------------------------------------------------------
Converts a color to HSL color space
-----------------------------------------------------------]]
function COLOR:ToHSL()
return ColorToHSL( self )
end
--[[---------------------------------------------------------
Converts a color to HSV color space
-----------------------------------------------------------]]
function COLOR:ToHSV()
return ColorToHSV( self )
end
--[[---------------------------------------------------------
Converts a color to HWB color space
-----------------------------------------------------------]]
function COLOR:ToHWB()
local h, s, v = self:ToHSV()
return h, ( 1 - s ) * v, 1 - v
end
--[[---------------------------------------------------------
Converts color to a hex string
-----------------------------------------------------------]]
function COLOR:ToHex( omitAlpha )
if ( omitAlpha or self.a == 255 ) then
return string.format( "#%02x%02x%02x", self.r, self.g, self.b )
end
return string.format( "#%02x%02x%02x%02x", self.r, self.g, self.b, self.a )
end
--[[---------------------------------------------------------
Converts color to vector - loss of precision / alpha lost
-----------------------------------------------------------]]
function COLOR:ToVector()
return Vector( self.r / 255, self.g / 255, self.b / 255 )
end
--[[---------------------------------------------------------
Unpacks the color into four variables
-----------------------------------------------------------]]
function COLOR:Unpack()
return self.r, self.g, self.b, self.a
end
function COLOR:Copy()
return Color( self.r, self.g, self.b, self.a )
end
function COLOR:Lerp( target_clr, frac )
return Color(
Lerp( frac, self.r, target_clr.r ),
Lerp( frac, self.g, target_clr.g ),
Lerp( frac, self.b, target_clr.b ),
Lerp( frac, self.a, target_clr.a )
)
end
function COLOR:SetUnpacked( r, g, b, a )
if ( r != nil and !isnumber( r ) ) then error( "bad argument #1 to 'SetUnpacked' (number expected, got " .. type( r ) .. ")", 2 ) end
if ( g != nil and !isnumber( g ) ) then error( "bad argument #2 to 'SetUnpacked' (number expected, got " .. type( g ) .. ")", 2 ) end
if ( b != nil and !isnumber( b ) ) then error( "bad argument #3 to 'SetUnpacked' (number expected, got " .. type( b ) .. ")", 2 ) end
if ( a != nil and !isnumber( a ) ) then error( "bad argument #4 to 'SetUnpacked' (number expected, got " .. type( a ) .. ")", 2 ) end
self.r = r or 255
self.g = g or 255
self.b = b or 255
self.a = a or 255
end
function COLOR:ToTable()
return { self.r, self.g, self.b, self.a }
end
local function ColorCopy( dest, origin )
dest.r = origin.r
dest.g = origin.g
dest.b = origin.b
end
-- HSV hue
function COLOR:GetHue()
local hue = self:ToHSV()
return hue
end
function COLOR:SetHue( hue )
local _, saturation, brightness = self:ToHSV()
hue = hue % 360
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
function COLOR:AddHue( hueAdd )
local hue, saturation, brightness = self:ToHSV()
hue = ( hue + hueAdd ) % 360
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
-- HSV saturation
function COLOR:GetSaturation()
local _, saturation = self:ToHSV()
return saturation
end
function COLOR:SetSaturation( saturation )
local hue, _, brightness = self:ToHSV()
saturation = math.Clamp( saturation, 0, 1 )
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
function COLOR:AddSaturation( saturationAdd )
local hue, saturation, brightness = self:ToHSV()
saturation = math.Clamp( saturation + saturationAdd, 0, 1 )
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
-- HSV brightness
function COLOR:GetBrightness()
local _, _, brightness = self:ToHSV()
return brightness
end
function COLOR:SetBrightness( brightness )
local hue, saturation = self:ToHSV()
brightness = math.Clamp( brightness, 0, 1 )
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
function COLOR:AddBrightness( brightnessAdd )
local hue, saturation, brightness = self:ToHSV()
brightness = math.Clamp( brightness + brightnessAdd, 0, 1 )
ColorCopy( self, HSVToColor( hue, saturation, brightness ) )
end
-- HSL lightness
function COLOR:GetLightness()
local _, _, lightness = self:ToHSL()
return lightness
end
function COLOR:SetLightness( lightness )
local hue, saturation = self:ToHSL()
lightness = math.Clamp( lightness, 0, 1 )
ColorCopy( self, HSLToColor( hue, saturation, lightness ) )
end
function COLOR:AddLightness( lightnessAdd )
local hue, saturation, lightness = self:ToHSL()
lightness = math.Clamp( lightness + lightnessAdd, 0, 1 )
ColorCopy( self, HSLToColor( hue, saturation, lightness ) )
end
-- HWB whiteness
function COLOR:GetWhiteness()
local _, whiteness = self:ToHWB()
return whiteness
end
function COLOR:SetWhiteness( whiteness )
local hue, _, blackness = self:ToHWB()
whiteness = math.Clamp( whiteness, 0, 1 )
ColorCopy( self, HWBToColor( hue, whiteness, blackness ) )
end
function COLOR:AddWhiteness( whitenessAdd )
local hue, whiteness, blackness = self:ToHWB()
whiteness = math.Clamp( whiteness + whitenessAdd, 0, 1 )
ColorCopy( self, HWBToColor( hue, whiteness, blackness ) )
end
-- HWB blackness
function COLOR:GetBlackness()
local _, _, blackness = self:ToHWB()
return blackness
end
function COLOR:SetBlackness( blackness )
local hue, whiteness = self:ToHWB()
blackness = math.Clamp( blackness, 0, 1 )
ColorCopy( self, HWBToColor( hue, whiteness, blackness ) )
end
function COLOR:AddBlackness( blacknessAdd )
local hue, whiteness, blackness = self:ToHWB()
blackness = math.Clamp( blackness + blacknessAdd, 0, 1 )
ColorCopy( self, HWBToColor( hue, whiteness, blackness ) )
end

View File

@@ -0,0 +1,40 @@
function JS_Language( html )
html:AddFunction( "language", "Update", function( phrase )
if ( !phrase ) then return end
return language.GetPhrase( phrase )
end )
end
function JS_Utility( html )
html:AddFunction( "util", "MotionSensorAvailable", function()
return motionsensor.IsAvailable()
end )
end
function JS_Workshop( html )
html:AddFunction( "gmod", "OpenWorkshopFile", function( param ) steamworks.ViewFile( param ) end )
html:AddFunction( "gmod", "DeleteLocal", function( param ) file.Delete( param, "MOD" ) end )
html:AddFunction( "gmod", "FetchItems", function( namespace, cat, offset, perpage, extraTags, searchText, filter, sort )
_G[ namespace ]:Fetch( cat, tonumber( offset ), tonumber( perpage ), string.Explode( ",", extraTags ), searchText, filter, sort )
end )
html:AddFunction( "gmod", "Vote", function( id, vote ) steamworks.Vote( id, tobool( vote ) ) end )
html:AddFunction( "gmod", "SetFavorite", function( id, vote ) steamworks.SetFavorite( id, tobool( vote ) ) end )
html:AddFunction( "gmod", "Publish", function( namespace, filePath, background ) _G[ namespace ]:Publish( filePath, background ) end )
// Dupes
html:AddFunction( "gmod", "DownloadDupe", function( param ) ws_dupe:DownloadAndArm( param ) end )
html:AddFunction( "gmod", "ArmDupe", function( param ) ws_dupe:Arm( param ) end )
html:AddFunction( "gmod", "SaveDupe", function() RunConsoleCommand( "dupe_save", "spawnmenu" ) end )
// Saves
html:AddFunction( "gmod", "DownloadSave", function( param ) ws_save:DownloadAndLoad( param ) end )
html:AddFunction( "gmod", "LoadSave", function( param ) ws_save:Load( param ) end )
html:AddFunction( "gmod", "SaveSave", function() RunConsoleCommand( "gm_save", "spawnmenu" ) end )
end

View File

@@ -0,0 +1,93 @@
--=============================================================================--
-- ___ ___ _ _ _ __ _ ___ ___ __ __
-- |_ _|| __| / \ | \_/ | / _| / \ | o \ o \\ V /
-- | | | _| | o || \_/ | ( |_n| o || / / \ /
-- |_| |___||_n_||_| |_| \__/|_n_||_|\\_|\\ |_| 2007
--
--=============================================================================--
local DatabasedModels = {}
if ( !sql.TableExists( "modelinfo" ) ) then
sql.Query( [[CREATE TABLE IF NOT EXISTS modelinfo ( name TEXT NOT NULL PRIMARY KEY,
poseparams INTEGER,
numsequences INTEGER,
numattachments INTEGER,
numbonecontrollers INTEGER,
numskins INTEGER,
size INTEGER );]] )
end
--[[---------------------------------------------------------
Called from the engine on model load to enable Lua to cache
the model stats in a database, so that rather than building
all in one go, they'll get updated as the player plays.
-----------------------------------------------------------]]
function OnModelLoaded( ModelName, NumPoseParams, NumSeq, NumAttachments, NumBoneControllers, NumSkins, Size )
local ModelName = string.lower( string.gsub( ModelName, "\\", "/" ) )
ModelName = "models/".. ModelName
-- No need to store a model more than once per session
if ( DatabasedModels[ ModelName ] ) then return end
DatabasedModels[ ModelName ] = true
-- Just in case. Don't want errors spewing all over
-- the place every time a model loads.
if ( !sql.TableExists( "modelinfo" ) ) then return end
local safeModelName = SQLStr( ModelName )
--
-- We delete the old entry because this model may have been updated.
-- The chances are very slim, but there's no real harm in it.
--
sql.Query( "DELETE FROM modelinfo WHERE model = "..safeModelName )
sql.Query( Format( [[INSERT INTO modelinfo ( name,
poseparams,
numsequences,
numattachments,
numbonecontrollers,
numskins,
size )
VALUES
( %s, %i, %i, %i, %i, %i, %i ) ]],
safeModelName,
NumPoseParams,
NumSeq,
NumAttachments,
NumBoneControllers,
NumSkins,
Size
) )
--[[
MsgN( ModelName,
"\nNumPoseParams: ", NumPoseParams,
"\nNumSeq: ", NumSeq,
"\nNumAttachments: ", NumAttachments,
"\nNumBoneControllers: ", NumBoneControllers,
"\nNumSkins: ", NumSkins,
"\nSize: ", Size )
--]]
end
--[[---------------------------------------------------------
Returns the number of skins this model has. If we don't
know, it will return 0
-----------------------------------------------------------]]
function NumModelSkins( ModelName )
local ModelName = string.lower( ModelName )
local safeModelName = SQLStr( ModelName )
local num = sql.QueryValue( "SELECT numskins FROM modelinfo WHERE name = " .. safeModelName )
if ( num == nil ) then return 0 end
return tonumber( num ) or 0
end

109
lua/includes/util/sql.lua Normal file
View File

@@ -0,0 +1,109 @@
-- Return if there's nothing to add on to
if ( !sql ) then return end
--[[----------------------------------------------------------
Attempts to make a string safe to put into the database
------------------------------------------------------------]]
function sql.SQLStr( str_in, bNoQuotes )
local str = tostring( str_in )
str = str:gsub( "'", "''" )
local null_chr = string.find( str, "\0" )
if ( null_chr ) then
str = string.sub( str, 1, null_chr - 1 )
end
if ( bNoQuotes ) then
return str
end
return "'" .. str .. "'"
end
SQLStr = sql.SQLStr
--[[---------------------------------------------------------
Returns true if the table exists. False if it doesn't
-----------------------------------------------------------]]
function sql.TableExists( name )
local r = sql.Query( "SELECT name FROM sqlite_master WHERE name=" .. SQLStr( name ) .. " AND type='table'" )
return r and true or false
end
--[[---------------------------------------------------------
Returns true if the index exists. False if it doesn't
-----------------------------------------------------------]]
function sql.IndexExists( name )
local r = sql.Query( "SELECT name FROM sqlite_master WHERE name=" .. SQLStr( name ) .. " AND type='index'" )
return r and true or false
end
--[[---------------------------------------------------------
Query and get a single row
eg sql.QueryRow( "SELECT * from ratings LIMIT 1" )
-----------------------------------------------------------]]
function sql.QueryRow( query, row )
row = row or 1
local r = sql.Query( query )
if ( r ) then return r[ row ] end
return r
end
--[[---------------------------------------------------------
Query and get a single value
eg sql.QueryValue( "SELECT count(*) from ratings" )
-----------------------------------------------------------]]
function sql.QueryValue( query )
local r = sql.QueryRow( query )
if ( r ) then
-- Is this really the best way to get the first/only value in a table
for k, v in pairs( r ) do return v end
end
return r
end
--[[---------------------------------------------------------
Call before lots of inserts (100+), will hold off writing to disk
until Commit is called, which will increase performance (a lot)
-----------------------------------------------------------]]
function sql.Begin()
sql.Query( "BEGIN;" )
end
--[[---------------------------------------------------------
See Above
-----------------------------------------------------------]]
function sql.Commit()
sql.Query( "COMMIT;" )
end
--[[----------------------------------------------------------
m_strError is set by the dll
------------------------------------------------------------]]
function sql.LastError()
return sql.m_strError
end

View File

@@ -0,0 +1,81 @@
local Tooltip = nil
--local TooltippedPanel = nil
--[[---------------------------------------------------------
Name: ChangeTooltip
Called from engine on hovering over a panel
-----------------------------------------------------------]]
function RemoveTooltip()
if ( !IsValid( Tooltip ) ) then return true end
-- Helper for SetTooltipPanelOverride
if ( Tooltip.Close ) then Tooltip:Close() else Tooltip:Remove() end
Tooltip = nil
return true
end
--[[---------------------------------------------------------
Name: FindTooltip
-----------------------------------------------------------]]
function FindTooltip( panel )
-- Look at the parent panel for tooltips.
while ( IsValid( panel ) ) do
if ( panel.strTooltipText || panel.pnlTooltipPanel || panel.pnlTooltipPanelOverride ) then
return panel.strTooltipText, panel.pnlTooltipPanel, panel, panel.pnlTooltipPanelOverride
end
panel = panel:GetParent()
end
end
--[[---------------------------------------------------------
Name: ChangeTooltip
Called from engine on hovering over a panel
-----------------------------------------------------------]]
function ChangeTooltip( panel )
RemoveTooltip()
local Text, ContentPanel, PositionPanel, PanelOverride = FindTooltip( panel )
if ( !Text && !IsValid( ContentPanel ) && !PanelOverride ) then return end
Tooltip = vgui.Create( PanelOverride or "DTooltip" )
if ( Text ) then
Tooltip:SetText( Text )
elseif ( IsValid( ContentPanel ) ) then
Tooltip:SetContents( ContentPanel, false )
end
Tooltip:OpenForPanel( PositionPanel )
--TooltippedPanel = panel
end
--[[---------------------------------------------------------
Name: EndTooltip
Called from engine on exiting from a panel
-----------------------------------------------------------]]
function EndTooltip( panel )
-- Don't do these checks, the engine has a problem with determing
-- which panel is currently being hovered in some very specific and unknown conditions
--if ( !IsValid( TooltippedPanel ) ) then return end
--if ( TooltippedPanel != panel ) then return end
RemoveTooltip()
end

View File

@@ -0,0 +1,41 @@
local Panels = {}
hook.Add( "DrawOverlay", "VGUIShowLayoutPaint", function()
for panel, data in pairs( Panels ) do
if ( panel:IsValid() ) then
local x, y = panel:LocalToScreen( 0, 0 )
local Alpha = math.Clamp( (data.Time - SysTime()) / 0.3, 0, 1 ) * 100
surface.SetDrawColor( 255, 0, 0, Alpha )
surface.DrawRect( x, y, panel:GetWide(), panel:GetTall() )
surface.SetDrawColor( 0, 255, 0, Alpha )
surface.DrawOutlinedRect( x, y, panel:GetWide(), panel:GetTall() )
-- vgui_visualizelayout 2?
-- draw.SimpleText( panel:GetZPos(), "Default", x + 3, y, color_white )
end
if ( !panel:IsValid() || data.Time < SysTime() ) then
Panels[ panel ] = nil
end
end
end )
-- Called from the engine
function VisualizeLayout( panel )
local tab = {}
tab.Time = SysTime() + 0.3
Panels[ panel ] = tab
end

View File

@@ -0,0 +1,298 @@
local PreviewCache = {}
local InfoCache = {}
local ListCache = {}
function WorkshopFileBase( namespace, requiredtags )
local ret = {}
ret.HTML = nil
function ret:Fetch( type, offset, perpage, extratags, searchText, filter, sort )
local tags = table.Copy( requiredtags )
for k, v in pairs( extratags ) do
if ( v == "" ) then continue end
table.insert( tags, v )
end
if ( type == "local" ) then
return self:FetchLocal( offset, perpage )
end
if ( type == "subscribed" ) then
return self:FetchSubscribed( offset, perpage, tags, searchText, false, filter, sort )
end
if ( type == "subscribed_ugc" ) then
return self:FetchSubscribed( offset, perpage, tags, searchText, true, filter, sort )
end
local userid = "0"
if ( type == "mine" ) then userid = "1" end
local cachename = type .. "-" .. table.concat( tags, "/" ) .. offset .. "-" .. perpage .. "-" .. userid
if ( type != "favorite" && ListCache[ cachename ] ) then
self:FillFileInfo( ListCache[ cachename ] )
return
end
steamworks.GetList( type, tags, offset, perpage, 0, userid, function( data )
if ( type != "favorite" ) then ListCache[ cachename ] = data end
self:FillFileInfo( data )
end )
end
function ret:FetchSubscribed( offset, perpage, tags, searchText, isUGC, filter, sort )
local subscriptions = {}
if ( isUGC ) then
subscriptions = engine.GetUserContent()
else
subscriptions = engine.GetAddons()
end
for id, e in pairs( subscriptions ) do
if ( e.timeadded == 0 ) then e.timeadded = os.time() end
end
if ( sort == "title" ) then
table.sort( subscriptions, function( a, b )
return a.title:lower() < b.title:lower()
end )
elseif ( sort == "size" ) then
table.sort( subscriptions, function( a, b )
return a.size > b.size
end )
elseif ( sort == "updated" ) then
table.sort( subscriptions, function( a, b )
return a.updated > b.updated
end )
else
table.sort( subscriptions, function( a, b )
return a.timeadded > b.timeadded
end )
end
-- First build a list of items that fit our search terms
local searchedItems = {}
local localFileHack = -1
for id, item in pairs( subscriptions ) do
-- This is a dirty hack for local addons, ideally should be done in engine, or not use solely IDs to identify addons
if ( item.wsid == "0" ) then
item.wsid = tostring( localFileHack ) -- why is this a string?
localFileHack = localFileHack - 1
end
-- Search for tags
local found = true
for _, tag in pairs( tags ) do
if ( !item.tags:lower():find( tag, 1, true ) ) then found = false end
end
if ( !found ) then continue end
-- Search for searchText
if ( searchText:Trim() != "" && !item.title:lower():find( searchText:lower(), 1, true ) ) then
continue
end
if ( filter && filter == "enabledonly" && !steamworks.ShouldMountAddon( item.wsid ) ) then
continue
end
if ( filter && filter == "disabledonly" && steamworks.ShouldMountAddon( item.wsid ) ) then
continue
end
searchedItems[ #searchedItems + 1 ] = item
end
-- Build the page!
local data = {
totalresults = #searchedItems,
extraresults = {}, -- The local info about the addon
otherresults = {}, -- The complete list of IDs that match the search query for the Addons menu UI
results = {}
}
-- Add the list of all items for "select all" in the UI
local i = 0
for id, item in ipairs( searchedItems ) do
data.otherresults[ i ] = item.wsid
i = i + 1
end
-- Add the actual results for the requested range
local p = 0
while ( p < perpage ) do
if ( searchedItems[ offset + p + 1 ] ) then
local res = table.insert( data.results, searchedItems[ offset + p + 1 ].wsid )
data.extraresults[ res ] = searchedItems[ offset + p + 1 ]
end
p = p + 1
end
self:FillFileInfo( data, isUGC )
end
function ret:RetrieveUserName( steamid, func )
steamworks.RequestPlayerInfo( steamid, function( name )
self.HTML:Call( namespace .. ".ReceiveUserName( \"" .. steamid:JavascriptSafe() .. "\", \"" .. name:JavascriptSafe() .. "\" )" )
if ( func ) then func( name ) end
end )
end
function ret:FillFileInfo( results, isUGC )
--
-- File info failed..
--
if ( !results ) then return end
--
-- Send the file index..
--
local json = util.TableToJSON( results, false )
self.HTML:Call( namespace .. ".ReceiveIndex( " .. json .. " )" )
--
-- Request info on each file..
--
for k, v in pairs( results.results ) do
v = v:JavascriptSafe()
--
-- Got it cached?
--
if ( PreviewCache[ v ] ) then
self.HTML:Call( namespace .. ".ReceiveImage( \"" .. v .. "\", \"" .. PreviewCache[ v ] .. "\" )" )
end
--
-- Get the file information
--
if ( tonumber( v ) <= 0 ) then
-- Local addon
local extra = results.extraresults[ k ]
if ( !extra ) then extra = {} end
extra.ownername = "Local"
extra.description = "Non workshop .gma addon. (" .. extra.file .. ")"
extra.floating = true
local jsonExtra = util.TableToJSON( extra, false )
self.HTML:Call( namespace .. ".ReceiveFileInfo( \"" .. v .. "\", " .. jsonExtra .. " )" )
self.HTML:Call( namespace .. ".ReceiveImage( \"" .. v .. "\", \"html/img/localaddon.png\" )" )
-- Do not try to get votes for this one
continue
elseif ( InfoCache[ v ] ) then
self.HTML:Call( namespace .. ".ReceiveFileInfo( \"" .. v .. "\", " .. InfoCache[ v ] .. " )" )
if ( MENU_DLL ) then
-- This could've changed..
steamworks.FileUserInfo( v, function( info )
if ( info.error ) then return end
local localUI = util.TableToJSON( info, false )
self.HTML:Call( namespace .. ".ReceiveFileUserInfo( \"" .. v .. "\", " .. localUI .. " )" )
end )
end
else
steamworks.FileInfo( v, function( result )
if ( !result || result.error != nil ) then
-- Try to get the title from the GetAddons(), this probably could be done more efficiently
local title = "Offline addon"
for id, t in pairs( isUGC && engine.GetUserContent() || engine.GetAddons() ) do
if ( tonumber( v ) == tonumber( t.wsid ) ) then title = t.title break end
end
local jsonErr = util.TableToJSON( { title = title, description = "Failed to get addon info, error code " .. ( result && result.error || "unknown" ) }, false )
self.HTML:Call( namespace .. ".ReceiveFileInfo( \"" .. v .. "\", " .. jsonErr .. " )" )
return
end
if ( result.description ) then
result.description = string.gsub( result.description, "%[img%]([^%]]*)%[/img%]", "" ) -- Gotta remove inner content of img tags
result.description = string.gsub( result.description, "%[([^%]]*)%]", "" )
result.description = string.Trim( result.description )
end
if ( result.owner && ( !result.ownername || result.ownername == "" || result.ownername == "[unknown]" ) ) then
self:RetrieveUserName( result.owner, function( name )
result.ownername = name
local jsonUN = util.TableToJSON( result, false )
InfoCache[ v ] = jsonUN
end )
end
local jsonFI = util.TableToJSON( result, false )
InfoCache[ v ] = jsonFI
self.HTML:Call( namespace .. ".ReceiveFileInfo( \"" .. v .. "\", " .. jsonFI .. " )" )
--
-- Now we have the preview id - get the preview image!
--
if ( !PreviewCache[ v ] && result.previewid ) then
steamworks.Download( result.previewid, false, function( name )
-- Download failed
if ( !name ) then return end
PreviewCache[ v ] = name:JavascriptSafe()
self.HTML:Call( namespace .. ".ReceiveImage( \"" .. v .. "\", \"" .. PreviewCache[ v ] .. "\" )" )
end )
end
if ( MENU_DLL ) then
steamworks.FileUserInfo( v, function( info )
if ( info.error ) then return end
local localUI = util.TableToJSON( info, false )
self.HTML:Call( namespace .. ".ReceiveFileUserInfo( \"" .. v .. "\", " .. localUI .. " )" )
end )
end
end )
end
end
end
function ret:Publish( filename, image )
--MsgN( "PUBLISHING ", filename )
--MsgN( "Image ", image )
local window = vgui.Create( "UGCPublishWindow" )
window:Setup( namespace, filename, image, self )
window:MakePopup()
window:DoModal() -- We want the user to either finish this or quit
end
return ret
end