mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-17 05:43:46 +03:00
345 lines
9.5 KiB
Lua
345 lines
9.5 KiB
Lua
--[[
|
|
| 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/
|
|
--]]
|
|
|
|
|
|
TOOL.Category = "Poser"
|
|
TOOL.Name = "#tool.eyeposer.name"
|
|
|
|
TOOL.Information = {
|
|
{ name = "left" },
|
|
{ name = "left_use" },
|
|
{ name = "right" },
|
|
{ name = "reload" },
|
|
}
|
|
|
|
TOOL.ClientConVar[ "x" ] = "0"
|
|
TOOL.ClientConVar[ "y" ] = "0"
|
|
TOOL.ClientConVar[ "strabismus" ] = "0"
|
|
|
|
local function SetEyeTarget( ply, ent, data )
|
|
|
|
if ( data.EyeTarget ) then ent:SetEyeTarget( data.EyeTarget ) end
|
|
|
|
if ( SERVER ) then
|
|
if ( data.EyeTarget == vector_origin ) then
|
|
duplicator.ClearEntityModifier( ent, "eyetarget" )
|
|
else
|
|
duplicator.StoreEntityModifier( ent, "eyetarget", data )
|
|
end
|
|
end
|
|
|
|
end
|
|
if ( SERVER ) then
|
|
duplicator.RegisterEntityModifier( "eyetarget", SetEyeTarget )
|
|
end
|
|
|
|
local function ConvertRelativeToEyesAttachment( ent, pos )
|
|
|
|
if ( ent:IsNPC() ) then return pos end
|
|
|
|
-- Convert relative to eye attachment
|
|
local eyeattachment = ent:LookupAttachment( "eyes" )
|
|
if ( eyeattachment == 0 ) then return end
|
|
|
|
local attachment = ent:GetAttachment( eyeattachment )
|
|
if ( !attachment ) then return end
|
|
|
|
return WorldToLocal( pos, angle_zero, attachment.Pos, attachment.Ang )
|
|
|
|
end
|
|
|
|
function TOOL:CalculateEyeTarget()
|
|
|
|
local x = math.Remap( self:GetClientNumber( "x" ), 0, 1, -1, 1 )
|
|
local y = math.Remap( self:GetClientNumber( "y" ), 0, 1, -1, 1 )
|
|
local fwd = Angle( y * 45, x * 45, 0 ):Forward()
|
|
local s = math.Clamp( self:GetClientNumber( "strabismus" ), -1, 1 )
|
|
local distance = 1000
|
|
|
|
if ( s < 0 ) then
|
|
s = math.Remap( s, -1, 0, 0, 1 )
|
|
distance = distance * math.pow( 10000, s - 1 )
|
|
elseif ( s > 0 ) then
|
|
distance = distance * -math.pow( 10000, -s )
|
|
end
|
|
|
|
-- Gotta do this for NPCs...
|
|
local ent = self:GetSelectedEntity()
|
|
if ( IsValid( ent ) and ent:IsNPC() ) then
|
|
local eyeattachment = ent:LookupAttachment( "eyes" )
|
|
if ( eyeattachment == 0 ) then return fwd * distance end
|
|
|
|
local attachment = ent:GetAttachment( eyeattachment )
|
|
if ( !attachment ) then return fwd * distance end
|
|
|
|
return LocalToWorld( fwd * distance, angle_zero, attachment.Pos, attachment.Ang )
|
|
end
|
|
|
|
return fwd * distance
|
|
|
|
end
|
|
|
|
function TOOL:GetSelectedEntity()
|
|
return self:GetWeapon():GetNWEntity( "eyeposer_ent" )
|
|
end
|
|
|
|
function TOOL:SetSelectedEntity( ent )
|
|
|
|
if ( !IsValid( ent ) ) then self:SetOperation( 0 ) end
|
|
|
|
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
|
return self:GetWeapon():SetNWEntity( "eyeposer_ent", ent )
|
|
end
|
|
|
|
-- Selects entity and aims their eyes
|
|
function TOOL:LeftClick( trace )
|
|
|
|
if ( self:GetOwner():KeyDown( IN_USE ) ) then
|
|
return self:MakeLookAtMe( trace )
|
|
end
|
|
|
|
if ( !IsValid( self:GetSelectedEntity() ) or self:GetOperation() != 1 ) then
|
|
|
|
self:SetSelectedEntity( trace.Entity )
|
|
if ( !IsValid( self:GetSelectedEntity() ) ) then return false end
|
|
|
|
local eyeAtt = self:GetSelectedEntity():LookupAttachment( "eyes" )
|
|
if ( eyeAtt == 0 ) then
|
|
self:SetSelectedEntity( NULL )
|
|
return false
|
|
end
|
|
|
|
self:SetOperation( 1 ) -- For UI
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
local selectedEnt = self:GetSelectedEntity()
|
|
|
|
self:SetSelectedEntity( NULL )
|
|
self:SetOperation( 0 )
|
|
|
|
if ( !IsValid( selectedEnt ) ) then return false end
|
|
|
|
local LocalPos = ConvertRelativeToEyesAttachment( selectedEnt, trace.HitPos )
|
|
if ( !LocalPos ) then return false end
|
|
|
|
SetEyeTarget( self:GetOwner(), selectedEnt, { EyeTarget = LocalPos } )
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
-- Select the eyes for posing through UI
|
|
function TOOL:RightClick( trace )
|
|
|
|
local hadEntity = IsValid( self:GetSelectedEntity() )
|
|
|
|
self:SetSelectedEntity( trace.Entity )
|
|
if ( !IsValid( self:GetSelectedEntity() ) ) then return hadEntity end
|
|
|
|
local eyeAtt = self:GetSelectedEntity():LookupAttachment( "eyes" )
|
|
if ( eyeAtt == 0 ) then
|
|
self:SetSelectedEntity( NULL )
|
|
return false
|
|
end
|
|
|
|
-- TODO: Reset? Save and load these raw values from the entity modifier?
|
|
--RunConsoleCommand( "eyeposer_x", 0.5 )
|
|
--RunConsoleCommand( "eyeposer_y", 0.5 )
|
|
--RunConsoleCommand( "eyeposer_strabismus", 0 )
|
|
|
|
self:SetOperation( 2 ) -- For UI
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
-- Makes the eyes look at the player
|
|
function TOOL:MakeLookAtMe( trace )
|
|
|
|
self:SetSelectedEntity( NULL )
|
|
self:SetOperation( 0 )
|
|
|
|
local ent = trace.Entity
|
|
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
|
if ( !IsValid( ent ) ) then return false end
|
|
|
|
if ( CLIENT ) then return true end
|
|
|
|
local pos = self:GetOwner():EyePos()
|
|
|
|
local LocalPos = ConvertRelativeToEyesAttachment( ent, pos )
|
|
if ( !LocalPos ) then return false end
|
|
|
|
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = LocalPos } )
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
-- Reset eye position
|
|
function TOOL:Reload( trace )
|
|
|
|
self:SetSelectedEntity( NULL )
|
|
self:SetOperation( 0 )
|
|
|
|
local ent = trace.Entity
|
|
if ( IsValid( ent ) and ent:GetClass() == "prop_effect" ) then ent = ent.AttachedEntity end
|
|
if ( !IsValid( ent ) ) then return false end
|
|
|
|
if ( CLIENT ) then return true end
|
|
|
|
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = vector_origin } )
|
|
|
|
return true
|
|
|
|
end
|
|
|
|
local validEntityLast = false
|
|
function TOOL:Think()
|
|
|
|
local ent = self:GetSelectedEntity()
|
|
|
|
-- If we're on the client just make sure the context menu is up to date
|
|
if ( CLIENT ) then
|
|
if ( IsValid( ent ) == validEntityLast ) then return end
|
|
|
|
validEntityLast = IsValid( ent )
|
|
self:RebuildControlPanel( validEntityLast )
|
|
|
|
return
|
|
end
|
|
|
|
if ( !IsValid( ent ) ) then self:SetOperation( 0 ) return end
|
|
|
|
if ( self:GetOperation() != 2 ) then return end
|
|
|
|
-- On the server we continually set the eye position
|
|
SetEyeTarget( self:GetOwner(), ent, { EyeTarget = self:CalculateEyeTarget() } )
|
|
|
|
end
|
|
|
|
-- The rest of the code is clientside only, it is not used on server
|
|
if ( SERVER ) then return end
|
|
|
|
local SelectionRing = surface.GetTextureID( "gui/faceposer_indicator" )
|
|
|
|
-- Draw a box indicating the face we have selected
|
|
function TOOL:DrawHUD()
|
|
|
|
local selected = self:GetSelectedEntity()
|
|
if ( !IsValid( selected ) ) then return end
|
|
|
|
local eyeattachment = selected:LookupAttachment( "eyes" )
|
|
if ( eyeattachment == 0 ) then return end
|
|
|
|
local attachment = selected:GetAttachment( eyeattachment )
|
|
local scrpos = attachment.Pos:ToScreen()
|
|
if ( !scrpos.visible ) then return end
|
|
|
|
if ( self:GetOperation() == 1 ) then
|
|
|
|
-- Get Target
|
|
local trace = self:GetOwner():GetEyeTrace()
|
|
|
|
-- Clientside preview
|
|
local LocalPos = ConvertRelativeToEyesAttachment( selected, trace.HitPos )
|
|
if ( LocalPos ) then
|
|
selected:SetEyeTarget( LocalPos )
|
|
end
|
|
|
|
-- Try to get each eye position.. this is a real guess and won't work on non-humans
|
|
local Leye = ( attachment.Pos + attachment.Ang:Right() * 1.5 ):ToScreen()
|
|
local Reye = ( attachment.Pos - attachment.Ang:Right() * 1.5 ):ToScreen()
|
|
|
|
-- Todo, make the line look less like ass
|
|
local scrhit = trace.HitPos:ToScreen()
|
|
local x = scrhit.x
|
|
local y = scrhit.y
|
|
|
|
surface.SetDrawColor( 0, 0, 0, 100 )
|
|
surface.DrawLine( Leye.x - 1, Leye.y + 1, x - 1, y + 1 )
|
|
surface.DrawLine( Leye.x - 1, Leye.y - 1, x - 1, y - 1 )
|
|
surface.DrawLine( Leye.x + 1, Leye.y + 1, x + 1, y + 1 )
|
|
surface.DrawLine( Leye.x + 1, Leye.y - 1, x + 1, y - 1 )
|
|
surface.DrawLine( Reye.x - 1, Reye.y + 1, x - 1, y + 1 )
|
|
surface.DrawLine( Reye.x - 1, Reye.y - 1, x - 1, y - 1 )
|
|
surface.DrawLine( Reye.x + 1, Reye.y + 1, x + 1, y + 1 )
|
|
surface.DrawLine( Reye.x + 1, Reye.y - 1, x + 1, y - 1 )
|
|
|
|
surface.SetDrawColor( 0, 255, 0, 255 )
|
|
surface.DrawLine( Leye.x, Leye.y, x, y )
|
|
surface.DrawLine( Leye.x, Leye.y - 1, x, y - 1 )
|
|
surface.DrawLine( Reye.x, Reye.y, x, y )
|
|
surface.DrawLine( Reye.x, Reye.y - 1, x, y - 1 )
|
|
|
|
end
|
|
|
|
if ( self:GetOperation() == 2 ) then
|
|
|
|
-- Clientside preview
|
|
--selected:SetEyeTarget( self:CalculateEyeTarget() )
|
|
|
|
-- Work out the side distance to give a rough headsize box..
|
|
local player_eyes = LocalPlayer():EyeAngles()
|
|
local side = ( attachment.Pos + player_eyes:Right() * 20 ):ToScreen()
|
|
local size = math.abs( side.x - scrpos.x )
|
|
|
|
-- Draw the selection ring
|
|
surface.SetDrawColor( 255, 255, 255, 255 )
|
|
surface.SetTexture( SelectionRing )
|
|
surface.DrawTexturedRect( scrpos.x - size, scrpos.y - size, size * 2, size * 2 )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function TOOL.BuildCPanel( CPanel, hasEntity )
|
|
|
|
CPanel:AddControl( "Header", { Description = "#tool.eyeposer.desc" } )
|
|
|
|
if ( hasEntity ) then
|
|
|
|
-- Panel for Slider ( limiting edge )
|
|
local SliderBackground = vgui.Create( "DPanel", CPanel )
|
|
SliderBackground:Dock( TOP )
|
|
SliderBackground:SetTall( 225 )
|
|
CPanel:AddItem( SliderBackground )
|
|
|
|
-- 2 axis slider for the eye position
|
|
local EyeSlider = vgui.Create( "DSlider", SliderBackground )
|
|
EyeSlider:Dock( FILL )
|
|
EyeSlider:SetLockY()
|
|
EyeSlider:SetSlideX( 0.5 )
|
|
EyeSlider:SetSlideY( 0.5 )
|
|
EyeSlider:SetTrapInside( true )
|
|
EyeSlider:SetConVarX( "eyeposer_x" )
|
|
EyeSlider:SetConVarY( "eyeposer_y" )
|
|
-- Draw the 'button' different from the slider
|
|
EyeSlider.Knob.Paint = function( panel, w, h ) derma.SkinHook( "Paint", "Button", panel, w, h ) end
|
|
|
|
function EyeSlider:Paint( w, h )
|
|
local knobX, knobY = self.Knob:GetPos()
|
|
local knobW, knobH = self.Knob:GetSize()
|
|
surface.SetDrawColor( 0, 0, 0, 250 )
|
|
surface.DrawLine( knobX + knobW / 2, knobY + knobH / 2, w / 2, h / 2 )
|
|
surface.DrawRect( w / 2 - 2, h / 2 - 2, 5, 5 )
|
|
end
|
|
|
|
CPanel:AddControl( "Slider", { Label = "#tool.eyeposer.strabismus", Command = "eyeposer_strabismus", Type = "Float", Min = -1, Max = 1, Default = 0 } )
|
|
|
|
end
|
|
|
|
CPanel:AddControl( "Slider", { Label = "#tool.eyeposer.size_eyes", Command = "r_eyesize", Type = "Float", Min = -0.5, Max = 2, Help = true, Default = 0 } )
|
|
|
|
end
|