Files
wnsrc/lua/entities/prop_animatable.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

272 lines
7.3 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.Base = "base_entity"
ENT.Type = "anim"
ENT.WantsTranslucency = true -- For the outline
ENT.AutomaticFrameAdvance = true
function ENT:SetupDataTables()
self:NetworkVar( "Bool", 0, "IsRagdoll" )
self:NetworkVar( "Bool", 1, "AnimateBodyXY" )
self:NetworkVar( "Bool", 2, "BecomeRagdoll" )
self:NetworkVar( "Bool", 3, "HideBBox" )
if ( CLIENT ) then return end
self:SetIsRagdoll( false )
self:SetAnimateBodyXY( false )
self:SetBecomeRagdoll( false )
end
if ( SERVER ) then
function ENT:SetPlayer( ply )
-- Name compatible with base Sandbox function of the same name
self.Founder = ply
end
function ENT:Initialize()
-- This is a silly way to check if the model has a physics mesh or not
self:PhysicsInit( SOLID_VPHYSICS )
-- We got no physics? Do some fake shit
if ( !IsValid( self:GetPhysicsObject() ) ) then
local mins, maxs = self:OBBMins(), self:OBBMaxs()
self:SetCollisionBounds( mins, maxs )
self:SetSolid( SOLID_BBOX )
end
self:PhysicsDestroy()
self:SetMoveType( MOVETYPE_NONE )
end
function ENT:FixRagdoll()
local mins, maxs = self:OBBMins(), self:OBBMaxs()
-- Just in case
self.OriginalCollisions = mins
self.OriginalCollisionsMax = maxs
-- Fix some NPC ragdolls flying above ground
mins.z = 0
self:SetCollisionBounds( mins, maxs )
self:SetSolid( SOLID_BBOX )
-- Used to determine if this animatable prop should have the "Turn into Ragdoll" option.
self:SetIsRagdoll( true )
end
function ENT:PreEntityCopy()
self.DuplicatorSavedSequence = self:GetSequence()
self.DuplicatorSavedSequenceName = self:GetSequenceName( self:GetSequence() )
self.DuplicatorSavedCycle = self:GetCycle()
self.DuplicatorSavedPlaybackRate = self:GetPlaybackRate()
self.PoseParameters = {}
for k = 0, self:GetNumPoseParameters() - 1 do
local name = self:GetPoseParameterName( k )
self.PoseParameters[ name ] = self:GetPoseParameter( name )
end
end
function ENT:PostEntityPaste()
if ( self:GetIsRagdoll() ) then self:FixRagdoll() end
if ( !self.DuplicatorSavedSequence ) then return end
if ( self.DuplicatorSavedSequence != self:LookupSequence( self.DuplicatorSavedSequenceName ) ) then
print( "Something went wrong with restoring sequence for animatable prop!" )
self.DuplicatorSavedSequence = self:LookupSequence( self.DuplicatorSavedSequenceName )
end
self:ResetSequence( self.DuplicatorSavedSequence )
self:SetCycle( self.DuplicatorSavedCycle )
self:SetPlaybackRate( self.DuplicatorSavedPlaybackRate )
if ( self.PoseParameters ) then
for name, value in pairs( self.PoseParameters ) do
self:SetPoseParameter( name, value )
end
end
end
function ENT:OnTakeDamage( dmg )
if ( !self:GetBecomeRagdoll() ) then return end
if ( util.IsValidRagdoll( self:GetModel() ) ) then
self:BecomeRagdollLua( dmg:GetDamageForce(), dmg:GetDamagePosition() )
else
self:GibBreakClient( dmg:GetDamageForce() )
self:Remove()
end
end
end
function ENT:BecomeRagdollLua( force, forcePos )
local ent = self
local ragdoll = ents.Create( "prop_ragdoll" )
ragdoll:SetModel( ent:GetModel() )
ragdoll:SetPos( ent:GetPos() )
ragdoll:SetAngles( ent:GetAngles() )
ragdoll:SetSkin( ent:GetSkin() )
ragdoll:SetFlexScale( ent:GetFlexScale() )
for i = 0, ent:GetNumBodyGroups() - 1 do ragdoll:SetBodygroup( i, ent:GetBodygroup( i ) ) end
for i = 0, ent:GetFlexNum() - 1 do ragdoll:SetFlexWeight( i, ent:GetFlexWeight( i ) ) end
for i = 0, ent:GetBoneCount() do
ragdoll:ManipulateBoneScale( i, ent:GetManipulateBoneScale( i ) )
ragdoll:ManipulateBoneAngles( i, ent:GetManipulateBoneAngles( i ) )
ragdoll:ManipulateBonePosition( i, ent:GetManipulateBonePosition( i ) )
ragdoll:ManipulateBoneJiggle( i, ent:GetManipulateBoneJiggle( i ) ) -- Even though we don't know what this does, I am still putting this here.
end
ragdoll:Spawn()
ragdoll:Activate()
if ( IsValid( self.Founder ) ) then
--self.Founder:AddCount( "ragdolls", ragdoll
gamemode.Call( "PlayerSpawnedRagdoll", self.Founder, ragdoll:GetModel(), ragdoll )
self.Founder:AddCleanup( "ragdolls", ragdoll )
end
ragdoll.EntityMods = ent.EntityMods
ragdoll.BoneMods = ent.BoneMods
duplicator.ApplyEntityModifiers( nil, ragdoll )
duplicator.ApplyBoneModifiers( nil, ragdoll )
for i = 0, ragdoll:GetPhysicsObjectCount() - 1 do
local bone = ragdoll:GetPhysicsObjectNum( i )
if ( IsValid( bone ) ) then
local pos, ang = ent:GetBonePosition( ragdoll:TranslatePhysBoneToBone( i ) )
if ( pos ) then bone:SetPos( pos ) end
if ( ang ) then bone:SetAngles( ang ) end
if ( !force ) then
bone:EnableMotion( false )
else
bone:ApplyForceOffset( force / ragdoll:GetPhysicsObjectCount(), forcePos )
end
end
end
undo.ReplaceEntity( ent, ragdoll )
cleanup.ReplaceEntity( ent, ragdoll )
constraint.RemoveAll( ent ) -- Remove all constraints ( this stops ropes from hanging around )
ent:Remove()
end
function ENT:Think()
-- Clientside only because Velocity is 0 on server
if ( self:GetAnimateBodyXY() and CLIENT ) then
local velocity = self:GetVelocity()
velocity.z = 0
local vecCurrentMoveYaw = Vector( velocity:GetNormalized():Dot( self:GetForward() ), velocity:GetNormalized():Dot( self:GetRight() ) )
local flInvScale = math.max( math.abs( vecCurrentMoveYaw.x ), math.abs( vecCurrentMoveYaw.y ) );
if ( flInvScale != 0.0 ) then
vecCurrentMoveYaw.x = vecCurrentMoveYaw.x / flInvScale;
vecCurrentMoveYaw.y = vecCurrentMoveYaw.y / flInvScale;
end
self:SetPoseParameter( "move_x", vecCurrentMoveYaw.x )
self:SetPoseParameter( "move_y", vecCurrentMoveYaw.y )
local maxSpeed = self:GetSequenceGroundSpeed( self:GetSequence() )
if ( maxSpeed > velocity:Length() ) then
vecCurrentMoveYaw.x = vecCurrentMoveYaw.x * ( velocity:Length() / maxSpeed )
vecCurrentMoveYaw.y = vecCurrentMoveYaw.y * ( velocity:Length() / maxSpeed )
end
self:SetPoseParameter( "move_x", vecCurrentMoveYaw.x )
self:SetPoseParameter( "move_y", vecCurrentMoveYaw.y )
-- This has to be on server to function :(
--[[local scale = velocity:Length() / maxSpeed
if ( maxSpeed != 0 ) then
self:SetPlaybackRate( scale )
end]]
end
if ( SERVER ) then
-- Ugly hack because no replicated cvars for Lua :(
self:SetHideBBox( GetConVarNumber( "rb655_easy_animation_nobbox_sv" ) > 0 )
end
-- Ensure the animation plays smoothly
self:NextThink( CurTime() )
return true
end
if ( SERVER ) then return end
function ENT:DrawBBox()
if ( GetConVarNumber( "rb655_easy_animation_noglow" ) != 0 or self:GetHideBBox() ) then return end
local wep = LocalPlayer():GetActiveWeapon()
if ( !IsValid( wep ) or wep:GetClass() != "gmod_tool" and wep:GetClass() != "weapon_physgun" ) then
return
end
local mins = self:OBBMins()
local maxs = self:OBBMaxs()
if ( self:GetSolid() == SOLID_BBOX ) then
render.DrawWireframeBox( self:GetPos(), angle_zero, mins, maxs )
else
render.DrawWireframeBox( self:GetPos(), self:GetAngles(), mins, maxs )
end
end
function ENT:Draw( flags )
self:DrawBBox()
-- This probably shouldn't run every frame..
self:SetRenderBounds( self:GetModelBounds() )
self:DrawModel( flags )
end
function ENT:DrawTranslucent( flags )
self:Draw( flags )
end