Initial commit
This commit is contained in:
188
lua/entities/sent_ball.lua
Normal file
188
lua/entities/sent_ball.lua
Normal file
@@ -0,0 +1,188 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS( "base_anim" )
|
||||
|
||||
ENT.PrintName = "#sent_ball"
|
||||
ENT.Author = "Garry Newman"
|
||||
ENT.Information = "An edible bouncy ball. Press USE on the bouncy ball to eat it."
|
||||
ENT.Category = "#spawnmenu.category.fun_games"
|
||||
|
||||
ENT.Editable = true
|
||||
ENT.Spawnable = true
|
||||
ENT.AdminOnly = false
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
|
||||
ENT.MinSize = 4
|
||||
ENT.MaxSize = 128
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "BallSize", { KeyName = "ballsize", Edit = { type = "Float", min = self.MinSize, max = self.MaxSize, order = 1 } } )
|
||||
self:NetworkVar( "Vector", 0, "BallColor", { KeyName = "ballcolor", Edit = { type = "VectorColor", order = 2 } } )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:NetworkVarNotify( "BallSize", self.OnBallSizeChanged )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- This is the spawn function. It's called when a client calls the entity to be spawned.
|
||||
-- If you want to make your SENT spawnable you need one of these functions to properly create the entity
|
||||
--
|
||||
-- ply is the name of the player that is spawning it
|
||||
-- tr is the trace from the player's eyes
|
||||
--
|
||||
function ENT:SpawnFunction( ply, tr, ClassName )
|
||||
|
||||
if ( !tr.Hit ) then return end
|
||||
|
||||
local size = math.random( 16, 48 )
|
||||
local SpawnPos = tr.HitPos + tr.HitNormal * size
|
||||
|
||||
-- Make sure the spawn position is not out of bounds
|
||||
local oobTr = util.TraceLine( {
|
||||
start = tr.HitPos,
|
||||
endpos = SpawnPos,
|
||||
mask = MASK_SOLID_BRUSHONLY
|
||||
} )
|
||||
|
||||
if ( oobTr.Hit ) then
|
||||
SpawnPos = oobTr.HitPos + oobTr.HitNormal * ( tr.HitPos:Distance( oobTr.HitPos ) / 2 )
|
||||
end
|
||||
|
||||
local ent = ents.Create( ClassName )
|
||||
ent:SetPos( SpawnPos )
|
||||
ent:SetBallSize( size )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
return ent
|
||||
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
|
||||
-- We do NOT want to execute anything below in this FUNCTION on CLIENT
|
||||
if ( CLIENT ) then return end
|
||||
|
||||
-- Use the helibomb model just for the shadow (because it's about the same size)
|
||||
self:SetModel( "models/Combine_Helicopter/helicopter_bomb01.mdl" )
|
||||
|
||||
-- We will put this here just in case, even though it should be called from OnBallSizeChanged in any case
|
||||
self:RebuildPhysics()
|
||||
|
||||
-- Set the size if it wasn't set already..
|
||||
if ( self:GetBallSize() == 0 ) then self:SetBallSize( 32 ) end
|
||||
|
||||
-- Select a random color for the ball, if one wasn't set.
|
||||
if ( !self:GetBallColor():IsZero() ) then return end
|
||||
|
||||
self:SetBallColor( table.Random( {
|
||||
Vector( 1, 0.3, 0.3 ),
|
||||
Vector( 0.3, 1, 0.3 ),
|
||||
Vector( 1, 1, 0.3 ),
|
||||
Vector( 0.2, 0.3, 1 ),
|
||||
} ) )
|
||||
|
||||
end
|
||||
|
||||
function ENT:RebuildPhysics( value )
|
||||
|
||||
-- This is necessary so that the vphysics.dll will not crash when attaching constraints to the new PhysObj after old one was destroyed
|
||||
-- TODO: Somehow figure out why it happens and/or move this code/fix to the constraint library
|
||||
self.ConstraintSystem = nil
|
||||
|
||||
local size = math.Clamp( value or self:GetBallSize(), self.MinSize, self.MaxSize ) / 2.1
|
||||
self:PhysicsInitSphere( size, "metal_bouncy" )
|
||||
self:SetCollisionBounds( Vector( -size, -size, -size ), Vector( size, size, size ) )
|
||||
|
||||
self:PhysWake()
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then
|
||||
|
||||
function ENT:OnBallSizeChanged( varname, oldvalue, newvalue )
|
||||
|
||||
-- Do not rebuild if the size wasn't changed
|
||||
if ( oldvalue == newvalue ) then return end
|
||||
|
||||
self:RebuildPhysics( newvalue )
|
||||
|
||||
end
|
||||
|
||||
function ENT:KeyValue( key, val )
|
||||
if ( key == "ball_size" ) then self:SetBallSize( val ) end
|
||||
if ( key == "rendercolor" ) then self:SetBallColor( Vector( val ) / 255 ) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local BounceSound = Sound( "garrysmod/balloon_pop_cute.wav" )
|
||||
|
||||
function ENT:PhysicsCollide( data, physobj )
|
||||
|
||||
-- Play sound on bounce
|
||||
if ( data.Speed > 60 && data.DeltaTime > 0.2 ) then
|
||||
|
||||
local pitch = 32 + 128 - math.Clamp( self:GetBallSize(), self.MinSize, self.MaxSize )
|
||||
sound.Play( BounceSound, self:GetPos(), 75, math.random( pitch - 10, pitch + 10 ), math.Clamp( data.Speed / 150, 0, 1 ) )
|
||||
|
||||
end
|
||||
|
||||
-- Bounce like a crazy bitch
|
||||
local LastSpeed = math.max( data.OurOldVelocity:Length(), data.Speed )
|
||||
local NewVelocity = physobj:GetVelocity()
|
||||
NewVelocity:Normalize()
|
||||
|
||||
LastSpeed = math.max( NewVelocity:Length(), LastSpeed )
|
||||
|
||||
local TargetVelocity = NewVelocity * LastSpeed * 0.9
|
||||
|
||||
physobj:SetVelocity( TargetVelocity )
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnTakeDamage( dmginfo )
|
||||
|
||||
-- React physically when shot/getting blown
|
||||
self:TakePhysicsDamage( dmginfo )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Use( activator, caller )
|
||||
|
||||
self:Remove()
|
||||
|
||||
if ( activator:IsPlayer() ) then
|
||||
|
||||
-- Give the collecting player some free health
|
||||
local health = activator:Health()
|
||||
activator:SetHealth( health + 5 )
|
||||
activator:SendLua( "achievements.EatBall()" )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if ( SERVER ) then return end -- We do NOT want to execute anything below in this FILE on SERVER
|
||||
|
||||
local matBall = Material( "sprites/sent_ball" )
|
||||
|
||||
function ENT:Draw()
|
||||
|
||||
render.SetMaterial( matBall )
|
||||
|
||||
local pos = self:GetPos()
|
||||
local lcolor = render.ComputeLighting( pos, Vector( 0, 0, 1 ) )
|
||||
local c = self:GetBallColor()
|
||||
|
||||
lcolor.x = c.r * ( math.Clamp( lcolor.x, 0, 1 ) + 0.5 ) * 255
|
||||
lcolor.y = c.g * ( math.Clamp( lcolor.y, 0, 1 ) + 0.5 ) * 255
|
||||
lcolor.z = c.b * ( math.Clamp( lcolor.z, 0, 1 ) + 0.5 ) * 255
|
||||
|
||||
local size = math.Clamp( self:GetBallSize(), self.MinSize, self.MaxSize )
|
||||
render.DrawSprite( pos, size, size, Color( lcolor.x, lcolor.y, lcolor.z, 255 ) )
|
||||
|
||||
end
|
||||
114
lua/entities/widget_arrow.lua
Normal file
114
lua/entities/widget_arrow.lua
Normal file
@@ -0,0 +1,114 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS( "widget_base" )
|
||||
|
||||
local matArrow = Material( "widgets/arrow.png", "nocull alphatest smooth mips" )
|
||||
local matScale = Material( "widgets/scale.png", "nocull alphatest smooth mips" )
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
BaseClass.SetupDataTables( self )
|
||||
|
||||
self:NetworkVar( "Bool", 2, "IsScaleArrow" )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetIsScaleArrow( false )
|
||||
end
|
||||
|
||||
end
|
||||
--
|
||||
-- Set our dimensions etc
|
||||
--
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetSize( 16 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:PressedShouldDraw( widget ) return widget == self end
|
||||
|
||||
function ENT:OverlayRender()
|
||||
|
||||
local fwd = self:GetAngles():Forward()
|
||||
local size = self:GetSize() * 0.5
|
||||
|
||||
local c = self:GetColor()
|
||||
|
||||
if ( !self:IsHovered() && !self:IsPressed() ) then
|
||||
c.r = c.r * 0.5
|
||||
c.g = c.g * 0.5
|
||||
c.b = c.b * 0.5
|
||||
end
|
||||
|
||||
if ( self:GetIsScaleArrow() ) then
|
||||
render.SetMaterial( matScale )
|
||||
else
|
||||
render.SetMaterial( matArrow )
|
||||
end
|
||||
|
||||
local pos = self:GetPos()
|
||||
|
||||
render.DepthRange( 0, 0.01 )
|
||||
render.DrawBeam( pos, pos + fwd * size, 2, 1, 0, Color( c.r, c.g, c.b, c.a * 0.1 ) )
|
||||
render.DepthRange( 0, 1 * self:GetPriority() )
|
||||
render.DrawBeam( pos, pos + fwd * size, 2, 1, 0, c )
|
||||
render.DepthRange( 0, 1 )
|
||||
|
||||
end
|
||||
|
||||
function ENT:TestCollision( startpos, delta, isbox, extents )
|
||||
|
||||
if ( isbox ) then return end
|
||||
if ( !widgets.Tracing ) then return end
|
||||
|
||||
local size = self:GetSize() * 0.5
|
||||
|
||||
local mins = Vector( 0, -1, -1 )
|
||||
local maxs = Vector( size, 1, 1 )
|
||||
|
||||
local hit, norm, fraction = util.IntersectRayWithOBB( startpos, delta, self:GetPos(), self:GetAngles(), mins, maxs )
|
||||
if ( !hit ) then return end
|
||||
|
||||
--debugoverlay.BoxAngles( self:GetPos(), mins, maxs, self:GetAngles(), 0.1, Color( 0, 0, 255, 64 ) )
|
||||
|
||||
return {
|
||||
HitPos = hit,
|
||||
Fraction = fraction * self:GetPriority()
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function ENT:DragThink( pl, mv, dist )
|
||||
|
||||
local d = dist.x * -1
|
||||
|
||||
self:ArrowDragged( pl, mv, d )
|
||||
|
||||
end
|
||||
|
||||
function ENT:ArrowDragged( pl, mv, dist )
|
||||
end
|
||||
|
||||
function ENT:GetGrabPos( Pos, Forward )
|
||||
|
||||
local fwd = Forward
|
||||
local eye = Pos
|
||||
local arrowdir = self:GetAngles():Forward()
|
||||
|
||||
local planepos = self:GetPos()
|
||||
local planenrm = ( eye - planepos ):GetNormalized()
|
||||
|
||||
local hitpos = util.IntersectRayWithPlane( eye, fwd, planepos, planenrm )
|
||||
if ( !hitpos ) then return end
|
||||
|
||||
-- Get nearest point along the arrow where we touched it
|
||||
local fdist, vpos, falong = util.DistanceToLine( planepos - arrowdir * 1024, planepos + arrowdir * 1024, hitpos )
|
||||
|
||||
return vpos
|
||||
|
||||
end
|
||||
121
lua/entities/widget_axis.lua
Normal file
121
lua/entities/widget_axis.lua
Normal file
@@ -0,0 +1,121 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
--
|
||||
-- widget_axis_arrow
|
||||
--
|
||||
|
||||
DEFINE_BASECLASS( "widget_arrow" )
|
||||
|
||||
local widget_axis_arrow = { Base = "widget_arrow" }
|
||||
|
||||
function widget_axis_arrow:SetupDataTables()
|
||||
|
||||
BaseClass.SetupDataTables( self )
|
||||
self:NetworkVar( "Int", 0, "AxisIndex" )
|
||||
|
||||
end
|
||||
|
||||
function widget_axis_arrow:ArrowDragged( pl, mv, dist )
|
||||
|
||||
self:GetParent():OnArrowDragged( self:GetAxisIndex(), dist, pl, mv )
|
||||
|
||||
end
|
||||
|
||||
scripted_ents.Register( widget_axis_arrow, "widget_axis_arrow" )
|
||||
|
||||
--
|
||||
-- widget_axis_disc
|
||||
--
|
||||
|
||||
DEFINE_BASECLASS( "widget_disc" )
|
||||
|
||||
local widget_axis_disc = { Base = "widget_disc" }
|
||||
|
||||
function widget_axis_disc:SetupDataTables()
|
||||
|
||||
BaseClass.SetupDataTables( self )
|
||||
self:NetworkVar( "Int", 0, "AxisIndex" )
|
||||
|
||||
end
|
||||
|
||||
|
||||
function widget_axis_disc:ArrowDragged( pl, mv, dist )
|
||||
|
||||
self:GetParent():OnArrowDragged( self:GetAxisIndex(), dist, pl, mv )
|
||||
|
||||
end
|
||||
|
||||
scripted_ents.Register( widget_axis_disc, "widget_axis_disc" )
|
||||
|
||||
DEFINE_BASECLASS( "widget_base" )
|
||||
|
||||
--
|
||||
-- Set our dimensions etc
|
||||
--
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
self:SetCollisionBounds( Vector( -1, -1, -1 ), Vector( 1, 1, 1 ) )
|
||||
self:SetSolid( SOLID_NONE )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Setup( ent, boneid, rotate )
|
||||
|
||||
self:FollowBone( ent, boneid )
|
||||
self:SetLocalPos( vector_origin )
|
||||
self:SetLocalAngles( angle_zero )
|
||||
|
||||
local EntName = "widget_axis_arrow"
|
||||
if ( rotate ) then EntName = "widget_axis_disc" end
|
||||
|
||||
self.ArrowX = ents.Create( EntName )
|
||||
self.ArrowX:SetParent( self )
|
||||
self.ArrowX:SetColor( Color( 255, 0, 0, 255 ) )
|
||||
self.ArrowX:Spawn()
|
||||
self.ArrowX:SetLocalPos( vector_origin )
|
||||
self.ArrowX:SetLocalAngles( Vector( 1, 0, 0 ):Angle() )
|
||||
self.ArrowX:SetAxisIndex( 1 )
|
||||
|
||||
self.ArrowY = ents.Create( EntName )
|
||||
self.ArrowY:SetParent( self )
|
||||
self.ArrowY:SetColor( Color( 0, 230, 50, 255 ) )
|
||||
self.ArrowY:Spawn()
|
||||
self.ArrowY:SetLocalPos( vector_origin )
|
||||
self.ArrowY:SetLocalAngles( Vector( 0, 1, 0 ):Angle() )
|
||||
self.ArrowY:SetAxisIndex( 2 )
|
||||
|
||||
self.ArrowZ = ents.Create( EntName )
|
||||
self.ArrowZ:SetParent( self )
|
||||
self.ArrowZ:SetColor( Color( 50, 100, 255, 255 ) )
|
||||
self.ArrowZ:Spawn()
|
||||
self.ArrowZ:SetLocalPos( vector_origin )
|
||||
self.ArrowZ:SetLocalAngles( Vector( 0, 0, 1 ):Angle() )
|
||||
self.ArrowZ:SetAxisIndex( 3 )
|
||||
|
||||
if ( self.IsScaleArrow && EntName == "widget_axis_arrow" ) then
|
||||
if ( IsValid( self.ArrowX ) ) then self.ArrowX:SetIsScaleArrow( true ) end
|
||||
if ( IsValid( self.ArrowY ) ) then self.ArrowY:SetIsScaleArrow( true ) end
|
||||
if ( IsValid( self.ArrowZ ) ) then self.ArrowZ:SetIsScaleArrow( true ) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:SetPriority( x )
|
||||
|
||||
if ( IsValid( self.ArrowX ) ) then self.ArrowX:SetPriority( x ) end
|
||||
if ( IsValid( self.ArrowY ) ) then self.ArrowY:SetPriority( x ) end
|
||||
if ( IsValid( self.ArrowZ ) ) then self.ArrowZ:SetPriority( x ) end
|
||||
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
|
||||
function ENT:OverlayRender()
|
||||
end
|
||||
|
||||
function ENT:OnArrowDragged( num, dist, pl, mv )
|
||||
end
|
||||
238
lua/entities/widget_base.lua
Normal file
238
lua/entities/widget_base.lua
Normal file
@@ -0,0 +1,238 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
DEFINE_BASECLASS( "base_anim" )
|
||||
|
||||
ENT.Spawnable = false
|
||||
ENT.AdminOnly = false
|
||||
ENT.RenderGroup = RENDERGROUP_TRANSLUCENT
|
||||
ENT.Widget = true
|
||||
|
||||
-- This appears to be unused in the base game, but leaving it in case someones does
|
||||
ENT.Materials = {}
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Float", 0, "SizeVar" ) -- Size (bounds)
|
||||
self:NetworkVar( "Float", 1, "Priority" ) -- Priority above other widgets (clicks, visually)
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Unfilled, for override. Self explanatory.
|
||||
-- Called on both client and server in multiplayer
|
||||
-- Only on the server in singleplayer.
|
||||
--
|
||||
function ENT:OnClick( ply ) end
|
||||
function ENT:OnRightClick( ply ) end
|
||||
function ENT:PressedThink( pl, mv ) end
|
||||
function ENT:PressedShouldDraw( widget ) return true end
|
||||
function ENT:PressStart( pl, mv ) end
|
||||
function ENT:PressEnd( pl, mv ) end
|
||||
function ENT:DragThink( pl, mv, dist ) end
|
||||
|
||||
--
|
||||
-- Set our dimensions etc
|
||||
--
|
||||
function ENT:Initialize()
|
||||
|
||||
self:SetCollisionGroup( COLLISION_GROUP_WORLD )
|
||||
self:DrawShadow( false )
|
||||
self:EnableCustomCollisions()
|
||||
self.Color = Color( 0, 255, 255 )
|
||||
self.Color_Hover = color_white
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetSize( 4 )
|
||||
self:SetPriority( 1 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetSize()
|
||||
return self:GetSizeVar()
|
||||
end
|
||||
|
||||
function ENT:SetSize( size )
|
||||
|
||||
if ( self:GetSize() == size ) then return end
|
||||
|
||||
local sizeVector = Vector( size, size, size )
|
||||
|
||||
self:SetSizeVar( size )
|
||||
self:SetSolid( SOLID_BBOX )
|
||||
self:SetCollisionBounds( sizeVector * -0.5, sizeVector * 0.5 )
|
||||
|
||||
end
|
||||
|
||||
function ENT:GetGrabPos( Pos, Forward )
|
||||
|
||||
local fwd = Forward
|
||||
local eye = Pos
|
||||
|
||||
local planepos = self:GetPos()
|
||||
local planenrm = ( eye - planepos ):GetNormalized()
|
||||
|
||||
return util.IntersectRayWithPlane( eye, fwd, planepos, planenrm )
|
||||
|
||||
end
|
||||
|
||||
function ENT:PressedThinkInternal( ply, mv )
|
||||
|
||||
local eyePos = ply:EyePos()
|
||||
local aimVector = ply:GetAimVector()
|
||||
|
||||
--
|
||||
-- TODO: We should find out why this happens instead of just preventing it!
|
||||
--
|
||||
if ( !istable( ply.WidgetMove ) ) then
|
||||
ply.WidgetMove = {}
|
||||
ply.WidgetMove.EyePos = eyePos
|
||||
ply.WidgetMove.EyeVec = aimVector
|
||||
end
|
||||
|
||||
local widgetMove = ply.WidgetMove
|
||||
local OldPos = self:GetGrabPos( widgetMove.EyePos, widgetMove.EyeVec )
|
||||
local NewPos = self:GetGrabPos( eyePos, aimVector )
|
||||
|
||||
if ( NewPos && OldPos ) then
|
||||
|
||||
local dist = self:WorldToLocal( OldPos ) - self:WorldToLocal( NewPos )
|
||||
local len = dist:LengthSqr()
|
||||
local minLen = 0.01 * 0.01
|
||||
local maxLen = 512 * 512
|
||||
|
||||
if ( len > minLen && len < maxLen ) then
|
||||
self:DragThink( ply, mv, dist )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
self:PressedThink( ply, mv )
|
||||
|
||||
-- Store the (new) old eye positions
|
||||
widgetMove.EyePos = eyePos
|
||||
widgetMove.EyeVec = aimVector
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by widget's Tick hook when a mouse button was
|
||||
-- pressed while hovering over this widget
|
||||
--
|
||||
function ENT:OnPress( ply, iButton, mv )
|
||||
|
||||
if ( self.Pressed ) then return end
|
||||
|
||||
ply:SetPressedWidget( self )
|
||||
|
||||
ply.WidgetMove = {}
|
||||
ply.WidgetMove.EyePos = ply:EyePos()
|
||||
ply.WidgetMove.EyeVec = ply:GetAimVector()
|
||||
|
||||
self:PressStart( ply, mv )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Called by widget's Tick hook when a mouse button was
|
||||
-- released while this widget is pressed
|
||||
--
|
||||
function ENT:OnRelease( ply, iButton, mv )
|
||||
|
||||
ply:SetPressedWidget( NULL )
|
||||
ply.WidgetMove = nil
|
||||
self:PressEnd( ply, mv )
|
||||
|
||||
--
|
||||
-- The player has to click and release on the widget
|
||||
-- or we assume they clicked and changed their mind
|
||||
-- so dragged off.. like people do sometimes.
|
||||
--
|
||||
if ( ply:GetHoveredWidget() != self ) then return end
|
||||
|
||||
--
|
||||
-- Left Mouse
|
||||
--
|
||||
if ( iButton == 1 ) then
|
||||
self:OnClick( ply )
|
||||
end
|
||||
|
||||
--
|
||||
-- Right Mouse
|
||||
--
|
||||
if ( iButton == 1 ) then
|
||||
self:OnRightClick( ply )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:IsHovered()
|
||||
return LocalPlayer():GetHoveredWidget() == self
|
||||
end
|
||||
|
||||
function ENT:SomethingHovered()
|
||||
return IsValid( LocalPlayer():GetHoveredWidget() )
|
||||
end
|
||||
|
||||
function ENT:IsPressed()
|
||||
return LocalPlayer():GetPressedWidget() == self
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
|
||||
widgets.RenderMe( self )
|
||||
|
||||
end
|
||||
|
||||
local colDefault = Color( 0, 0, 50, 255 )
|
||||
local colHovered = Color( 20, 50, 100, 255 )
|
||||
local colPressed = Color( 180, 180, 50, 255 )
|
||||
local colHoveredAndPressed = Color( 255, 255, 100, 255 )
|
||||
|
||||
function ENT:OverlayRender()
|
||||
|
||||
local col = colDefault
|
||||
local ply = LocalPlayer()
|
||||
local hovered = ply:GetHoveredWidget()
|
||||
|
||||
if ( hovered == self ) then
|
||||
col = colHovered
|
||||
end
|
||||
|
||||
if ( self:IsPressed() ) then
|
||||
|
||||
col = colPressed
|
||||
|
||||
if ( hovered == ply:GetPressedWidget() ) then
|
||||
col = colHoveredAndPressed
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local size = self:GetSize()
|
||||
local vSize = Vector( size, size, size )
|
||||
local pos = self:GetPos()
|
||||
local angles = self:GetAngles()
|
||||
|
||||
render.SetColorMaterialIgnoreZ()
|
||||
render.DrawBox( pos, angles, -vSize, vSize, ColorAlpha( col, 0.8 ) )
|
||||
|
||||
render.SetColorMaterial()
|
||||
render.DrawBox( pos, angles, -vSize, vSize, col )
|
||||
|
||||
end
|
||||
|
||||
function ENT:TestCollision( startpos, delta, isbox, extents )
|
||||
|
||||
if ( isbox ) then return end
|
||||
if ( !widgets.Tracing ) then return end
|
||||
|
||||
-- TODO. Actually trace against our cube!
|
||||
|
||||
return {
|
||||
HitPos = self:GetPos(),
|
||||
Fraction = 0.5 * self:GetPriority()
|
||||
}
|
||||
|
||||
end
|
||||
176
lua/entities/widget_bones.lua
Normal file
176
lua/entities/widget_bones.lua
Normal file
@@ -0,0 +1,176 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local matBone = Material( "widgets/bone.png", "smooth" )
|
||||
local matBoneSmall = Material( "widgets/bone_small.png", "smooth" )
|
||||
local c = Color( 255, 255, 255, 255 )
|
||||
|
||||
local widget_bone = {
|
||||
Base = "widget_base",
|
||||
a = 255,
|
||||
|
||||
GetParentPos = function( self )
|
||||
|
||||
local p = self:GetParent()
|
||||
if ( !IsValid( p ) ) then return end
|
||||
|
||||
local bp = p:GetBoneParent( self:GetParentAttachment() )
|
||||
if ( bp <= 0 ) then return end
|
||||
|
||||
return p:GetBonePosition( bp )
|
||||
|
||||
end,
|
||||
|
||||
OverlayRender = function( self )
|
||||
|
||||
local pp = self:GetParentPos()
|
||||
if ( !pp ) then return end
|
||||
|
||||
local len = self:GetSize() / 2
|
||||
local w = len * 0.2
|
||||
|
||||
if ( len > 10 ) then
|
||||
render.SetMaterial( matBone )
|
||||
else
|
||||
render.SetMaterial( matBoneSmall )
|
||||
end
|
||||
|
||||
local hovered = LocalPlayer():GetHoveredWidget()
|
||||
|
||||
if ( IsValid( hovered ) && hovered != self ) then
|
||||
self.a = math.Approach( self.a, 20, FrameTime() * 255 * 10 )
|
||||
else
|
||||
self.a = math.Approach( self.a, 255, FrameTime() * 255 * 10 )
|
||||
end
|
||||
|
||||
local pos = self:GetPos()
|
||||
|
||||
cam.IgnoreZ( true )
|
||||
c.a = self.a * 0.5
|
||||
render.DrawBeam( pos, pp, w, 0, 1, c )
|
||||
cam.IgnoreZ( false )
|
||||
|
||||
c.a = self.a
|
||||
render.DrawBeam( pos, pp, w, 0, 1, c )
|
||||
|
||||
end,
|
||||
|
||||
TestCollision = function( self, startpos, delta, isbox, extents )
|
||||
|
||||
if ( isbox ) then return end
|
||||
if ( !widgets.Tracing ) then return end
|
||||
|
||||
local pp = self:GetParentPos()
|
||||
if ( !pp ) then return end
|
||||
|
||||
local pos = self:GetPos()
|
||||
local fwd = ( pp - pos ):GetNormal()
|
||||
local ang = fwd:Angle()
|
||||
local len = self:GetSize() / 2
|
||||
local w = len * 0.2
|
||||
|
||||
local mins = Vector( 0, w * -0.5, w * -0.5 )
|
||||
local maxs = Vector( len, w * 0.5, w * 0.5 )
|
||||
|
||||
local hit, norm, fraction = util.IntersectRayWithOBB( startpos, delta, pos, ang, mins, maxs )
|
||||
if ( !hit ) then return end
|
||||
|
||||
--debugoverlay.BoxAngles( self:GetPos(), mins, maxs, ang, 0.1, Color( 0, 255, 0, 64 ) )
|
||||
|
||||
return {
|
||||
HitPos = hit,
|
||||
Fraction = fraction * self:GetPriority()
|
||||
}
|
||||
|
||||
end,
|
||||
|
||||
Think = function( self )
|
||||
|
||||
if ( !SERVER ) then return end
|
||||
|
||||
local parent = self:GetParent()
|
||||
|
||||
if ( !IsValid( parent ) ) then return end
|
||||
|
||||
--
|
||||
-- Because the bone length changes (with the manipulator)
|
||||
-- we need to update the bones pretty regularly
|
||||
--
|
||||
|
||||
local size = parent:BoneLength( self:GetParentAttachment() ) * 2
|
||||
size = math.ceil( size )
|
||||
|
||||
self:SetSize( size )
|
||||
|
||||
end,
|
||||
|
||||
CalcAbsolutePosition = function( self, v, a )
|
||||
|
||||
local ent = self:GetParent()
|
||||
if ( !IsValid( ent ) ) then return end
|
||||
|
||||
local bone = self:GetParentAttachment()
|
||||
if ( bone <= 0 ) then return end
|
||||
|
||||
return ent:GetBonePosition( bone )
|
||||
|
||||
end
|
||||
}
|
||||
|
||||
scripted_ents.Register( widget_bone, "widget_bone" )
|
||||
|
||||
DEFINE_BASECLASS( "widget_base" )
|
||||
|
||||
function ENT:SetupDataTables()
|
||||
|
||||
self:NetworkVar( "Entity", 0, "Target" )
|
||||
|
||||
self.BaseClass.SetupDataTables( self )
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
-- Set our dimensions etc
|
||||
--
|
||||
function ENT:Initialize()
|
||||
|
||||
self.BaseClass.Initialize( self )
|
||||
|
||||
self:SetCollisionBounds( Vector( -1, -1, -1 ), Vector( 1, 1, 1 ) )
|
||||
self:SetSolid( SOLID_NONE )
|
||||
|
||||
end
|
||||
|
||||
function ENT:Setup( ent )
|
||||
|
||||
self:SetTarget( ent )
|
||||
self:SetParent( ent )
|
||||
self:SetLocalPos( vector_origin )
|
||||
|
||||
for k = 0, ent:GetBoneCount() - 1 do
|
||||
|
||||
if ( ent:GetBoneParent( k ) <= 0 ) then continue end
|
||||
if ( !ent:BoneHasFlag( k, BONE_USED_BY_VERTEX_LOD0 ) ) then continue end
|
||||
|
||||
local btn = ents.Create( "widget_bone" )
|
||||
btn:FollowBone( ent, k )
|
||||
btn:SetLocalPos( vector_origin )
|
||||
btn:SetLocalAngles( angle_zero )
|
||||
btn:Spawn()
|
||||
btn:SetSize( ent:BoneLength( k ) * 2 )
|
||||
|
||||
btn.OnClick = function( x, ply )
|
||||
self:OnBoneClick( k, ply )
|
||||
end
|
||||
|
||||
self:DeleteOnRemove( btn )
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:OnBoneClick( boneid, ply )
|
||||
end
|
||||
|
||||
function ENT:OverlayRender()
|
||||
end
|
||||
111
lua/entities/widget_disc.lua
Normal file
111
lua/entities/widget_disc.lua
Normal file
@@ -0,0 +1,111 @@
|
||||
|
||||
AddCSLuaFile()
|
||||
|
||||
local matDisc = Material( "widgets/disc.png", "nocull alphatest smooth mips" )
|
||||
local matDiscAlpha = Material( "widgets/disc.png", "nocull smooth mips" )
|
||||
|
||||
DEFINE_BASECLASS( "widget_arrow" )
|
||||
|
||||
--
|
||||
-- Set our dimensions etc
|
||||
--
|
||||
function ENT:Initialize()
|
||||
|
||||
BaseClass.Initialize( self )
|
||||
|
||||
if ( SERVER ) then
|
||||
self:SetSize( 16 )
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ENT:PressedShouldDraw( widget ) return widget == self end
|
||||
|
||||
function ENT:OverlayRender()
|
||||
|
||||
local angles = self:GetAngles()
|
||||
local fwd = angles:Forward()
|
||||
local size = self:GetSize()
|
||||
|
||||
local c = self:GetColor()
|
||||
|
||||
if ( !self:IsHovered() && !self:IsPressed() ) then
|
||||
c.r = c.r * 0.5
|
||||
c.g = c.g * 0.5
|
||||
c.b = c.b * 0.5
|
||||
end
|
||||
|
||||
local pos = self:GetPos()
|
||||
local ang = angles.roll - 90
|
||||
|
||||
render.DepthRange( 0, 0.01 )
|
||||
render.SetMaterial( matDiscAlpha )
|
||||
render.DrawQuadEasy( pos, fwd, size, size, Color( c.r, c.g, c.b, c.a * 0.2 ), ang )
|
||||
render.DepthRange( 0, 1 )
|
||||
render.SetMaterial( matDisc )
|
||||
render.DrawQuadEasy( pos, fwd, size, size, c, ang )
|
||||
render.DepthRange( 0, 1 )
|
||||
|
||||
end
|
||||
|
||||
function ENT:TestCollision( startpos, delta, isbox, extents )
|
||||
|
||||
if ( isbox ) then return end
|
||||
if ( !widgets.Tracing ) then return end
|
||||
|
||||
local fwd = self:GetAngles():Forward()
|
||||
local size = self:GetSize() * 0.5
|
||||
local pos = self:GetPos()
|
||||
|
||||
local hitpos = util.IntersectRayWithPlane( startpos, delta:GetNormalized(), pos, fwd )
|
||||
if ( !hitpos ) then return end
|
||||
|
||||
local dist = pos:DistToSqr( hitpos )
|
||||
size = size * size
|
||||
if ( dist > size ) then return end
|
||||
if ( dist < size * 0.9 ) then return end
|
||||
|
||||
--debugoverlay.Cross( hitpos, 0.5, 60 )
|
||||
|
||||
local fraction = ( hitpos - startpos ):Length() / delta:Length()
|
||||
|
||||
return {
|
||||
HitPos = hitpos,
|
||||
Fraction = fraction * self:GetPriority()
|
||||
}
|
||||
|
||||
end
|
||||
|
||||
function ENT:DragThink( pl, mv, dist )
|
||||
|
||||
local d = dist.x * -1
|
||||
|
||||
self:ArrowDragged( pl, mv, d )
|
||||
|
||||
end
|
||||
|
||||
function ENT:ArrowDragged( pl, mv, dist )
|
||||
end
|
||||
|
||||
function ENT:GetGrabPos( Pos, Forward )
|
||||
|
||||
local fwd = Forward
|
||||
local eye = Pos
|
||||
local arrowdir = self:GetAngles():Forward()
|
||||
|
||||
local planepos = self:GetPos()
|
||||
--local planenrm = ( eye - planepos ):GetNormal()
|
||||
|
||||
local hitpos = util.IntersectRayWithPlane( eye, fwd, planepos, arrowdir )
|
||||
if ( !hitpos ) then return end
|
||||
|
||||
-- The whole circle should be 360
|
||||
hitpos = self:WorldToLocal( hitpos )
|
||||
hitpos:Normalize()
|
||||
|
||||
local angle = math.atan2( hitpos.y, hitpos.z ) + math.pi
|
||||
angle = math.deg( angle ) * -1
|
||||
|
||||
return arrowdir * angle
|
||||
|
||||
end
|
||||
Reference in New Issue
Block a user