TOOL.Category = "Poser" TOOL.Name = "#Face Poser" TOOL.Command = nil TOOL.ConfigName = "" //local EYE_END = 11 local gLastFacePoseEntity = NULL TOOL.FaceTimer = 0 local function IsUselessFaceFlex( strName ) if ( strName == "gesture_rightleft" ) then return true end if ( strName == "gesture_updown" ) then return true end if ( strName == "head_forwardback" ) then return true end if ( strName == "chest_rightleft" ) then return true end if ( strName == "body_rightleft" ) then return true end if ( strName == "eyes_rightleft" ) then return true end if ( strName == "eyes_updown" ) then return true end if ( strName == "head_tilt" ) then return true end if ( strName == "head_updown" ) then return true end if ( strName == "head_rightleft" ) then return true end return false end /*--------------------------------------------------------- ---------------------------------------------------------*/ function TOOL:FacePoserEntity() return self:GetWeapon():GetNetworkedEntity( 1 ) end /*--------------------------------------------------------- ---------------------------------------------------------*/ function TOOL:SetFacePoserEntity( ent ) return self:GetWeapon():SetNetworkedEntity( 1, ent ) end /*--------------------------------------------------------- ---------------------------------------------------------*/ function TOOL:Think() // If we're on the client just make sure the context menu is up to date if (CLIENT) then if ( self:FacePoserEntity() == gLastFacePoseEntity ) then return end gLastFacePoseEntity = self:FacePoserEntity(); self:UpdateFaceControlPanel(); return end // On the server we continually set the flex weights if (self.FaceTimer > CurTime() ) then return end local ent = self:FacePoserEntity() if ( !ValidEntity( ent ) ) then return end local FlexNum = ent:GetFlexNum() - 1 if (FlexNum <= 0) then return end for i=0, FlexNum-1 do local Name = ent:GetFlexName( i ) if ( IsUselessFaceFlex(Name ) ) then ent:SetFlexWeight( i, 0 ) else local num = self:GetClientNumber( "flex"..i ) ent:SetFlexWeight( i, num ) end end local num = self:GetClientNumber( "scale" ) ent:SetFlexScale( num ) end /*--------------------------------------------------------- Alt fire sucks the facepose from the model's face ---------------------------------------------------------*/ function TOOL:RightClick( trace ) if ( SERVER ) then self:SetFacePoserEntity( trace.Entity ) end if ( trace.Entity == NULL ) then return end if ( trace.Entity:GetFlexNum() == 0 ) then return end local ent = trace.Entity local FlexNum = ent:GetFlexNum() if ( SERVER ) then // This stops it applying the current sliders to the newly selected face.. // it should probably be linked to the ping somehow.. but 1 second seems pretty safe self.FaceTimer = CurTime() + 1 // In multiplayer the rest is only done on the client to save bandwidth. // We can't do that in single player because these functions don't get called on the client if ( !SinglePlayer() ) then return end end for i=0, FlexNum-1 do local Weight = '0.0' if ( i <= FlexNum ) then Weight = ent:GetFlexWeight( i ) end self:GetOwner():ConCommand( "faceposer_flex"..i.." " .. Weight ) end self:GetOwner():ConCommand( "faceposer_scale "..ent:GetFlexScale() ) end if ( SERVER ) then /*--------------------------------------------------------- Just select as the current object - Current settings will get applied ---------------------------------------------------------*/ function TOOL:LeftClick( trace ) if ( trace.Entity == NULL ) then return end if ( trace.Entity:GetFlexNum() == 0 ) then return end self.FaceTimer = 0; self:SetFacePoserEntity( trace.Entity ) end function CC_Face_Randomize( pl, command, arguments ) for i=0, 64 do local num = math.Rand( 0, 1 ) pl:ConCommand( "faceposer_flex"..i.." " .. string.format( "%.3f", num ) ) end end concommand.Add( "faceposer_randomize", CC_Face_Randomize ) end if ( CLIENT ) then for i=0,64 do TOOL.ClientConVar[ "flex"..i ] = "0" end TOOL.ClientConVar[ "scale" ] = "1.0" /*--------------------------------------------------------- Updates the spawn menu panel ---------------------------------------------------------*/ function TOOL:UpdateFaceControlPanel( index ) local CPanel = GetControlPanel( "faceposer" ) if ( !CPanel ) then Msg("Couldn't find faceposer panel!\n") return end CPanel:ClearControls() self.BuildCPanel( CPanel, self:FacePoserEntity() ) end /*--------------------------------------------------------- Updates the Control Panel ---------------------------------------------------------*/ function TOOL.BuildCPanel( CPanel, FaceEntity ) if ( !ValidEntity( FaceEntity ) ) then // Maybe add some help` return end local Presets = vgui.Create( "ControlPresets", CPanel ) Presets:SetPreset( "face" ) for i=0, 64 do Presets:AddConVar( "faceposer_flex"..i ) end CPanel:AddItem( Presets ) local QuickFace = vgui.Create( "MatSelect", CPanel ) QuickFace:SetNumRows( 3 ) QuickFace:SetItemWidth( 64 ) QuickFace:SetItemHeight( 32 ) // Todo: These really need to be the name of the flex. local Clear = {} for i=0, 64 do Clear[ "faceposer_flex"..i ] = 0 end QuickFace:AddMaterialEx( "Clear", "vgui/face/clear", nil, Clear ) QuickFace:AddMaterialEx( "Open Eyes", "vgui/face/open_eyes", nil, { faceposer_flex0 = "1", faceposer_flex1 = "1", faceposer_flex2 = "0", faceposer_flex3 = "0", faceposer_flex4 = "0", faceposer_flex5 = "0", faceposer_flex6 = "0", faceposer_flex7 = "0", faceposer_flex8 = "0", faceposer_flex9 = "0"} ) QuickFace:AddMaterialEx( "Close Eyes", "vgui/face/close_eyes", nil, { faceposer_flex0 = "0", faceposer_flex1 = "0", faceposer_flex2 = "1", faceposer_flex3 = "1", faceposer_flex4 = "1", faceposer_flex5 = "1", faceposer_flex6 = "1", faceposer_flex7 = "1", faceposer_flex8 = "1", faceposer_flex9 = "1"} ) QuickFace:AddMaterialEx( "Angry Eyebrows", "vgui/face/angry_eyebrows", nil, { faceposer_flex10 = "0", faceposer_flex11 = "0", faceposer_flex12 = "1", faceposer_flex13 = "1", faceposer_flex14 = "0.5", faceposer_flex15 = "0.5"} ) QuickFace:AddMaterialEx( "Normal Eyebrows", "vgui/face/normal_eyebrows", nil, { faceposer_flex10 = "0", faceposer_flex11 = "0", faceposer_flex12 = "0", faceposer_flex13 = "0", faceposer_flex14 = "0", faceposer_flex15 = "0" }) QuickFace:AddMaterialEx( "Sorry Eyebrows", "vgui/face/sorry_eyebrows", nil, { faceposer_flex10 = "1", faceposer_flex11 = "1", faceposer_flex12 = "0", faceposer_flex13 = "0", faceposer_flex14 = "0", faceposer_flex15 = "0" }) QuickFace:AddMaterialEx( "Grin", "vgui/face/grin", nil, { faceposer_flex20 = "1", faceposer_flex21 = "1", faceposer_flex22 = "1", faceposer_flex23 = "1", faceposer_flex24 = "0", faceposer_flex25 = "0", faceposer_flex26 = "0", faceposer_flex27 = "1", faceposer_flex28 = "1", faceposer_flex29 = "0", faceposer_flex30 = "0", faceposer_flex31 = "0", faceposer_flex32 = "0", faceposer_flex33 = "1", faceposer_flex34 = "1", faceposer_flex35 = "0", faceposer_flex36 = "0", faceposer_flex37 = "0", faceposer_flex38 = "0", faceposer_flex39 = "1", faceposer_flex40 = "0", faceposer_flex41 = "0", faceposer_flex42 = "1", faceposer_flex43 = "1" }) QuickFace:AddMaterialEx( "Sad", "vgui/face/sad", nil, { faceposer_flex20 = "0", faceposer_flex21 = "0", faceposer_flex22 = "0", faceposer_flex23 = "0", faceposer_flex24 = "1", faceposer_flex25 = "1", faceposer_flex26 = "0.0", faceposer_flex27 = "0", faceposer_flex28 = "0", faceposer_flex29 = "0", faceposer_flex30 = "0", faceposer_flex31 = "0", faceposer_flex32 = "0", faceposer_flex33 = "0", faceposer_flex34 = "0", faceposer_flex35 = "0", faceposer_flex36 = "0", faceposer_flex37 = "0", faceposer_flex38 = "0.5", faceposer_flex39 = "0", faceposer_flex40 = "0", faceposer_flex41 = "0", faceposer_flex42 = "0", faceposer_flex43 = "0" }) QuickFace:AddMaterialEx( "Smile", "vgui/face/smile", nil, { faceposer_flex20 = "1", faceposer_flex21 = "1", faceposer_flex22 = "1", faceposer_flex23 = "1", faceposer_flex24 = "0", faceposer_flex25 = "0", faceposer_flex26 = "0", faceposer_flex27 = "0.6", faceposer_flex28 = "0.4", faceposer_flex29 = "0", faceposer_flex30 = "0", faceposer_flex31 = "0", faceposer_flex32 = "0", faceposer_flex33 = "1", faceposer_flex34 = "1", faceposer_flex35 = "0", faceposer_flex36 = "0", faceposer_flex37 = "0", faceposer_flex38 = "0", faceposer_flex39 = "0", faceposer_flex40 = "1", faceposer_flex41 = "1", faceposer_flex42 = "0", faceposer_flex43 = "0", faceposer_flex44 = "0", }) CPanel:AddItem( QuickFace ) local FlexNum = FaceEntity:GetFlexNum() local params = {} params.Label = "#FacePoser_scale" params.Type = "Float" params.Min = "-1" params.Max = "20" params.Command = "faceposer_scale" CPanel:AddControl( "Slider", params ) local params = {} params.Text = "#FacePoser_randomize" params.Command = "faceposer_randomize" CPanel:AddControl( "Button", params ) for i=0, FlexNum-1 do local Name = FaceEntity:GetFlexName( i ) if ( !IsUselessFaceFlex(Name ) ) then local params = {} params.Label = "#" .. Name params.Type = "Float" params.Min, params.Max = 0, 1 params.Command = "faceposer_flex"..i CPanel:AddControl( "Slider", params ) end end end local FacePoser = surface.GetTextureID( "gui/faceposer_indicator" ) /*--------------------------------------------------------- Draw a box indicating the face we have selected ---------------------------------------------------------*/ function TOOL:DrawHUD() local selected = self:FacePoserEntity() if ( !ValidEntity( selected ) ) then return end if ( selected:IsWorld() ) then return end local vEyePos = selected:EyePos() 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 // 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 ) surface.SetDrawColor( 255, 255, 255, 255 ) surface.SetTexture( FacePoser ) surface.DrawTexturedRect( scrpos.x-size, scrpos.y-size, size*2, size*2 ) end end