zcnpci/lua/fedhoria/modules/stumble_legs.lua

554 lines
15 KiB
Lua
Raw Normal View History

2026-05-25 04:57:41 +00:00
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