554 lines
No EOL
15 KiB
Lua
554 lines
No EOL
15 KiB
Lua
MODULE.Model = "models/barney.mdl"
|
|
MODULE.BoneList =
|
|
{
|
|
"ValveBiped.Bip01_Pelvis",
|
|
"ValveBiped.Bip01_Spine2",
|
|
--"ValveBiped.Bip01_Head1",
|
|
--"ValveBiped.Bip01_R_Upperarm",
|
|
--"ValveBiped.Bip01_R_Forearm",
|
|
--"ValveBiped.Bip01_R_Hand",
|
|
--"ValveBiped.Bip01_L_Upperarm",
|
|
--"ValveBiped.Bip01_L_Forearm",
|
|
--"ValveBiped.Bip01_L_Hand",
|
|
"ValveBiped.Bip01_R_Thigh",
|
|
"ValveBiped.Bip01_R_Calf",
|
|
"ValveBiped.Bip01_R_Foot",
|
|
"ValveBiped.Bip01_L_Thigh",
|
|
"ValveBiped.Bip01_L_Calf",
|
|
"ValveBiped.Bip01_L_Foot"
|
|
}
|
|
|
|
local stumble_time = CreateConVar("fedhoria_stumble_time", 2, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
|
local grab_chance = CreateConVar("fedhoria_woundgrab_chance", 0.9, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
|
local grab_time = CreateConVar("fedhoria_woundgrab_time", 5, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
|
|
|
local math_atan2 = math.atan2
|
|
local math_pi = math.pi
|
|
local math_Clamp = math.Clamp
|
|
local math_max = math.max
|
|
local math_min = math.min
|
|
|
|
local constant = 10000
|
|
|
|
local function CreateSpring(phys1, phys2)
|
|
if (!IsValid(phys1) or !IsValid(phys2)) then return NULL end
|
|
local str_axis = tostring(phys2:LocalToWorld(phys2:GetAABBCenter()))
|
|
|
|
local const = ents.Create("phys_spring")
|
|
const:SetPos(phys1:LocalToWorld(phys1:GetAABBCenter()))
|
|
const:SetKeyValue("springaxis", str_axis)
|
|
const:SetKeyValue("constant", constant)
|
|
const:SetKeyValue("damping", 0.1)
|
|
const:SetKeyValue("relativedamping", 0.1)
|
|
const:SetPhysConstraintObjects(phys1, phys2)
|
|
const:Spawn()
|
|
const:Activate()
|
|
--const:Fire("SetSpringLength", 0, 0)
|
|
|
|
return const
|
|
end
|
|
|
|
local allowed_touch =
|
|
{
|
|
"ValveBiped.Bip01_R_Calf",
|
|
"ValveBiped.Bip01_R_Foot",
|
|
"ValveBiped.Bip01_L_Calf",
|
|
"ValveBiped.Bip01_L_Foot"
|
|
}
|
|
|
|
local hand_offset = Vector(2, 0, 0)
|
|
|
|
function MODULE:Init(phys_bone, lpos)
|
|
self.seq_walk = self:LookupSequence("walk_all")
|
|
self.seq_walk_speed = self:GetSequenceMoveDist(self.seq_walk) * self:SequenceDuration(self.seq_walk)
|
|
|
|
self.seq_run = self:LookupSequence("run_all")
|
|
self.seq_run_speed = self:GetSequenceMoveDist(self.seq_run) * self:SequenceDuration(self.seq_run)
|
|
|
|
self.seq_sprint = self:LookupSequence("sprint_all")
|
|
self.seq_sprint_speed = self:GetSequenceMoveDist(self.seq_sprint) * self:SequenceDuration(self.seq_sprint)
|
|
|
|
self:ResetSequence(self:LookupSequence("idle01"))
|
|
|
|
local target = self:GetTarget()
|
|
|
|
for _, bone_name in pairs(self.BoneList) do
|
|
local bone = self:LookupBone(bone_name)
|
|
if bone then
|
|
local phys_bone = target:TranslateBoneToPhysBone(bone)
|
|
local phys = target:GetPhysicsObjectNum(phys_bone)
|
|
--phys:AddGameFlag(FVPHYSICS_NO_SELF_COLLISIONS)
|
|
end
|
|
end
|
|
|
|
self.bone_lthigh = self:LookupBone("ValveBiped.Bip01_L_Thigh")
|
|
self.bone_rthigh = self:LookupBone("ValveBiped.Bip01_R_Thigh")
|
|
|
|
if (self.bone_lthigh and self.bone_rthigh) then
|
|
self.phys_bone_lthigh = self:TranslateBoneToPhysBone(self.bone_lthigh)
|
|
self.phys_bone_rthigh = self:TranslateBoneToPhysBone(self.bone_rthigh)
|
|
end
|
|
|
|
self.bone_lcalf = self:LookupBone("ValveBiped.Bip01_L_Calf")
|
|
self.bone_rcalf = self:LookupBone("ValveBiped.Bip01_R_Calf")
|
|
|
|
if (self.bone_lcalf and self.bone_rcalf) then
|
|
self.phys_bone_lcalf = self:TranslateBoneToPhysBone(self.bone_lcalf)
|
|
self.phys_bone_rcalf = self:TranslateBoneToPhysBone(self.bone_rcalf)
|
|
end
|
|
|
|
self.bone_lfoot = self:LookupBone("ValveBiped.Bip01_L_Foot")
|
|
self.bone_rfoot = self:LookupBone("ValveBiped.Bip01_R_Foot")
|
|
|
|
if (self.bone_lfoot and self.bone_rfoot) then
|
|
self.phys_bone_lfoot = self:TranslateBoneToPhysBone(self.bone_lfoot)
|
|
self.phys_bone_rfoot = self:TranslateBoneToPhysBone(self.bone_rfoot)
|
|
end
|
|
|
|
self.bone_lhand = self:LookupBone("ValveBiped.Bip01_L_Hand")
|
|
self.bone_rhand = self:LookupBone("ValveBiped.Bip01_R_Hand")
|
|
|
|
if (self.bone_lhand and self.bone_rhand) then
|
|
self.phys_bone_lhand = self:TranslateBoneToPhysBone(self.bone_lhand)
|
|
self.phys_bone_rhand = self:TranslateBoneToPhysBone(self.bone_rhand)
|
|
end
|
|
|
|
self.phys_allowed_touch = {}
|
|
|
|
for _, bone_name in pairs(allowed_touch) do
|
|
local bone = self:LookupBone(bone_name)
|
|
if bone then
|
|
local phys_bone = self:TranslateBoneToPhysBone(bone)
|
|
self.phys_allowed_touch[phys_bone] = true
|
|
end
|
|
end
|
|
|
|
self.bone_pelvis = self:LookupBone("ValveBiped.Bip01_Pelvis")
|
|
self.bone_torso = self:LookupBone("ValveBiped.Bip01_Spine2")
|
|
|
|
if (self.bone_pelvis and self.bone_torso) then
|
|
self.phys_bone_pelvis = target:TranslateBoneToPhysBone(self.bone_pelvis)
|
|
self.phys_bone_torso = target:TranslateBoneToPhysBone(self.bone_torso)
|
|
|
|
--constraint.Weld(target, target, phys_bone_pelvis, phys_bone_torso)
|
|
end
|
|
|
|
local vel = target:GetVelocity():Length2D()
|
|
|
|
if phys_bone then
|
|
self.Springs = {}
|
|
--Grab wound
|
|
local phys = target:GetPhysicsObjectNum(phys_bone)
|
|
local dmgpos = phys:LocalToWorld(lpos)
|
|
if (IsValid(phys) and phys_bone != self.phys_bone_lhand and phys_bone != self.phys_bone_rhand) then
|
|
local phys_lhand = target:GetPhysicsObjectNum(self.phys_bone_lhand)
|
|
local phys_rhand = target:GetPhysicsObjectNum(self.phys_bone_rhand)
|
|
|
|
local str_axis = tostring(dmgpos)
|
|
|
|
if (IsValid(phys_lhand) and math.random() < grab_chance:GetFloat()) then
|
|
local const = ents.Create("phys_spring")
|
|
const:SetPos(phys_lhand:LocalToWorld(hand_offset))
|
|
const:SetKeyValue("springaxis", str_axis)
|
|
const:SetKeyValue("constant", 300)
|
|
const:SetKeyValue("damping", 0.1)
|
|
const:SetKeyValue("relativedamping", 0.1)
|
|
const:SetPhysConstraintObjects(phys_lhand, phys)
|
|
const:Spawn()
|
|
const:Activate()
|
|
const:Fire("SetSpringLength", 0, 0)
|
|
|
|
SafeRemoveEntityDelayed(const, grab_time:GetFloat())
|
|
|
|
table.insert(self.Springs, const)
|
|
end
|
|
|
|
if (IsValid(phys_rhand) and math.random() < grab_chance:GetFloat()) then
|
|
local const = ents.Create("phys_spring")
|
|
const:SetPos(phys_rhand:LocalToWorld(hand_offset))
|
|
const:SetKeyValue("springaxis", str_axis)
|
|
const:SetKeyValue("constant", 300)
|
|
const:SetKeyValue("damping", 0.1)
|
|
const:SetKeyValue("relativedamping", 0.1)
|
|
const:SetPhysConstraintObjects(phys_rhand, phys)
|
|
const:Spawn()
|
|
const:Activate()
|
|
const:Fire("SetSpringLength", 0, 0)
|
|
|
|
SafeRemoveEntityDelayed(const, grab_time:GetFloat())
|
|
|
|
table.insert(self.Springs, const)
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[if (!target.GS2IsDismembered and vel < self.seq_walk_speed) then
|
|
--self:Remove()
|
|
self.Springs = {}
|
|
if (self.phys_bone_lthigh and self.phys_bone_lcalf) then
|
|
local phys_lthigh = target:GetPhysicsObjectNum(self.phys_bone_lthigh)
|
|
local phys_lcalf = target:GetPhysicsObjectNum(self.phys_bone_lcalf)
|
|
|
|
table.insert(self.Springs, CreateSpring(phys_lthigh, phys_lcalf))
|
|
end
|
|
|
|
if (self.phys_bone_rthigh and self.phys_bone_rcalf) then
|
|
local phys_rthigh = target:GetPhysicsObjectNum(self.phys_bone_rthigh)
|
|
local phys_rcalf = target:GetPhysicsObjectNum(self.phys_bone_rcalf)
|
|
|
|
table.insert(self.Springs, CreateSpring(phys_rthigh, phys_rcalf))
|
|
end
|
|
|
|
if (self.phys_bone_pelvis and self.phys_bone_torso) then
|
|
local phys_pelvis = target:GetPhysicsObjectNum(self.phys_bone_pelvis)
|
|
local phys_torso = target:GetPhysicsObjectNum(self.phys_bone_torso)
|
|
|
|
--CreateSpring(phys_pelvis, phys_torso)
|
|
end
|
|
|
|
if (self.phys_bone_pelvis and self.phys_bone_lthigh) then
|
|
local phys_pelvis = target:GetPhysicsObjectNum(self.phys_bone_pelvis)
|
|
local phys_lthigh = target:GetPhysicsObjectNum(self.phys_bone_lthigh)
|
|
|
|
--CreateSpring(phys_pelvis, phys_lthigh)
|
|
end
|
|
|
|
if (self.phys_bone_pelvis and self.phys_bone_rthigh) then
|
|
local phys_pelvis = target:GetPhysicsObjectNum(self.phys_bone_pelvis)
|
|
local phys_rthigh = target:GetPhysicsObjectNum(self.phys_bone_rthigh)
|
|
|
|
--CreateSpring(phys_pelvis, phys_rthigh)
|
|
end
|
|
end]]
|
|
end
|
|
|
|
local function DoFallingAnim(ent)
|
|
local mod1 = fedhoria.StartModule(ent, "falling_legs")
|
|
local mod2 = fedhoria.StartModule(ent, "falling_torso")
|
|
end
|
|
|
|
function MODULE:OnRemove()
|
|
local target = self:GetTarget()
|
|
if !IsValid(target) then return end
|
|
|
|
for _, bone_name in pairs(self.BoneList) do
|
|
local bone = target:LookupBone(bone_name)
|
|
if bone then
|
|
local phys_bone = target:TranslateBoneToPhysBone(bone)
|
|
local phys = target:GetPhysicsObjectNum(phys_bone)
|
|
if IsValid(phys) then
|
|
phys:ClearGameFlag(FVPHYSICS_NO_SELF_COLLISIONS)
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[if self.Springs then
|
|
for _, spring in pairs(self.Springs) do
|
|
SafeRemoveEntityDelayed(spring, 1)
|
|
end
|
|
end]]
|
|
|
|
DoFallingAnim(target)
|
|
end
|
|
|
|
function MODULE:Think()
|
|
|
|
end
|
|
|
|
function MODULE:PhysicsCollide(ent, data)
|
|
--if (data.HitEntity == ent) then return end
|
|
if (data.HitEntity != game.GetWorld()) then return end
|
|
if (CurTime() - self.Created < 0.1) then return end
|
|
|
|
local phys = data.PhysObject
|
|
local phys_bone = phys:GetID()
|
|
|
|
if !self.phys_allowed_touch[phys_bone] then
|
|
SafeRemoveEntityDelayed(self, 0)
|
|
end
|
|
end
|
|
|
|
local constant = 1
|
|
|
|
local tilt_ang = Angle(0, 0, 0)
|
|
|
|
local pelvis_offset = Vector(0, 0, 35)
|
|
local torso_offset = Vector(0, 0, 50)
|
|
|
|
local trace = {output={}}
|
|
local tr = trace.output
|
|
|
|
function MODULE:PhysicsSimulate(phys, dt)
|
|
local phys_bone = phys:GetID()
|
|
|
|
local target = self:GetTarget()
|
|
|
|
if (self.Springs and target:GetNWInt("GS2DisMask", 0) != 0) then
|
|
for _, spring in pairs(self.Springs) do
|
|
SafeRemoveEntity(spring)
|
|
end
|
|
end
|
|
|
|
local st = stumble_time:GetFloat()
|
|
|
|
if (st <= 0) then
|
|
self:Remove()
|
|
return false
|
|
end
|
|
|
|
local f = 1 - (CurTime() - self.Created) / st
|
|
|
|
--RagMod Reworked support
|
|
if ragmod and ragmod:IsRagmodRagdoll(target) then
|
|
local owner = target:GetOwningPlayer()
|
|
if !IsValid(owner) or !owner:Alive() then
|
|
f = 0
|
|
else
|
|
f = 1
|
|
end
|
|
end
|
|
|
|
if (f <= 0) then
|
|
self:Remove()
|
|
return false
|
|
end
|
|
|
|
--helps reduce excessive twitching
|
|
if (phys:GetStress() > 100) then
|
|
return false
|
|
end
|
|
|
|
if (phys_bone == self.phys_bone_torso) then
|
|
local phys_pelvis = target:GetPhysicsObjectNum(self.phys_bone_pelvis or 0)
|
|
local vel = phys:GetVelocity()
|
|
vel.z = 0
|
|
vel:Normalize()
|
|
|
|
local ang = phys_pelvis:GetAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
|
|
local x = ang:Right():Dot(vel)
|
|
local y = ang:Forward():Dot(vel)
|
|
|
|
local yaw = 180 * math_atan2(y, x) / math_pi
|
|
|
|
if (yaw < 90 and yaw > -90) then
|
|
return false
|
|
end
|
|
end
|
|
|
|
if (phys_bone == (self.phys_bone_pelvis or 0)) then
|
|
local phys_torso = target:GetPhysicsObjectNum(self.phys_bone_torso or 1)
|
|
--calculate animation settings here so its only done once per frame
|
|
local pos = phys:GetPos()
|
|
local ang = phys:GetAngles()
|
|
--local vel = phys:GetVelocity()
|
|
local vel = phys_torso:GetVelocity()
|
|
|
|
local forward = ang:Forward()
|
|
local right = ang:Right()
|
|
local up = ang:Up()
|
|
|
|
--try keeping balance a little bit better
|
|
tilt_ang.y = math_Clamp(90 + 180 * math_atan2(right.z, up.z) / math_pi, -50, 20) * f
|
|
|
|
--too much balance?
|
|
tilt_ang.p = -ang.p * f
|
|
|
|
self:ManipulateBoneAngles(self.bone_lthigh, tilt_ang)
|
|
self:ManipulateBoneAngles(self.bone_rthigh, tilt_ang)
|
|
|
|
local speed = vel:Length2D()
|
|
|
|
local slow = false
|
|
|
|
if (speed > self.seq_sprint_speed) then
|
|
self:ResetSequence(self.seq_sprint)
|
|
elseif (speed > self.seq_run_speed) then
|
|
self:ResetSequence(self.seq_run)
|
|
elseif (speed > self.seq_walk_speed) then
|
|
self:ResetSequence(self.seq_walk)
|
|
else
|
|
slow = true
|
|
end
|
|
|
|
if slow then
|
|
return false
|
|
--[[elseif (self.Springs) then
|
|
for _, spring in pairs(self.Springs) do
|
|
SafeRemoveEntity(spring)
|
|
end
|
|
self.Springs = nil]]
|
|
end
|
|
|
|
--self:ResetSequence(self.seq_sprint)
|
|
|
|
--local mass_center = target:GetMassCenter()
|
|
|
|
self.last_pos = self.last_pos or pos
|
|
|
|
local delta = (pos - self.last_pos) / dt
|
|
|
|
self.last_pos = pos
|
|
|
|
local pbr = vel:Length2D() / self:GetSequenceMoveDist(self:GetSequence())
|
|
--local pbr = vel:Dot(ang:Right()) / self:GetSequenceMoveDist(self:GetSequence())
|
|
|
|
--pbr = pbr / self:SequenceDuration()
|
|
|
|
vel.z = 0
|
|
vel:Normalize()
|
|
|
|
local ang = phys:GetAngles()
|
|
ang.p = 0
|
|
ang.r = 0
|
|
|
|
local x = ang:Right():Dot(vel)
|
|
local y = ang:Forward():Dot(vel)
|
|
|
|
self.pbr = math.min(3, Lerp(dt * constant, self.pbr or pbr, pbr))
|
|
|
|
local yaw = 180 * math_atan2(y, x) / math_pi
|
|
|
|
local m = 1
|
|
|
|
if (yaw > 90) then
|
|
m = -1.5
|
|
yaw = -90 + yaw - 90
|
|
self:ResetSequence(self.seq_sprint)
|
|
elseif (yaw < -90) then
|
|
m = -1.5
|
|
yaw = 90 - (yaw + 90)
|
|
self:ResetSequence(self.seq_sprint)
|
|
end
|
|
|
|
self.move_yaw = Lerp(dt * constant, self.move_yaw or yaw, yaw)
|
|
|
|
self:SetPoseParameter("move_yaw", self.move_yaw)
|
|
|
|
self:SetPlaybackRate(m * self.pbr * self:SequenceDuration())
|
|
|
|
trace.filter = target
|
|
trace.start = pos
|
|
trace.endpos = pos - torso_offset
|
|
|
|
util.TraceLine(trace)
|
|
|
|
if tr.Hit then
|
|
if (x < 0) then
|
|
ang = phys:GetAngles()
|
|
local a = math.max(0, -ang:Right().z)^2
|
|
|
|
if (a < 0.2) then
|
|
--self:Remove()
|
|
--return false
|
|
end
|
|
|
|
pos = phys_torso:GetPos()
|
|
|
|
local d = (pos - tr.HitPos):Length2D()
|
|
|
|
local div = self:GetSequenceMoveDist(self:GetSequence()) * self:SequenceDuration()
|
|
|
|
local m = math_max(0, 1 - (d / div))
|
|
|
|
vel = phys:GetVelocity()
|
|
vel.x = 0
|
|
vel.y = 0
|
|
|
|
m = m * a
|
|
|
|
vel.z = vel.z * m
|
|
|
|
phys:ApplyForceCenter(-vel * phys:GetMass() * f)
|
|
|
|
vel = phys_torso:GetVelocity()
|
|
vel.x = 0
|
|
vel.y = 0
|
|
|
|
vel.z = vel.z * m
|
|
|
|
phys_torso:ApplyForceCenter(-vel * phys_torso:GetMass() * f)
|
|
return false
|
|
else
|
|
local l2d = delta:Length2D()
|
|
|
|
local f = f * math_Clamp(l2d / self:GetSequenceMoveDist(self:GetSequence()), 0, 1)
|
|
|
|
local targetZ = tr.HitPos.z + torso_offset.z * f
|
|
|
|
local offsetZ = targetZ - phys_torso:GetPos().z
|
|
|
|
if (offsetZ > 0) then
|
|
local force = offsetZ^2 - phys_torso:GetVelocity().z
|
|
force = force * 0.5
|
|
force = math_min(force, 40)
|
|
phys_torso:ApplyForceCenter(Vector(0, 0, force) * phys_torso:GetMass() * f)
|
|
end
|
|
|
|
local targetZ = tr.HitPos.z + pelvis_offset.z * f
|
|
|
|
local offsetZ = targetZ - phys:GetPos().z
|
|
|
|
if (offsetZ > 0) then
|
|
local force = offsetZ^2 - phys:GetVelocity().z
|
|
force = force * 0.5
|
|
force = math_min(force, 40)
|
|
phys:ApplyForceCenter(Vector(0, 0, force) * phys:GetMass() * f)
|
|
end
|
|
end
|
|
else
|
|
self:Remove()
|
|
return false
|
|
end
|
|
|
|
if (self.phys_bone_lhand) then
|
|
--[[local phys_lhand = target:GetPhysicsObjectNum(self.phys_bone_lhand)
|
|
|
|
pos = phys_lhand:GetPos()
|
|
|
|
local pos2 = target:GetBonePosition(target:LookupBone("ValveBiped.Bip01_L_Upperarm"))
|
|
|
|
local offset = pos2 - pos
|
|
|
|
offset:Add(phys:GetVelocity() * dt)
|
|
|
|
offset.z = 0
|
|
|
|
offset = offset:GetNormal() * offset:Length()^2
|
|
|
|
offset:Sub(phys_lhand:GetVelocity())
|
|
|
|
phys_lhand:ApplyForceCenter(offset * phys_lhand:GetMass() * f)]]
|
|
end
|
|
|
|
if (self.phys_bone_rhand) then
|
|
--[[local phys_rhand = target:GetPhysicsObjectNum(self.phys_bone_rhand)
|
|
|
|
pos = phys_rhand:GetPos()
|
|
|
|
local pos2 = target:GetBonePosition(target:LookupBone("ValveBiped.Bip01_R_Upperarm"))
|
|
|
|
local offset = pos2 - pos
|
|
|
|
offset:Add(phys:GetVelocity() * dt)
|
|
|
|
offset.z = 0
|
|
|
|
offset = offset:GetNormal() * offset:Length()^2
|
|
|
|
offset:Sub(phys_rhand:GetVelocity())
|
|
|
|
phys_rhand:ApplyForceCenter(offset * phys_rhand:GetMass() * f)]]
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--[[if self.Springs then
|
|
return false
|
|
end]]
|
|
|
|
return true, f
|
|
end |