mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
318 lines
6.6 KiB
Lua
318 lines
6.6 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/
|
|
--]]
|
|
|
|
|
|
AddCSLuaFile()
|
|
|
|
ENT.Type = "anim"
|
|
ENT.Spawnable = false
|
|
ENT.AdminOnly = false
|
|
ENT.Editable = true
|
|
|
|
function ENT:SetupDataTables()
|
|
|
|
--
|
|
-- Scale - how far the ragdoll will move in the game world in relation to how far it moved in the real world
|
|
--
|
|
self:NetworkVar( "Float", 0, "Scale", { KeyName = "scale", Edit = { type = "Float", min = 1, max = 512, order = 1 } } )
|
|
|
|
--
|
|
-- Normalize - if enabled the limbs aren't stretched
|
|
--
|
|
self:NetworkVar( "Bool", 0, "Normalize", { KeyName = "normalize", Edit = { type = "Boolean", order = 2 } } )
|
|
|
|
--
|
|
-- Debug - Shows some debug info - only available on a listen server
|
|
--
|
|
self:NetworkVar( "Bool", 1, "Debug", { KeyName = "debug", Edit = { type = "Boolean", order = 100 } } )
|
|
|
|
--
|
|
-- Controller - the entity that is currently controlling the ragdoll
|
|
--
|
|
self:NetworkVar( "Entity", 0, "Controller" )
|
|
self:NetworkVar( "Entity", 1, "Target" )
|
|
|
|
--
|
|
-- Defaults
|
|
--
|
|
if ( SERVER ) then
|
|
|
|
self:SetScale( 36 )
|
|
self:SetDebug( false )
|
|
self:SetNormalize( true )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:Initialize()
|
|
|
|
if ( SERVER ) then
|
|
|
|
self:SetModel( "models/maxofs2d/motion_sensor.mdl" )
|
|
self:PhysicsInit( SOLID_VPHYSICS )
|
|
|
|
-- Don't collide with the player
|
|
self:SetCollisionGroup( COLLISION_GROUP_WEAPON )
|
|
|
|
self:DrawShadow( false )
|
|
|
|
local phys = self:GetPhysicsObject()
|
|
if ( IsValid( phys ) ) then
|
|
phys:Wake()
|
|
phys:EnableGravity( false )
|
|
phys:EnableDrag( false )
|
|
end
|
|
|
|
local colors = {
|
|
Color( 180, 255, 50 ),
|
|
Color( 0, 150, 255 ),
|
|
Color( 255, 255, 0 ),
|
|
Color( 255, 50, 255 )
|
|
}
|
|
|
|
self:SetColor( table.Random( colors ) )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--
|
|
-- We don't want to move unless the player moves us or we're constrained to something.
|
|
--
|
|
function ENT:PhysicsUpdate( physobj )
|
|
|
|
if ( self:IsPlayerHolding() ) then return end
|
|
if ( self:IsConstrained() ) then return end
|
|
|
|
physobj:SetVelocity( vector_origin )
|
|
physobj:Sleep()
|
|
|
|
end
|
|
|
|
--
|
|
-- Clean up on remove
|
|
--
|
|
function ENT:OnRemove()
|
|
|
|
if ( SERVER ) then
|
|
|
|
local ragdoll = self:GetTarget()
|
|
if ( IsValid( ragdoll ) ) then
|
|
ragdoll:SetRagdollBuildFunction( nil )
|
|
|
|
if ( IsValid( ragdoll.MotionSensorController ) && ragdoll.MotionSensorController == self ) then
|
|
ragdoll.MotionSensorController = nil
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:Draw()
|
|
|
|
--
|
|
-- Don't draw if we're holding the camera
|
|
--
|
|
local ply = LocalPlayer()
|
|
local wep = ply:GetActiveWeapon()
|
|
if ( IsValid( wep ) && wep:GetClass() == "gmod_camera" ) then
|
|
return
|
|
end
|
|
|
|
self:DrawModel()
|
|
|
|
end
|
|
|
|
function ENT:DrawDebug( ragdoll, controller, pos, ang, rotation, scale, center, changed_sensor )
|
|
|
|
local UpdateTime = 0.1
|
|
local StayTime = 0.15
|
|
|
|
if ( self.LastDebugUpdate && CurTime() - self.LastDebugUpdate < UpdateTime ) then return end
|
|
|
|
self.LastDebugUpdate = CurTime()
|
|
|
|
center = center
|
|
|
|
local col_bone = color_white
|
|
local col_point = Color( 255, 0, 0, 255 )
|
|
local col_tran_bn = Color( 0, 255, 0, 255 )
|
|
|
|
local realbonepos = {}
|
|
local fixedbonepos = {}
|
|
local min = Vector( 1, 1, 1 ) * -0.5
|
|
local max = Vector( 1, 1, 1 ) * 0.5
|
|
|
|
--
|
|
-- Draw Points
|
|
--
|
|
for i = 0, 19 do
|
|
|
|
realbonepos[i] = controller:MotionSensorPos( i ) * scale
|
|
realbonepos[i]:Rotate( rotation )
|
|
realbonepos[i] = realbonepos[i] + center
|
|
|
|
fixedbonepos[i] = changed_sensor[ i ] * scale
|
|
-- (already rotated)
|
|
fixedbonepos[i] = fixedbonepos[i] + center
|
|
|
|
debugoverlay.Box( realbonepos[i], min, max, StayTime, col_point )
|
|
debugoverlay.Box( fixedbonepos[i], min, max, StayTime, col_tran_bn )
|
|
|
|
end
|
|
|
|
--
|
|
-- Draw bones
|
|
--
|
|
for k, v in ipairs( motionsensor.DebugBones ) do
|
|
|
|
debugoverlay.Line( realbonepos[ v[1] ], realbonepos[ v[2] ], StayTime, col_bone, true )
|
|
|
|
end
|
|
|
|
--
|
|
-- Draw translated sensor bones
|
|
--
|
|
for k, v in ipairs( motionsensor.DebugBones ) do
|
|
|
|
debugoverlay.Line( fixedbonepos[ v[1] ], fixedbonepos[ v[2] ], StayTime, col_tran_bn, true )
|
|
|
|
end
|
|
|
|
--
|
|
-- Draw ragdoll physics bones
|
|
--
|
|
for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do
|
|
|
|
local phys = ragdoll:GetPhysicsObjectNum( i )
|
|
|
|
local position = phys:GetPos()
|
|
local angle = phys:GetAngles()
|
|
local txt = tostring( i )
|
|
|
|
if ( ang[i] == nil ) then
|
|
txt = i .. " (UNSET)"
|
|
end
|
|
|
|
debugoverlay.Text( position, txt, StayTime )
|
|
debugoverlay.Axis( position, angle, 5, StayTime, true )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
function ENT:SetRagdoll( ragdoll )
|
|
|
|
ragdoll.MotionSensorController = self
|
|
|
|
self:SetTarget( ragdoll )
|
|
ragdoll:PhysWake()
|
|
|
|
local buildername = motionsensor.ChooseBuilderFromEntity( ragdoll )
|
|
|
|
--
|
|
-- Set the ragdoll build function.
|
|
-- This function is called whenever the ragdoll bones are built.
|
|
-- in this function is the one place you can successfully call ent:SetRagdollBone
|
|
--
|
|
ragdoll:SetRagdollBuildFunction( function( ragdoll )
|
|
|
|
local controller = self:GetController()
|
|
if ( !IsValid( controller ) ) then return end
|
|
|
|
local builder = list.Get( "SkeletonConvertor" )[ buildername ]
|
|
local scale = self:GetScale()
|
|
local rotation = self:GetAngles()
|
|
local center = self:GetPos()
|
|
local normalize = self:GetNormalize()
|
|
local debug = self:GetDebug()
|
|
|
|
--
|
|
-- Call the build skeleton function.
|
|
-- This is thrown out to a pseudo class because we want to be
|
|
-- able to add new skeleton types nice and easily.
|
|
--
|
|
local pos, ang, changed_sensor = motionsensor.BuildSkeleton( builder, controller, rotation )
|
|
|
|
--
|
|
-- For development
|
|
--
|
|
if ( debug ) then
|
|
self:DrawDebug( ragdoll, controller, pos, ang, rotation, scale, center, changed_sensor )
|
|
end
|
|
|
|
--
|
|
-- If we don't have 85% of the points, just drop dead
|
|
--
|
|
local iSkipped = 0
|
|
local iMaxSkip = table.Count( pos ) * 0.25
|
|
for k, v in pairs( pos ) do
|
|
|
|
if ( math.abs( v.x ) > 0.05 ) then continue end
|
|
if ( math.abs( v.y ) > 0.05 ) then continue end
|
|
|
|
pos[k] = nil -- don't use this point to control the ragdoll
|
|
ang[k] = nil -- (use the ragdoll point)
|
|
|
|
iSkipped = iSkipped + 1
|
|
|
|
if ( iSkipped > iMaxSkip ) then
|
|
|
|
ragdoll:RagdollStopControlling()
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--
|
|
-- Loop each returned position
|
|
--
|
|
for k, v in pairs( pos ) do
|
|
|
|
--
|
|
-- Set the bone angle
|
|
--
|
|
if ( ang[ k ] != nil ) then
|
|
ragdoll:SetRagdollAng( k, ang[ k ] )
|
|
end
|
|
|
|
--
|
|
-- The root bone, we directly set the position of this one.
|
|
--
|
|
if ( k == 0 || !normalize ) then
|
|
|
|
local new_position = center + v * scale
|
|
ragdoll:SetRagdollPos( k, new_position )
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--
|
|
-- Normalize the ragdoll
|
|
--
|
|
if ( normalize ) then
|
|
|
|
ragdoll:RagdollSolve()
|
|
|
|
end
|
|
|
|
--
|
|
-- Makes the physics objects follow the set bone positions
|
|
--
|
|
ragdoll:RagdollUpdatePhysics()
|
|
|
|
end )
|
|
|
|
end
|