Files
wnsrc/gamemodes/base/entities/entities/ragdoll_motion.lua
lifestorm c6d9b6f580 Upload
2024-08-05 18:40:29 +03:00

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