mirror of
https://github.com/Winded/RagdollMover.git
synced 2025-03-04 03:13:36 -05:00
Ragdoll mover update (#4)
* Ragdoll mover edit from workshop by Le Hot Doge * Initial pass, some changes and tweaks for Doge's edit to not throw errors and a bit of formatting * Added angle showing thing when rotating entities * Added ability to manipulate non physical bones (like fingers), option to disable entity filter to select any entity (like cameras or lights) * Streamlined the bone selection process. Fixed bug with pressing the R key * Update 2 - Fixed error that happened when first using ragoll mover in the map, fixed some weird models causing tool to break, added ability to select effect prop's effect, added new option to disable children physics bones moving with the parent, made it so only bonelist tab updated when changing selected entity * Tweaks to the gizmos - Rotation gizmo now will not have the issue of rotating stuff in the opposite direction for non physical bones, Plane movement stuffs now work for non physical bones, also effect's root bone gizmos will set its movement angles to be that of effect's base prop * Made it so gizmos will track yaw of non physical bones, as it seems to move other angle stuff with it * Tweak to make bones on prop_physics selectable * Reverted gizmos to track all rotations of the non physical bones. Those are very weird * Fixed that minor lua error that was happening if you try first using the tool and had manual bone picking enabled
This commit is contained in:
parent
c5971644d8
commit
091553465c
@ -1,3 +1,4 @@
|
||||
Ragdoll Mover v1
|
||||
Ragdoll Mover v1 edit
|
||||
================
|
||||
This is the first version of Ragdoll Mover; the one that's already released.
|
||||
This is the edit of first version of Ragdoll Mover;
|
||||
You can help the development by testing it and providing feedback.
|
@ -212,15 +212,51 @@ function GetOffsetTable(tool,ent,rotate)
|
||||
CreateDefaultIKs(tool,ent)
|
||||
end
|
||||
|
||||
RTable[0] = {}
|
||||
RTable[0].pos = ent:GetPhysicsObjectNum(0):GetPos()
|
||||
RTable[0].ang = ent:GetPhysicsObjectNum(0):GetAngles()
|
||||
RTable[0].moving = ent:GetPhysicsObjectNum(0):IsMoveable()
|
||||
local bonestart
|
||||
--------------------------------------------------------- gotta sort out the bones in case if there are genius sfm to gmod ports with roottransform as 0 bone, like wtf
|
||||
for a = 0, ent:GetBoneCount() - 1 do
|
||||
local phys;
|
||||
local IsPhysBone = false;
|
||||
|
||||
for i = 0, ent:GetPhysicsObjectCount() - 1 do
|
||||
local b = ent:TranslatePhysBoneToBone(i)
|
||||
if a == b then
|
||||
phys = i
|
||||
end
|
||||
end
|
||||
|
||||
local count = ent:GetPhysicsObjectCount()
|
||||
|
||||
if count == 0 then
|
||||
phys = -1
|
||||
elseif count == 1 then
|
||||
phys = 0
|
||||
IsPhysBone = true;
|
||||
end
|
||||
|
||||
if phys and 0 <= phys and count > phys then
|
||||
if ent:GetPhysicsObjectNum(phys) then
|
||||
IsPhysBone = true
|
||||
end
|
||||
end
|
||||
--------------------------------------------------------- wait until we get first physics bone, that'll be our parent bone, and not some non physical stuff like roottransform that causes stuff to freak out
|
||||
if IsPhysBone then
|
||||
bonestart = a
|
||||
a = ent:TranslateBoneToPhysBone(a)
|
||||
RTable[a] = {}
|
||||
RTable[a].pos = ent:GetPhysicsObjectNum(a):GetPos()
|
||||
RTable[a].ang = ent:GetPhysicsObjectNum(a):GetAngles()
|
||||
RTable[a].moving = ent:GetPhysicsObjectNum(a):IsMoveable()
|
||||
RTable["FirstBone"] = a
|
||||
RTable["FirstNPHys"] = bonestart
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
for i=1,ent:GetBoneCount()-1 do
|
||||
for i=1+bonestart,ent:GetBoneCount()-1 do
|
||||
local pb = BoneToPhysBone(ent,i)
|
||||
local parent = GetPhysBoneParent(ent,pb)
|
||||
if pb and pb != 0 and parent and !RTable[pb] then
|
||||
if pb and pb != RTable["FirstBone"] and parent and !RTable[pb] then
|
||||
local b = ent:TranslatePhysBoneToBone(pb)
|
||||
local bn = ent:GetBoneName(b)
|
||||
local obj1 = ent:GetPhysicsObjectNum(pb)
|
||||
@ -271,14 +307,17 @@ end
|
||||
|
||||
local function SetBoneOffsets(ent,ostable,sbone)
|
||||
local RTable = {}
|
||||
RTable[0] = {}
|
||||
RTable[0].pos = ostable[0].pos
|
||||
RTable[0].ang = ostable[0].ang
|
||||
if sbone.b == 0 then
|
||||
RTable[0].pos = sbone.p
|
||||
RTable[0].ang = sbone.a
|
||||
local firstbone = ostable["FirstBone"]
|
||||
local firstnphys = ostable["FirstNPHys"]
|
||||
|
||||
RTable[firstbone] = {}
|
||||
RTable[firstbone].pos = ostable[firstbone].pos
|
||||
RTable[firstbone].ang = ostable[firstbone].ang
|
||||
if sbone.b == firstbone then
|
||||
RTable[firstbone].pos = sbone.p
|
||||
RTable[firstbone].ang = sbone.a
|
||||
end
|
||||
for i=1,ent:GetBoneCount()-1 do
|
||||
for i=1 + firstnphys,ent:GetBoneCount()-1 do
|
||||
local pb = BoneToPhysBone(ent,i)
|
||||
if ostable[pb] then
|
||||
local parent = ostable[pb].parent
|
||||
|
@ -81,12 +81,40 @@ hook.Add("PlayerSpawn","rgmSpawn",function(pl)
|
||||
pl.rgm = {};
|
||||
pl.rgmSync = Sync;
|
||||
pl.rgmSyncOne = SyncOne;
|
||||
pl.rgm.ClientSet = false;
|
||||
end
|
||||
end)
|
||||
|
||||
if SERVER then
|
||||
|
||||
util.AddNetworkString("rgmSync");
|
||||
util.AddNetworkString("rgmSyncClient");
|
||||
|
||||
net.Receive("rgmSyncClient", function(len, ply)
|
||||
local pl = ply;
|
||||
if !pl.rgm then pl.rgm = {}; end
|
||||
|
||||
local count = net.ReadInt(32);
|
||||
|
||||
for i=1, count do
|
||||
local name = net.ReadString();
|
||||
|
||||
local type = net.ReadInt(8);
|
||||
local value = nil
|
||||
if type == TYPE_ENTITY then
|
||||
value = net.ReadEntity();
|
||||
elseif type == TYPE_NUMBER then
|
||||
value = net.ReadFloat();
|
||||
elseif type == TYPE_VECTOR then
|
||||
value = net.ReadVector();
|
||||
elseif type == TYPE_ANGLE then
|
||||
value = net.ReadAngle();
|
||||
elseif type == TYPE_BOOL then
|
||||
value = net.ReadBit() == 1;
|
||||
end
|
||||
pl.rgm[name] = value;
|
||||
end
|
||||
end)
|
||||
|
||||
else
|
||||
|
||||
|
@ -53,7 +53,6 @@ end)
|
||||
|
||||
function ENT:DrawLines(scale)
|
||||
local pl = LocalPlayer();
|
||||
if !self.Axises then return end
|
||||
|
||||
local rotate = pl.rgm.Rotate or false;
|
||||
local collision = self:TestCollision(LocalPlayer(),scale)
|
||||
@ -61,6 +60,7 @@ function ENT:DrawLines(scale)
|
||||
local Start,End = 1,6
|
||||
if rotate then Start,End = 7,10 end
|
||||
-- print(self.Axises);
|
||||
if !self.Axises then return end;
|
||||
for i=Start,End do
|
||||
local moveaxis = self.Axises[i];
|
||||
local yellow = false
|
||||
@ -90,6 +90,24 @@ function ENT:DrawDirectionLine(norm,scale,ghost)
|
||||
surface.DrawLine(pos1.x,pos1.y,pos2.x,pos2.y)
|
||||
end
|
||||
|
||||
function ENT:DrawAngleText(axis, hitpos, startAngle)
|
||||
local pos = WorldToLocal(hitpos, Angle(0,0,0), axis:GetPos(), axis:GetAngles())
|
||||
local overnine
|
||||
pos = WorldToLocal(pos, pos:Angle(), Vector(0, 0, 0), startAngle:Angle())
|
||||
|
||||
local localized = Vector(pos.x, pos.z, 0):Angle()
|
||||
|
||||
if(localized.y > 181) then
|
||||
overnine = 360
|
||||
else
|
||||
overnine = 0
|
||||
end
|
||||
|
||||
local textAngle = math.abs(math.Round( (overnine - localized.y) * 100 ) / 100)
|
||||
local textpos = hitpos:ToScreen()
|
||||
draw.SimpleText(textAngle,"HudHintTextLarge",textpos.x + 5,textpos.y,Color(0,200,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM)
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
end
|
||||
function ENT:DrawTranslucent()
|
||||
|
@ -11,7 +11,7 @@ util.AddNetworkString("rgmAxis");
|
||||
util.AddNetworkString("rgmAxisUpdate");
|
||||
|
||||
function ENT:Setup()
|
||||
|
||||
|
||||
//Arrows
|
||||
self.ArrowX = ents.Create("rgm_axis_arrow")
|
||||
self.ArrowX:SetParent(self)
|
||||
@ -19,6 +19,7 @@ function ENT:Setup()
|
||||
self.ArrowX:SetColor(Color(255,0,0,255))
|
||||
self.ArrowX:SetLocalPos(Vector(0,0,0))
|
||||
self.ArrowX:SetLocalAngles(Vector(1,0,0):Angle())
|
||||
self.ArrowX.axistype = 1
|
||||
|
||||
self.ArrowY = ents.Create("rgm_axis_arrow")
|
||||
self.ArrowY:SetParent(self)
|
||||
@ -26,6 +27,7 @@ function ENT:Setup()
|
||||
self.ArrowY:SetColor(Color(0,255,0,255))
|
||||
self.ArrowY:SetLocalPos(Vector(0,0,0))
|
||||
self.ArrowY:SetLocalAngles(Vector(0,1,0):Angle())
|
||||
self.ArrowY.axistype = 2
|
||||
|
||||
self.ArrowZ = ents.Create("rgm_axis_arrow")
|
||||
self.ArrowZ:SetParent(self)
|
||||
@ -33,6 +35,7 @@ function ENT:Setup()
|
||||
self.ArrowZ:SetColor(Color(0,0,255,255))
|
||||
self.ArrowZ:SetLocalPos(Vector(0,0,0))
|
||||
self.ArrowZ:SetLocalAngles(Vector(0,0,1):Angle())
|
||||
self.ArrowZ.axistype = 3
|
||||
|
||||
//Arrow sides
|
||||
self.ArrowXY = ents.Create("rgm_axis_side")
|
||||
@ -70,6 +73,7 @@ function ENT:Setup()
|
||||
self.DiscP:SetNWInt("type",TYPE_DISC)
|
||||
self.DiscP:SetLocalPos(Vector(0,0,0))
|
||||
self.DiscP:SetLocalAngles(Vector(0,1,0):Angle())
|
||||
self.DiscP.axistype = 1 -- axistype is a variable to help with setting non physical bones - 1 for pitch, 2 yaw, 3 roll, 4 for the big one
|
||||
|
||||
self.DiscY = ents.Create("rgm_axis_disc")
|
||||
self.DiscY:SetParent(self)
|
||||
@ -78,6 +82,7 @@ function ENT:Setup()
|
||||
self.DiscY:SetNWInt("type",TYPE_DISC)
|
||||
self.DiscY:SetLocalPos(Vector(0,0,0))
|
||||
self.DiscY:SetLocalAngles(Vector(0,0,1):Angle())
|
||||
self.DiscY.axistype = 2
|
||||
|
||||
self.DiscR = ents.Create("rgm_axis_disc")
|
||||
self.DiscR:SetParent(self)
|
||||
@ -86,6 +91,7 @@ function ENT:Setup()
|
||||
self.DiscR:SetNWInt("type",TYPE_DISC)
|
||||
self.DiscR:SetLocalPos(Vector(0,0,0))
|
||||
self.DiscR:SetLocalAngles(Vector(1,0,0):Angle())
|
||||
self.DiscR.axistype = 3
|
||||
|
||||
self.DiscLarge = ents.Create("rgm_axis_disc_large")
|
||||
self.DiscLarge:SetParent(self)
|
||||
@ -95,6 +101,7 @@ function ENT:Setup()
|
||||
self.DiscLarge:SetNWInt("type",TYPE_DISC)
|
||||
self.DiscLarge:SetLocalPos(Vector(0,0,0))
|
||||
self.DiscLarge:SetLocalAngles(Vector(1,0,0):Angle()) //This will be constantly changed
|
||||
self.DiscLarge.axistype = 4
|
||||
|
||||
self.Axises = {
|
||||
self.ArrowX,
|
||||
@ -143,25 +150,59 @@ function ENT:Think()
|
||||
|
||||
local ent = pl.rgm.Entity;
|
||||
local bone = pl.rgm.PhysBone;
|
||||
if !IsValid(ent) then return end
|
||||
if !IsValid(ent) or !pl.rgm.Bone then return end
|
||||
|
||||
local OldPos = self:GetPos();
|
||||
local OldAng = self:GetAngles();
|
||||
local OldDiscPos = self.DiscLarge:GetLocalPos();
|
||||
local OldDiscAng = self.DiscLarge:GetLocalAngles();
|
||||
local pos, ang;
|
||||
local rotate = pl.rgm.Rotate or false;
|
||||
|
||||
local physobj = ent:GetPhysicsObjectNum(bone)
|
||||
local pos,ang = physobj:GetPos(),physobj:GetAngles()
|
||||
|
||||
if pl.rgm.IsPhysBone then
|
||||
local physobj = ent:GetPhysicsObjectNum(bone);
|
||||
if physobj == nil then return end
|
||||
pos,ang = physobj:GetPos(),physobj:GetAngles();
|
||||
else
|
||||
if !pl.rgm.GizmoPos then
|
||||
local matrix = ent:GetBoneMatrix(bone);
|
||||
pos = ent:GetBonePosition(bone);
|
||||
if pos == ent:GetPos() then
|
||||
pos = matrix:GetTranslation();
|
||||
end
|
||||
else
|
||||
pos = pl.rgm.GizmoPos;
|
||||
end
|
||||
|
||||
if rotate then
|
||||
if !pl.rgm.GizmoAng then -- dunno if there is a need for these failsafes
|
||||
_ , ang = ent:GetBonePosition(bone);
|
||||
else
|
||||
ang = pl.rgm.GizmoAng;
|
||||
end
|
||||
else
|
||||
if ent:GetBoneParent(bone) ~= -1 then
|
||||
if !pl.rgm.GizmoParent then
|
||||
matrix = ent:GetBoneMatrix(ent:GetBoneParent(bone)); -- never would have guessed that when moving bones they use angles of their parent bone rather than their own angles. happened to get to know that after looking at vanilla bone manipulator!
|
||||
ang = matrix:GetAngles();
|
||||
else
|
||||
ang = pl.rgm.GizmoParent;
|
||||
end
|
||||
elseif IsValid(pl.rgm.EffectBase) then
|
||||
ang = pl.rgm.EffectBase:GetAngles();
|
||||
end
|
||||
end
|
||||
end
|
||||
self:SetPos(pos)
|
||||
|
||||
local localstate = self.localizedpos
|
||||
local rotate = pl.rgm.Rotate or false;
|
||||
if rotate then localstate = self.localizedang end
|
||||
if localstate then
|
||||
self:SetAngles(ang)
|
||||
else
|
||||
self:SetAngles(Angle(0,0,0))
|
||||
if !pl.rgm.Moving then -- Prevent whole thing from rotating when we do localized rotation - needed for proper angle reading
|
||||
if localstate or !pl.rgm.IsPhysBone then -- Non phys bones don't go well with world coordinates. Well, I didn't make them to behave with those
|
||||
self:SetAngles(ang or Angle(0,0,0))
|
||||
else
|
||||
self:SetAngles(Angle(0,0,0))
|
||||
end
|
||||
end
|
||||
|
||||
//Updating positions
|
||||
|
@ -24,6 +24,7 @@ function ENT:TestCollision(pl,scale)
|
||||
local Start,End = 1,6
|
||||
if rotate then Start,End = 7,10 end
|
||||
local cols = {}
|
||||
if !self.Axises then return false end;
|
||||
for i=Start,End do
|
||||
local e = self.Axises[i];
|
||||
-- print(e);
|
||||
|
@ -3,13 +3,24 @@ include("shared.lua")
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm)
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm, isphys, StartGrab, NPhysPos)
|
||||
local intersect = self:GetGrabPos(eyepos,eyeang,ppos)
|
||||
local localized = self:WorldToLocal(intersect)
|
||||
localized = Vector(localized.x,0,0)
|
||||
intersect = self:LocalToWorld(localized)
|
||||
local ang = obj:GetAngles()
|
||||
local pos,_a = LocalToWorld(Vector(offpos.x,0,0),Angle(0,0,0),intersect,self:GetAngles())
|
||||
local pos, ang
|
||||
|
||||
if isphys then
|
||||
local _a
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
localized = Vector(localized.x,0,0)
|
||||
intersect = self:LocalToWorld(localized)
|
||||
ang = obj:GetAngles()
|
||||
pos,_a = LocalToWorld(Vector(offpos.x,0,0),Angle(0,0,0),intersect,self:GetAngles())
|
||||
else
|
||||
pos = ent:GetManipulateBonePosition(bone)
|
||||
localized = Vector(localized.x - StartGrab.x,0,0)
|
||||
local posadd = NPhysPos[self.axistype] + localized.x
|
||||
ang = ent:GetManipulateBoneAngles(bone)
|
||||
pos[self.axistype] = posadd
|
||||
end
|
||||
return pos,ang
|
||||
end
|
@ -3,12 +3,73 @@ include("shared.lua")
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm)
|
||||
local function ConvertVector(vec, axistype)
|
||||
local rotationtable, result
|
||||
|
||||
if axistype == 1 then
|
||||
result = Vector(-vec.x, vec.z, 0)
|
||||
elseif axistype == 2 then
|
||||
result = Vector(vec.x, vec.y, 0)
|
||||
elseif axistype == 3 then
|
||||
result = Vector(vec.y, vec.z, 0)
|
||||
else
|
||||
result = vec
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm, isphys, startAngle, garbage, NPhysAngle) -- initially i had a table instead of separate things for initial bone pos and angle, but sync command can't handle tables and i thought implementing a way to handle those would be too much hassle
|
||||
local intersect = self:GetGrabPos(eyepos,eyeang,ppos,pnorm)
|
||||
local localized = self:WorldToLocal(intersect)
|
||||
localized = Vector(localized.y,localized.z,0):Angle()
|
||||
local pos = self:GetPos()
|
||||
local ang = self:LocalToWorldAngles(Angle(0,0,localized.y))
|
||||
local _p,_a = LocalToWorld(Vector(0,0,0),offang,pos,ang)
|
||||
return pos,_a
|
||||
end
|
||||
local _p, _a
|
||||
local pl = self:GetParent().Owner
|
||||
local axistable = {
|
||||
(self:GetParent():LocalToWorld(Vector(0,1,0)) - self:GetPos()):Angle(),
|
||||
(self:GetParent():LocalToWorld(Vector(0,0,1)) - self:GetPos()):Angle(),
|
||||
(self:GetParent():LocalToWorld(Vector(1,0,0)) - self:GetPos()):Angle(),
|
||||
(self:GetPos()-pl:EyePos()):Angle()
|
||||
}
|
||||
|
||||
|
||||
if isphys then
|
||||
localized = Vector(localized.y,localized.z,0):Angle()
|
||||
local pos = self:GetPos()
|
||||
local ang = self:LocalToWorldAngles(Angle(0,0,localized.y))
|
||||
_p,_a = LocalToWorld(Vector(0,0,0),offang,pos,ang)
|
||||
_p = pos
|
||||
else
|
||||
local rotateang, axisangle
|
||||
axisangle = axistable[self.axistype]
|
||||
--[[ _a = ent:GetManipulateBoneAngles(bone)
|
||||
localized = WorldToLocal(localized, localized:Angle(), Vector(0, 0, 0), startAngle:Angle())
|
||||
localized = Vector(localized.x, localized.z, 0):Angle()
|
||||
rotateang = NPhysAngle[self.axistype] + localized.y -- putting it in another variable to avoid constant adding onto the angle variable
|
||||
_a[self.axistype] = rotateang]]
|
||||
|
||||
local _, boneang = ent:GetBonePosition(bone)
|
||||
local startlocal = LocalToWorld(startAngle, startAngle:Angle(), Vector(0,0,0), axisangle) -- first we get our vectors into world coordinates, relative to the axis angles
|
||||
localized = LocalToWorld(localized, localized:Angle(), Vector(0,0,0), axisangle)
|
||||
localized = WorldToLocal(localized, localized:Angle(), Vector(0,0,0), boneang) -- then convert that vector to the angles of the bone
|
||||
startlocal = WorldToLocal(startlocal, startlocal:Angle(), Vector(0,0,0), boneang)
|
||||
|
||||
localized = ConvertVector(localized, self.axistype)
|
||||
startlocal = ConvertVector(startlocal, self.axistype)
|
||||
|
||||
localized = localized:Angle() - startlocal:Angle()
|
||||
|
||||
if self.axistype == 4 then
|
||||
rotateang = NPhysAngle + localized
|
||||
_a = rotateang
|
||||
else
|
||||
_a = ent:GetManipulateBoneAngles(bone)
|
||||
rotateang = NPhysAngle[self.axistype] + localized.y
|
||||
_a[self.axistype] = rotateang
|
||||
end
|
||||
|
||||
|
||||
_p = ent:GetManipulateBonePosition(bone)
|
||||
end
|
||||
|
||||
return _p,_a
|
||||
end
|
||||
|
@ -3,7 +3,9 @@ ENT.Type = "anim"
|
||||
ENT.Base = "base_entity"
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetNoDraw(true)
|
||||
if CLIENT then
|
||||
self:SetNoDraw(true)
|
||||
end
|
||||
self:DrawShadow(false)
|
||||
self:SetCollisionBounds(Vector(-0.1,-0.1,-0.1),Vector(0.1,0.1,0.1))
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
|
@ -3,10 +3,35 @@ include("shared.lua")
|
||||
AddCSLuaFile("cl_init.lua")
|
||||
AddCSLuaFile("shared.lua")
|
||||
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm)
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
function ENT:ProcessMovement(offpos,offang,eyepos,eyeang,ent,bone,ppos,pnorm, isphys, startGrab, NPhysPos)
|
||||
local intersect = self:GetGrabPos(eyepos,eyeang,ppos,pnorm)
|
||||
local ang = obj:GetAngles()
|
||||
local pos,_a = LocalToWorld(offpos,Angle(0,0,0),intersect,self:GetAngles())
|
||||
local pos, ang
|
||||
local pl = self:GetParent().Owner
|
||||
|
||||
if isphys then
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
ang = obj:GetAngles()
|
||||
pos = LocalToWorld(offpos,Angle(0,0,0),intersect,self:GetAngles())
|
||||
else
|
||||
local localized, startmove, finalpos, boneang
|
||||
if ent:GetBoneParent(bone) ~= -1 then
|
||||
local matrix = ent:GetBoneMatrix(ent:GetBoneParent(bone))
|
||||
boneang = matrix:GetAngles();
|
||||
else
|
||||
if IsValid(pl.rgm.EffectBase) then
|
||||
boneang = pl.rgm.EffectBase:GetAngles()
|
||||
else
|
||||
boneang = Angle(0,0,0)
|
||||
end
|
||||
end
|
||||
|
||||
localized = LocalToWorld(offpos,Angle(0,0,0),intersect,self:GetAngles())
|
||||
localized = WorldToLocal(localized, Angle(0,0,0), self:GetPos(), boneang)
|
||||
|
||||
finalpos = NPhysPos + localized
|
||||
ang = ent:GetManipulateBoneAngles(bone)
|
||||
pos = finalpos
|
||||
end
|
||||
|
||||
return pos,ang
|
||||
end
|
@ -8,6 +8,14 @@ TOOL.ClientConVar["localpos"] = 0
|
||||
TOOL.ClientConVar["localang"] = 1
|
||||
TOOL.ClientConVar["scale"] = 10
|
||||
TOOL.ClientConVar["fulldisc"] = 0
|
||||
TOOL.ClientConVar["manual"] = 0
|
||||
TOOL.ClientConVar["boneid"] = 0
|
||||
TOOL.ClientConVar["entityholder"] = "some"
|
||||
TOOL.ClientConVar["entity"] = ""
|
||||
TOOL.ClientConVar["resetbone"] = 0
|
||||
TOOL.ClientConVar["disablefilter"] = 0
|
||||
TOOL.ClientConVar["disablechildbone"] = 0
|
||||
TOOL.ClientConVar["selecteffects"] = 0
|
||||
|
||||
TOOL.ClientConVar["ik_leg_L"] = 0
|
||||
TOOL.ClientConVar["ik_leg_R"] = 0
|
||||
@ -21,12 +29,112 @@ TOOL.ClientConVar["updaterate"] = 0.01
|
||||
|
||||
TOOL.ClientConVar["rotatebutton"] = MOUSE_MIDDLE
|
||||
|
||||
TOOL.ClientConVar["boneidmax"] = 20
|
||||
TOOL.ClientConVar["boneidmaxholder"] = 20
|
||||
|
||||
RunConsoleCommand("ragdollmover_boneid",0)
|
||||
|
||||
concommand.Add("ragdollmover_resetroot", function(pl)
|
||||
pl.rgm.IsPhysBone = true;
|
||||
pl.rgm.PhysBone = 0;
|
||||
pl.rgm.Bone = 0;
|
||||
RunConsoleCommand("ragdollmover_boneid",0);
|
||||
pl:rgmSync();
|
||||
end)
|
||||
|
||||
local TransTable = {
|
||||
"ArrowX", "ArrowY", "ArrowZ",
|
||||
"ArrowXY", "ArrowXZ", "ArrowYZ",
|
||||
"DiscP", "DiscY", "DiscR"
|
||||
}
|
||||
|
||||
local function SyncOneClient(self, name)
|
||||
if SERVER or !self.rgm then return end
|
||||
|
||||
local v = self.rgm[name];
|
||||
if v == nil then return end
|
||||
|
||||
net.Start("rgmSyncClient");
|
||||
|
||||
local count = 1;
|
||||
net.WriteInt(count, 32);
|
||||
|
||||
net.WriteString(name);
|
||||
|
||||
local Type = string.lower(type(v));
|
||||
if Type == "entity" then
|
||||
net.WriteInt(1, 8); -- Int's correspond to the type of data we pass, for more info check ragdollmover_meta.lua, since that's where i took the function from
|
||||
net.WriteEntity(v);
|
||||
elseif Type == "number" then
|
||||
net.WriteInt(2, 8);
|
||||
net.WriteFloat(v);
|
||||
elseif Type == "vector" then
|
||||
net.WriteInt(3, 8);
|
||||
net.WriteVector(v);
|
||||
elseif Type == "angle" then
|
||||
net.WriteInt(4, 8);
|
||||
net.WriteAngle(v);
|
||||
elseif Type == "boolean" then
|
||||
net.WriteInt(5, 8);
|
||||
net.WriteBit(v);
|
||||
end
|
||||
net.SendToServer();
|
||||
end
|
||||
|
||||
local function RGMGetBone(pl, ent, bone)
|
||||
--------------------------------------------------------- yeah this part is from locrotscale
|
||||
local phys, physobj;
|
||||
local manual = tobool(GetConVarNumber("ragdollmover_manual"));
|
||||
pl.rgm.IsPhysBone = false;
|
||||
|
||||
for i = 0, ent:GetPhysicsObjectCount() - 1 do
|
||||
local b = ent:TranslatePhysBoneToBone(i);
|
||||
if bone == b then
|
||||
phys = i;
|
||||
end
|
||||
end
|
||||
|
||||
local count = ent:GetPhysicsObjectCount()
|
||||
|
||||
if count == 0 then
|
||||
phys = -1;
|
||||
elseif count == 1 then
|
||||
if ent:GetBoneCount() <= 1 then
|
||||
phys = 0;
|
||||
pl.rgm.IsPhysBone = true;
|
||||
end
|
||||
end
|
||||
|
||||
if phys and 0 <= phys and count > phys then
|
||||
physobj = ent:GetPhysicsObjectNum(phys);
|
||||
|
||||
if physobj then
|
||||
pl.rgm.IsPhysBone = true;
|
||||
end
|
||||
end
|
||||
---------------------------------------------------------
|
||||
if manual and tobool(GetConVarNumber("ragdollmover_selecteffects")) then
|
||||
if phys == -1 then phys = nil end
|
||||
end
|
||||
local bonen = phys or bone;
|
||||
|
||||
pl.rgm.PhysBone = bonen;
|
||||
pl.rgm.Bone = bonen;
|
||||
end
|
||||
|
||||
function TOOL:Deploy()
|
||||
if SERVER then
|
||||
local pl = self:GetOwner();
|
||||
local axis = pl.rgm.Axis;
|
||||
if !IsValid(axis) then
|
||||
axis = ents.Create("rgm_axis");
|
||||
axis:Spawn();
|
||||
axis.Owner = pl;
|
||||
pl.rgm.Axis = axis;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL:LeftClick(tr)
|
||||
|
||||
if CLIENT then return false end
|
||||
@ -36,36 +144,39 @@ function TOOL:LeftClick(tr)
|
||||
if pl.rgm.Moving then return false end
|
||||
|
||||
local axis = pl.rgm.Axis;
|
||||
if !IsValid(axis) then
|
||||
axis = ents.Create("rgm_axis")
|
||||
axis:Spawn()
|
||||
axis.Owner = pl;
|
||||
axis:Setup()
|
||||
pl.rgm.Axis = axis;
|
||||
if !axis.Axises then
|
||||
axis:Setup();
|
||||
end
|
||||
|
||||
local collision = axis:TestCollision(pl,self:GetClientNumber("scale",10))
|
||||
local ent = pl.rgm.Entity;
|
||||
local entstr = tostring(ent)
|
||||
RunConsoleCommand("ragdollmover_entity",entstr)
|
||||
if collision and IsValid(ent) then
|
||||
|
||||
if _G["physundo"] and _G["physundo"].Create then
|
||||
_G["physundo"].Create(ent,pl)
|
||||
end
|
||||
|
||||
|
||||
local apart = collision.axis
|
||||
|
||||
pl.rgmISPos = collision.hitpos*1
|
||||
pl.rgmISDir = apart:GetAngles():Forward()
|
||||
|
||||
pl.rgmOffsetTable = rgm.GetOffsetTable(self, ent, pl.rgm.Rotate)
|
||||
|
||||
pl.rgmOffsetPos = WorldToLocal(apart:GetPos(),apart:GetAngles(),collision.hitpos,apart:GetAngles())
|
||||
|
||||
local opos = apart:WorldToLocal(collision.hitpos)
|
||||
local obj = ent:GetPhysicsObjectNum(pl.rgm.PhysBone)
|
||||
local grabang = apart:LocalToWorldAngles(Angle(0,0,Vector(opos.y,opos.z,0):Angle().y))
|
||||
local _p
|
||||
_p,pl.rgmOffsetAng = WorldToLocal(apart:GetPos(),obj:GetAngles(),apart:GetPos(),grabang)
|
||||
if obj then
|
||||
_p,pl.rgmOffsetAng = WorldToLocal(apart:GetPos(),obj:GetAngles(),apart:GetPos(),grabang)
|
||||
pl.rgmOffsetTable = rgm.GetOffsetTable(self, ent, pl.rgm.Rotate)
|
||||
end
|
||||
|
||||
pl.rgm.StartAngle = WorldToLocal(collision.hitpos, Angle(0,0,0), apart:GetPos(), apart:GetAngles())
|
||||
pl.rgm.NPhysBonePos = ent:GetManipulateBonePosition(pl.rgm.Bone)
|
||||
pl.rgm.NPhysBoneAng = ent:GetManipulateBoneAngles(pl.rgm.Bone)
|
||||
|
||||
local dirnorm = (collision.hitpos-axis:GetPos())
|
||||
dirnorm:Normalize()
|
||||
@ -77,24 +188,57 @@ function TOOL:LeftClick(tr)
|
||||
pl.rgm.MoveAxis = apart;
|
||||
pl.rgm.KeyDown = true;
|
||||
pl.rgm.Moving = true;
|
||||
|
||||
pl:rgmSync();
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
if IsValid(tr.Entity) and (tr.Entity:GetClass() == "prop_ragdoll" or tr.Entity:GetClass() == "prop_physics") then
|
||||
-- pl:SetNWInt("ragdollmover_physbone",tr.PhysicsBone)
|
||||
-- pl:SetNWInt("ragdollmover_bone",tr.Entity:TranslatePhysBoneToBone(tr.PhysicsBone))
|
||||
-- pl:SetNWEntity("ragdollmover_ent",tr.Entity)
|
||||
-- pl:SetNWBool("ragdollmover_draw",true)
|
||||
pl.rgm.PhysBone = tr.PhysicsBone;
|
||||
pl.rgm.Bone = tr.Entity:TranslatePhysBoneToBone(tr.PhysicsBone);
|
||||
pl.rgm.Entity = tr.Entity;
|
||||
pl.rgm.Draw = true;
|
||||
if IsValid(tr.Entity) and ( (tr.Entity:GetClass() == "prop_ragdoll" or tr.Entity:GetClass() == "prop_physics" or tr.Entity:GetClass() == "prop_effect" ) or tobool(self:GetClientNumber("disablefilter",0)) ) then
|
||||
local entity
|
||||
|
||||
pl:rgmSync();
|
||||
if tobool(self:GetClientNumber("manual",0)) and tobool(self:GetClientNumber("selecteffects",0)) and IsValid(tr.Entity.AttachedEntity) then
|
||||
pl:SetNWEntity("ragdollmover_ent",tr.Entity.AttachedEntity) -- if manual bone selection is enabled and we select props, we select attached entity (the prop of effect prop, if that makes sense)
|
||||
|
||||
pl.rgm.EffectBase = tr.Entity
|
||||
entity = tr.Entity.AttachedEntity
|
||||
pl.rgm.Entity = tr.Entity.AttachedEntity
|
||||
pl.rgm.Draw = true
|
||||
else
|
||||
-- pl:SetNWInt("ragdollmover_physbone",tr.PhysicsBone)
|
||||
-- pl:SetNWInt("ragdollmover_bone",tr.Entity:TranslatePhysBoneToBone(tr.PhysicsBone))
|
||||
pl:SetNWEntity("ragdollmover_ent",tr.Entity)
|
||||
-- pl:SetNWBool("ragdollmover_draw",true)
|
||||
entity = tr.Entity
|
||||
pl.rgm.Entity = tr.Entity;
|
||||
pl.rgm.EffectBase = nil;
|
||||
pl.rgm.Draw = true;
|
||||
end
|
||||
|
||||
if not entity.rgmbonecached then -- also taken from locrotscale. some hacky way to cache the bones?
|
||||
local p = self.SWEP:GetParent();
|
||||
self.SWEP:FollowBone(entity, 0);
|
||||
self.SWEP:SetParent(p);
|
||||
entity.rgmbonecached = true;
|
||||
end
|
||||
|
||||
if !tobool(self:GetClientNumber("manual",0)) then
|
||||
pl.rgm.PhysBone = tr.PhysicsBone;
|
||||
pl.rgm.Bone = entity:TranslatePhysBoneToBone(tr.PhysicsBone);
|
||||
pl.rgm.IsPhysBone = true;
|
||||
end
|
||||
|
||||
local bonecount = entity:GetBoneCount() - 1
|
||||
if bonecount then
|
||||
RunConsoleCommand("ragdollmover_boneidmax", bonecount);
|
||||
end
|
||||
|
||||
if ((GetConVarNumber("ragdollmover_boneidmaxholder") ~= GetConVarNumber("ragdollmover_boneidmax"))
|
||||
or (GetConVarString("ragdollmover_entity") ~= GetConVarString("ragdollmover_entityholder")))
|
||||
and tobool(self:GetClientNumber("manual",0)) then
|
||||
RunConsoleCommand("ragdollmover_resetroot");
|
||||
else
|
||||
pl:rgmSync();
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
@ -111,22 +255,81 @@ function TOOL:Reload()
|
||||
|
||||
local pl = self:GetOwner();
|
||||
|
||||
pl.rgm.PhysBone = 0;
|
||||
pl.rgm.Bone = 0;
|
||||
|
||||
pl:rgmSync();
|
||||
RunConsoleCommand("ragdollmover_resetroot")
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
function TOOL:Think()
|
||||
if CLIENT then
|
||||
|
||||
local pl = self:GetOwner();
|
||||
if !pl.rgm then return end
|
||||
if !pl.rgm.ClientSet then -- setting special function for syncing client to server variables, since hook in ragdollmover_meta only works serverside
|
||||
pl.rgmSyncClient = SyncOneClient;
|
||||
pl.rgm.ClientSet = true;
|
||||
end
|
||||
|
||||
if (GetConVarNumber("ragdollmover_boneidmaxholder") ~= GetConVarNumber("ragdollmover_boneidmax")) then
|
||||
RunConsoleCommand("ragdollmover_boneidmaxholder", GetConVarNumber("ragdollmover_boneidmax"));
|
||||
--ripped from default faceposer
|
||||
self:UpdateFaceControlPanel();
|
||||
return;
|
||||
elseif (GetConVarString("ragdollmover_entity") ~= GetConVarString("ragdollmover_entityholder")) then
|
||||
RunConsoleCommand("ragdollmover_entityholder", GetConVarString("ragdollmover_entity"));
|
||||
--ripped from default faceposer
|
||||
self:UpdateFaceControlPanel();
|
||||
return;
|
||||
end
|
||||
|
||||
if pl.rgm.Moving then return end -- don't want to keep updating this stuff when we move stuff, so it'll go smoother
|
||||
|
||||
local ent, axis = pl.rgm.Entity, pl.rgm.Axis; -- so, this thing... bone position and angles seem to work clientside best, whereas server's ones are kind of shite
|
||||
if IsValid(ent) and IsValid(axis) and pl.rgm.Bone then
|
||||
local bone = pl.rgm.Bone;
|
||||
local pos, ang = ent:GetBonePosition(bone);
|
||||
if pos == ent:GetPos() then
|
||||
local matrix = ent:GetBoneMatrix(bone);
|
||||
pos = matrix:GetTranslation();
|
||||
ang = matrix:GetAngles();
|
||||
end
|
||||
if ent:GetBoneParent(bone) ~= -1 then
|
||||
local matrix = ent:GetBoneMatrix(ent:GetBoneParent(bone))
|
||||
local ang = matrix:GetAngles();
|
||||
pl.rgm.GizmoParent = ang;
|
||||
else
|
||||
pl.rgm.GizmoParent = nil;
|
||||
end
|
||||
pl.rgm.GizmoPos = pos;
|
||||
pl.rgm.GizmoAng = ang;
|
||||
pl:rgmSyncClient("GizmoPos");
|
||||
pl:rgmSyncClient("GizmoAng");
|
||||
pl:rgmSyncClient("GizmoParent");
|
||||
else
|
||||
pl.rgm.GizmoPos = nil;
|
||||
pl.rgm.GizmoAng = nil;
|
||||
pl.rgm.GizmoParent = nil;
|
||||
pl:rgmSyncClient("GizmoPos");
|
||||
pl:rgmSyncClient("GizmoAng");
|
||||
pl:rgmSyncClient("GizmoParent");
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
|
||||
|
||||
if !self.LastThink then self.LastThink = CurTime() end
|
||||
if CurTime() < self.LastThink + self:GetClientNumber("updaterate",0.01) then return end
|
||||
|
||||
local pl = self:GetOwner()
|
||||
local ent = pl.rgm.Entity;
|
||||
--[[ physboneid = ent:TranslatePhysBoneToBone(GetConVarNumber("ragdollmover_boneid"))
|
||||
RunConsoleCommand("ragdollmover_boneidlabel", ent:GetBoneName(physboneid)) ]]
|
||||
|
||||
if pl.rgm.Bone ~= GetConVarNumber("ragdollmover_boneid") and tobool(self:GetClientNumber("manual",0)) and IsValid(ent) then
|
||||
RGMGetBone(pl, ent, self:GetClientNumber( "boneid",0 ))
|
||||
pl:rgmSync()
|
||||
end
|
||||
|
||||
local axis = pl.rgm.Axis;
|
||||
if IsValid(axis) then
|
||||
@ -138,6 +341,12 @@ function TOOL:Think()
|
||||
end
|
||||
end
|
||||
|
||||
if GetConVarNumber("ragdollmover_resetbone") ~= 0 then
|
||||
RunConsoleCommand("ragdollmover_resetbone", 0)
|
||||
ent:ManipulateBoneAngles(pl.rgm.Bone, Angle(0, 0, 0))
|
||||
ent:ManipulateBonePosition(pl.rgm.Bone, Vector(0, 0, 0))
|
||||
end
|
||||
|
||||
local moving = pl.rgm.Moving or false;
|
||||
local rotate = pl.rgm.Rotate or false;
|
||||
if moving then
|
||||
@ -149,81 +358,106 @@ function TOOL:Think()
|
||||
local apart = pl.rgm.MoveAxis;
|
||||
local bone = pl.rgm.PhysBone;
|
||||
local ent = pl.rgm.Entity;
|
||||
|
||||
|
||||
if !IsValid(ent) then
|
||||
pl.rgm.Moving = false;
|
||||
return
|
||||
end
|
||||
|
||||
local isik,iknum = rgm.IsIKBone(self,ent,bone)
|
||||
local physbonecount = ent:GetBoneCount() - 1
|
||||
if physbonecount == nil then return end
|
||||
|
||||
RunConsoleCommand("ragdollmover_boneidmax", physbonecount)
|
||||
|
||||
local pos,ang = apart:ProcessMovement(pl.rgmOffsetPos,pl.rgmOffsetAng,eyepos,eyeang,ent,bone,pl.rgmISPos,pl.rgmISDir)
|
||||
if pl.rgm.IsPhysBone then
|
||||
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
if !isik or iknum == 3 or (rotate and (iknum == 1 or iknum == 2)) then
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
obj:SetPos(pos)
|
||||
obj:SetAngles(ang)
|
||||
obj:EnableMotion(false)
|
||||
obj:Wake()
|
||||
elseif iknum == 2 then
|
||||
for k,v in pairs(ent.rgmIKChains) do
|
||||
if v.knee == bone then
|
||||
local intersect = apart:GetGrabPos(eyepos,eyeang)
|
||||
local obj1 = ent:GetPhysicsObjectNum(v.hip)
|
||||
local obj2 = ent:GetPhysicsObjectNum(v.foot)
|
||||
local kd = (intersect-(obj2:GetPos()+(obj1:GetPos()-obj2:GetPos())))
|
||||
kd:Normalize()
|
||||
ent.rgmIKChains[k].ikkneedir = kd*1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local postable = rgm.SetOffsets(self,ent,pl.rgmOffsetTable,{b = bone,p = obj:GetPos(),a = obj:GetAngles()})
|
||||
local sbik,sbiknum = rgm.IsIKBone(self,ent,bone)
|
||||
if !sbik or sbiknum != 2 then
|
||||
postable[bone].dontset = true
|
||||
end
|
||||
for i=0,ent:GetPhysicsObjectCount()-1 do
|
||||
if postable[i] and !postable[i].dontset then
|
||||
local obj = ent:GetPhysicsObjectNum(i)
|
||||
-- postable[i].pos.x = math.Round(postable[i].pos.x,3)
|
||||
-- postable[i].pos.y = math.Round(postable[i].pos.y,3)
|
||||
-- postable[i].pos.z = math.Round(postable[i].pos.z,3)
|
||||
-- postable[i].ang.p = math.Round(postable[i].ang.p,3)
|
||||
-- postable[i].ang.y = math.Round(postable[i].ang.y,3)
|
||||
-- postable[i].ang.r = math.Round(postable[i].ang.r,3)
|
||||
|
||||
local poslen = postable[i].pos:Length();
|
||||
local anglen = Vector(postable[i].ang.p,postable[i].ang.y,postable[i].ang.r):Length();
|
||||
|
||||
//Temporary solution for INF and NaN decimals crashing the game (Even rounding doesnt fix it)
|
||||
if poslen > 2 and anglen > 2 then
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
obj:SetPos(postable[i].pos)
|
||||
obj:SetAngles(postable[i].ang)
|
||||
obj:EnableMotion(false)
|
||||
obj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if !pl:GetNWBool("ragdollmover_keydown") then
|
||||
if !pl:KeyDown(IN_ATTACK) then
|
||||
if self:GetClientNumber("unfreeze",1) > 0 then
|
||||
for i=0,ent:GetPhysicsObjectCount()-1 do
|
||||
if pl.rgmOffsetTable[i].moving then
|
||||
local obj = ent:GetPhysicsObjectNum(i)
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
local isik,iknum = rgm.IsIKBone(self,ent,bone)
|
||||
|
||||
local pos,ang = apart:ProcessMovement(pl.rgmOffsetPos,pl.rgmOffsetAng,eyepos,eyeang,ent,bone,pl.rgmISPos,pl.rgmISDir, true)
|
||||
|
||||
local obj = ent:GetPhysicsObjectNum(bone)
|
||||
if !isik or iknum == 3 or (rotate and (iknum == 1 or iknum == 2)) then
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
obj:SetPos(pos)
|
||||
obj:SetAngles(ang)
|
||||
obj:EnableMotion(false)
|
||||
obj:Wake()
|
||||
elseif iknum == 2 then
|
||||
for k,v in pairs(ent.rgmIKChains) do
|
||||
if v.knee == bone then
|
||||
local intersect = apart:GetGrabPos(eyepos,eyeang)
|
||||
local obj1 = ent:GetPhysicsObjectNum(v.hip)
|
||||
local obj2 = ent:GetPhysicsObjectNum(v.foot)
|
||||
local kd = (intersect-(obj2:GetPos()+(obj1:GetPos()-obj2:GetPos())))
|
||||
kd:Normalize()
|
||||
ent.rgmIKChains[k].ikkneedir = kd*1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pl.rgm.Moving = false;
|
||||
pl:rgmSyncOne("Moving");
|
||||
if !tobool(self:GetClientNumber("disablechildbone",0)) then
|
||||
|
||||
local postable = rgm.SetOffsets(self,ent,pl.rgmOffsetTable,{b = bone,p = obj:GetPos(),a = obj:GetAngles()})
|
||||
|
||||
if postable == nil then return end
|
||||
|
||||
local firstbone = pl.rgmOffsetTable["FirstBone"]
|
||||
local sbik,sbiknum = rgm.IsIKBone(self,ent,bone)
|
||||
if !sbik or sbiknum != 2 then
|
||||
postable[bone].dontset = true
|
||||
end
|
||||
for i=0 + firstbone,ent:GetPhysicsObjectCount()-1 do
|
||||
if postable[i] and !postable[i].dontset then
|
||||
local obj = ent:GetPhysicsObjectNum(i)
|
||||
-- postable[i].pos.x = math.Round(postable[i].pos.x,3)
|
||||
-- postable[i].pos.y = math.Round(postable[i].pos.y,3)
|
||||
-- postable[i].pos.z = math.Round(postable[i].pos.z,3)
|
||||
-- postable[i].ang.p = math.Round(postable[i].ang.p,3)
|
||||
-- postable[i].ang.y = math.Round(postable[i].ang.y,3)
|
||||
-- postable[i].ang.r = math.Round(postable[i].ang.r,3)
|
||||
|
||||
local poslen = postable[i].pos:Length();
|
||||
local anglen = Vector(postable[i].ang.p,postable[i].ang.y,postable[i].ang.r):Length();
|
||||
|
||||
//Temporary solution for INF and NaN decimals crashing the game (Even rounding doesnt fix it)
|
||||
if poslen > 2 and anglen > 2 then
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
obj:SetPos(postable[i].pos)
|
||||
obj:SetAngles(postable[i].ang)
|
||||
obj:EnableMotion(false)
|
||||
obj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if !pl:GetNWBool("ragdollmover_keydown") then
|
||||
if !pl:KeyDown(IN_ATTACK) then
|
||||
if self:GetClientNumber("unfreeze",1) > 0 then
|
||||
for i=0,ent:GetPhysicsObjectCount()-1 do
|
||||
if pl.rgmOffsetTable[i].moving then
|
||||
local obj = ent:GetPhysicsObjectNum(i)
|
||||
obj:EnableMotion(true)
|
||||
obj:Wake()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
pl.rgm.Moving = false;
|
||||
pl:rgmSyncOne("Moving");
|
||||
end
|
||||
else
|
||||
local pos, ang = apart:ProcessMovement(pl.rgmOffsetPos,pl.rgmOffsetAng,eyepos,eyeang,ent,bone,pl.rgmISPos,pl.rgmISDir, false, pl.rgm.StartAngle, pl.rgm.NPhysBonePos, pl.rgm.NPhysBoneAng) -- if a bone is not physics one, we pass over "start angle" thing
|
||||
|
||||
ent:ManipulateBoneAngles(bone, ang)
|
||||
ent:ManipulateBonePosition(bone, pos)
|
||||
|
||||
if !pl:KeyDown(IN_ATTACK) then -- don't think entity has to be unfrozen if you were working with non phys bones, that would be weird?
|
||||
pl.rgm.Moving = false;
|
||||
pl:rgmSyncOne("Moving");
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@ -251,6 +485,7 @@ local function CCheckBox(cpanel,text,cvar)
|
||||
local CB = vgui.Create("DCheckBoxLabel",cpanel)
|
||||
CB:SetText(text)
|
||||
CB:SetConVar(cvar)
|
||||
CB:SetDark(true)
|
||||
cpanel:AddItem(CB)
|
||||
return CB
|
||||
end
|
||||
@ -260,7 +495,10 @@ local function CNumSlider(cpanel,text,cvar,min,max,dec)
|
||||
SL:SetDecimals(dec)
|
||||
SL:SetMinMax(min,max)
|
||||
SL:SetConVar(cvar)
|
||||
SL:SetDark(true)
|
||||
|
||||
cpanel:AddItem(SL)
|
||||
|
||||
return SL
|
||||
end
|
||||
local function CCol(cpanel,text)
|
||||
@ -274,15 +512,53 @@ local function CCol(cpanel,text)
|
||||
col:EnableHorizontal(false)
|
||||
col:EnableVerticalScrollbar(true)
|
||||
col.Paint = function()
|
||||
surface.SetDrawColor(100,100,100,255)
|
||||
surface.DrawRect(0, 0, 500, 500)
|
||||
end
|
||||
cat:SetContents(col)
|
||||
return col
|
||||
return col, cat
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel(CPanel)
|
||||
|
||||
local function RGMResetButton(cpanel)
|
||||
local pl = LocalPlayer()
|
||||
if !pl.rgm then return end
|
||||
local ent = pl.rgm.Entity
|
||||
if !IsValid(ent) then return end
|
||||
local butt = vgui.Create("DButton", cpanel)
|
||||
butt:SetText("Reset Non-Physics Bone")
|
||||
function butt:DoClick()
|
||||
if !IsValid(ent) then return end
|
||||
RunConsoleCommand("ragdollmover_resetbone", 1)
|
||||
end
|
||||
cpanel:AddItem(butt)
|
||||
end
|
||||
|
||||
local colbones
|
||||
local category
|
||||
local Col4
|
||||
|
||||
local function RGMBuildBoneMenu(ent, cpanel)
|
||||
if category then
|
||||
colbones:Remove()
|
||||
category:Remove()
|
||||
end
|
||||
colbones, category = CCol(cpanel, "Bone List")
|
||||
RGMResetButton(colbones)
|
||||
CNumSlider(colbones,"BoneID","ragdollmover_boneid",0,GetConVarNumber("ragdollmover_boneidmax"),0)
|
||||
if !IsValid(ent) then return end
|
||||
local num = GetConVarNumber("ragdollmover_boneidmax")
|
||||
for i = 0,num do
|
||||
local text1 = ent:GetBoneName(i)
|
||||
local butt = vgui.Create("DButton", colbones)
|
||||
butt:SetText(text1)
|
||||
function butt:DoClick() --think making a function to call a console command is better than making another console command... to call another console command
|
||||
RunConsoleCommand("ragdollmover_boneid",i)
|
||||
end
|
||||
colbones:AddItem(butt)
|
||||
--:AddControl("Button",{text = text1, Command = cmd})
|
||||
end
|
||||
end
|
||||
|
||||
function TOOL.BuildCPanel(CPanel, ent)
|
||||
CPanel:AddControl("Header",{Name = "#Tool_ragdollmover_name","#Tool_ragdollmover_desc"})
|
||||
|
||||
CPanel:SetSpacing(3)
|
||||
@ -292,7 +568,7 @@ function TOOL.BuildCPanel(CPanel)
|
||||
CCheckBox(Col1,"Localized angle gizmo.","ragdollmover_localang")
|
||||
CNumSlider(Col1,"Scale","ragdollmover_scale",1.0,50.0,1)
|
||||
CCheckBox(Col1,"Fully visible discs.","ragdollmover_fulldisc")
|
||||
|
||||
|
||||
local Col2 = CCol(CPanel,"IK Chains")
|
||||
CCheckBox(Col2,"Left Hand IK","ragdollmover_ik_hand_L")
|
||||
CCheckBox(Col2,"Right Hand IK","ragdollmover_ik_hand_R")
|
||||
@ -302,8 +578,9 @@ function TOOL.BuildCPanel(CPanel)
|
||||
local Col3 = CCol(CPanel,"Misc")
|
||||
local CB = CCheckBox(Col3,"Unfreeze on release.","ragdollmover_unfreeze")
|
||||
CB:SetToolTip("Unfreeze bones that were unfrozen before grabbing the ragdoll.")
|
||||
local DisFil = CCheckBox(Col3, "Disable entity filter.","ragdollmover_disablefilter")
|
||||
DisFil:SetToolTip("Disable entity filter to select ANY entity. CAUTION - may be buggy")
|
||||
CNumSlider(Col3,"Tool update rate.","ragdollmover_updaterate",0.01,1.0,2)
|
||||
-- CCheckBox(Col3, "Use right mouse button.", "ragdollmover_use_rmb");
|
||||
|
||||
CPanel:AddControl( "Numpad", { Label = "Move/Rotate toggle button", Command = "ragdollmover_rotatebutton" } )
|
||||
-- local B = vgui.Create("DButton", CPanel);
|
||||
@ -311,9 +588,26 @@ function TOOL.BuildCPanel(CPanel)
|
||||
-- B:SetToolTip("This must be pressed so that the move/rotate button is changed.");
|
||||
-- B.DoClick = function() LocalPlayer():ConCommand("ragdollmover_changebutton"); end
|
||||
|
||||
Col4 = CCol(CPanel, "Bone Manipulation")
|
||||
local manual = CCheckBox(Col4,"Manual Bone Picking","ragdollmover_manual")
|
||||
manual:SetToolTip("Enable bone selection through the bone menu. Select bone ID and then click on the selected ragdoll to pick that bone.")
|
||||
local disableoffset = CCheckBox(Col4, "Disable Child Bone Offset", "ragdollmover_disablechildbone")
|
||||
disableoffset:SetToolTip("Disable child bone offset (Example: When you rotate pelvis, angles of other bones will be the same)")
|
||||
local effectselect = CCheckBox(Col4, "Select Effects", "ragdollmover_selecteffects")
|
||||
effectselect:SetToolTip("MAKE SURE MANUAL BONE PICKING IS ENABLED. Allows you to manipulate bones of the effect props.")
|
||||
RGMBuildBoneMenu(ent, Col4)
|
||||
|
||||
//CPanel:SetHeight(500)
|
||||
end
|
||||
|
||||
function TOOL:UpdateFaceControlPanel( index )
|
||||
local pl = self:GetOwner()
|
||||
local ent = pl.rgm.Entity
|
||||
|
||||
RGMBuildBoneMenu(ent, Col4)
|
||||
|
||||
end
|
||||
|
||||
function TOOL:DrawHUD()
|
||||
|
||||
local pl = LocalPlayer()
|
||||
@ -325,13 +619,10 @@ function TOOL:DrawHUD()
|
||||
local ent = pl.rgm.Entity;
|
||||
local bone = pl.rgm.Bone;
|
||||
local axis = pl.rgm.Axis;
|
||||
local dodraw = pl.rgm.Draw or false;
|
||||
|
||||
local moving = pl.rgm.Moving or false;
|
||||
|
||||
//We don't draw the axis if we don't have the axis entity or the target entity,
|
||||
//or if we're not allowed to draw it.
|
||||
if IsValid(ent) and IsValid(axis) and bone and dodraw then
|
||||
if IsValid(ent) and IsValid(axis) and bone then
|
||||
local scale = self:GetClientNumber("scale",10)
|
||||
local rotate = pl.rgm.Rotate or false;
|
||||
local moveaxis = pl.rgm.MoveAxis;
|
||||
@ -344,6 +635,7 @@ function TOOL:DrawHUD()
|
||||
axis:DrawDirectionLine(fwd,scale,false)
|
||||
local dirnorm = pl.rgm.DirNorm or Vector(1,0,0);
|
||||
axis:DrawDirectionLine(dirnorm,scale,true)
|
||||
axis:DrawAngleText(moveaxis, intersect, pl.rgm.StartAngle)
|
||||
end
|
||||
else
|
||||
axis:DrawLines(scale)
|
||||
@ -353,7 +645,7 @@ function TOOL:DrawHUD()
|
||||
|
||||
local tr = pl:GetEyeTrace()
|
||||
local aimedbone = pl.rgm.AimedBone or 0;
|
||||
if IsValid(tr.Entity) and (tr.Entity:GetClass() == "prop_ragdoll" or tr.Entity:GetClass() == "prop_physics")
|
||||
if IsValid(tr.Entity) and (tr.Entity:GetClass() == "prop_ragdoll" or tr.Entity:GetClass() == "prop_physics" or tr.Entity:GetClass() == "prop_effect")
|
||||
and (!bone or aimedbone != bone) and !moving then
|
||||
rgm.DrawBoneName(tr.Entity,aimedbone);
|
||||
-- if (!bone or aimedbone != bone) and !pl:GetNWBool("ragdollmover_moving",false) then
|
||||
@ -364,8 +656,8 @@ function TOOL:DrawHUD()
|
||||
-- end
|
||||
-- _pos = _pos:ToScreen()
|
||||
-- local textpos = {x = _pos.x+5,y = _pos.y-5}
|
||||
-- surface.DrawCircle(_pos.x,_pos.y,2.5,Color(0,200,0,255))
|
||||
-- draw.SimpleText(name,"Default",textpos.x,textpos.y,Color(0,200,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM)
|
||||
-- surface.DrawCircle(_pos.x,_pos.y,2.5,Color(0,0,0,255))
|
||||
-- draw.SimpleText(name,"Default",textpos.x,textpos.y,Color(0,0,0,255),TEXT_ALIGN_LEFT,TEXT_ALIGN_BOTTOM)
|
||||
-- end
|
||||
end
|
||||
|
||||
|
@ -9,8 +9,8 @@ TOOL.ClientConVar["type"] = "Left Leg"
|
||||
local ikchains_iktypes = {
|
||||
"Left Leg",
|
||||
"Right Leg",
|
||||
"Left Hand",
|
||||
"Right Hand"
|
||||
"Left Arm",
|
||||
"Right Arm"
|
||||
}
|
||||
|
||||
local function Message(ply,text,icon,sound)
|
||||
@ -73,24 +73,24 @@ if CLIENT then
|
||||
|
||||
language.Add("tool.ragmover_ikchains.name","Ragdoll Mover - IK Chains")
|
||||
language.Add("tool.ragmover_ikchains.desc","Make your own IK chains for ragdolls to be used with Ragdoll Mover.")
|
||||
language.Add("tool.ragmover_ikchains.0","Left click to select IK hip bone.")
|
||||
language.Add("tool.ragmover_ikchains.1","Now left click again to select foot bone.")
|
||||
language.Add("tool.ragmover_ikchains.0","Left click to select IK hip/upperarm bone.")
|
||||
language.Add("tool.ragmover_ikchains.1","Now left click again to select foot/hand bone.")
|
||||
|
||||
function TOOL.BuildCPanel(CPanel)
|
||||
|
||||
CPanel:AddControl("Header",{Name = "#Tool_ragmover_ikchains_name","#Tool_ragmover_ikchains_desc"})
|
||||
|
||||
/*local mc = CPanel:MultiChoice("IK chain type","ragmover_ikchains_type")
|
||||
--[[ local mc = CPanel:MultiChoice("IK chain type","ragmover_ikchains_type")
|
||||
mc:AddChoice("Left Leg")
|
||||
mc:AddChoice("Right Leg")
|
||||
mc:AddChoice("Left Hand")
|
||||
mc:AddChoice("Right Hand")*/
|
||||
mc:AddChoice("Left Arm")
|
||||
mc:AddChoice("Right Arm") ]]
|
||||
|
||||
local s = CPanel:NumSlider("IK slot: "..ikchains_iktypes[1],"ragmover_ikchains_type",1,4,0)
|
||||
s:SetValue(0)
|
||||
s:SetDecimals(0);
|
||||
s.ValueChanged = function(self,val)
|
||||
self:SetText("IK slot: "..ikchains_iktypes[math.ceil(self:GetValue())])
|
||||
RunConsoleCommand("ragmover_ikchains_type",math.Round(self:GetValue()))
|
||||
self:SetText("IK slot: "..ikchains_iktypes[math.Round(self:GetValue())])
|
||||
end
|
||||
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user