Compare commits
No commits in common. "4c4d59838a79a27b59787cc70a7fdf31d2a749c9" and "e8112ffd8ac4ec27552e9a5dc2084b02ab4a7236" have entirely different histories.
4c4d59838a
...
e8112ffd8a
9 changed files with 34 additions and 527 deletions
|
|
@ -34,16 +34,13 @@ It is, however, not compatbile with:
|
||||||
|
|
||||||
MUST BE DONE BEFORE RELEASE:
|
MUST BE DONE BEFORE RELEASE:
|
||||||
|
|
||||||
- Spinal injuries
|
|
||||||
- NPCs should not unfake when moved around
|
- NPCs should not unfake when moved around
|
||||||
- Fire / falling / pain reaction (more rapid flailing)
|
- Actual specific reactions to being on fire / falling / lots of pain
|
||||||
- NPCs should not unfake if being grabbed
|
|
||||||
|
|
||||||
Stuff to do:
|
Stuff to do:
|
||||||
|
|
||||||
- Facial expressions
|
- Facial expressions
|
||||||
- Generally improve stumbling (foot stepping)
|
- Generally improve stumbling (foot stepping)
|
||||||
- Stop NPCs from dropping their guns (that's not a good thing to do)
|
|
||||||
|
|
||||||
Post release ideas:
|
Post release ideas:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,8 @@
|
||||||
local function PopulateAISBXToolMenu(pnl)
|
|
||||||
pnl:CheckBox("Allow NPCs to target downed NPCs", "zcnpci_npc_targeting_enabled")
|
|
||||||
pnl:ControlHelp("If enabled, NPCs target downed hostile NPCs.")
|
|
||||||
|
|
||||||
pnl:CheckBox("NPCs should target head", "zcnpci_target_should_follow_head")
|
|
||||||
pnl:ControlHelp("Should NPCs target the player's head? This can result in more effective targeting.")
|
|
||||||
|
|
||||||
pnl:CheckBox("NPCs shouldn't target unconscious NPCs", "zcnpci_no_unconscious_targeting")
|
|
||||||
|
|
||||||
pnl:CheckBox("NPCs shouldn't target unconscious players", "zcnpci_no_unconscious_targeting_players")
|
|
||||||
pnl:ControlHelp("This may or may not work.")
|
|
||||||
end
|
|
||||||
|
|
||||||
local function PopulateCustomNPCSBXToolMenu(pnl)
|
local function PopulateCustomNPCSBXToolMenu(pnl)
|
||||||
local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "NPC-classes-here!", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "NPC-classes-here!", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
|
||||||
pnl:Help("ZCNPCi has support for both modded NPCs, as well as base-game humanoid NPCs that Z-City never added. There is no guarantee that modded NPCs will work, but ones with similar skeletal structure to other base-game humanoid NPCs will generally work better.")
|
pnl:Help("ZCNPCi has support for both modded NPCs, as well as base-game humanoid NPCs that Z-City never added. There is no guarantee that modded NPCs will work, but ones with similar skeletal structure to other base-game humanoid NPCs will generally work better.")
|
||||||
|
|
||||||
pnl:Help("As long as the NPC has a compatible skeleton, support will be provided for modded NPCs on a best-effort basis.")
|
|
||||||
|
|
||||||
pnl:CheckBox("Allow base-game extended NPCs", "zcnpci_allow_extended_base_npcs")
|
pnl:CheckBox("Allow base-game extended NPCs", "zcnpci_allow_extended_base_npcs")
|
||||||
pnl:ControlHelp("Enable or disables applying custom health system to most other base-game humanoid NPCs, such as Kleiner.")
|
pnl:ControlHelp("Enable or disables applying custom health system to most other base-game humanoid NPCs, such as Kleiner.")
|
||||||
|
|
||||||
|
|
@ -40,7 +25,7 @@ local function PopulateCustomNPCSBXToolMenu(pnl)
|
||||||
|
|
||||||
pnl:AddItem(text)
|
pnl:AddItem(text)
|
||||||
|
|
||||||
pnl:Help("A list of NPC classes, seperated by spaces or line breaks. Can only be set by a superadmin or server operator.")
|
pnl:Help("One NPC class per line. No spaces or other characters. Can only be set by a superadmin or server operator.")
|
||||||
end
|
end
|
||||||
|
|
||||||
local function PopulateRagdollSBXToolMenu(pnl)
|
local function PopulateRagdollSBXToolMenu(pnl)
|
||||||
|
|
@ -140,11 +125,6 @@ if engine.ActiveGamemode() == "sandbox" then
|
||||||
PopulateRagdollSBXToolMenu(pnl)
|
PopulateRagdollSBXToolMenu(pnl)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "AISettings", "AI", "", "", function(pnl)
|
|
||||||
pnl:ClearControls()
|
|
||||||
PopulateAISBXToolMenu(pnl)
|
|
||||||
end)
|
|
||||||
|
|
||||||
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "MainSettings", "Main", "", "", function(pnl)
|
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "MainSettings", "Main", "", "", function(pnl)
|
||||||
pnl:ClearControls()
|
pnl:ClearControls()
|
||||||
PopulateMainSBXToolMenu(pnl)
|
PopulateMainSBXToolMenu(pnl)
|
||||||
|
|
|
||||||
|
|
@ -4,53 +4,39 @@ ENT.Type = "ai"
|
||||||
ENT.Base = "base_ai"
|
ENT.Base = "base_ai"
|
||||||
ENT.AutomaticFrameAdvance = true
|
ENT.AutomaticFrameAdvance = true
|
||||||
|
|
||||||
local debug_show_ragdoll_targets = CreateConVar("zcnpci_debug_show_ragdoll_targets", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
local debug_show_ragdoll_targets = CreateConVar("zcnpci_debug_show_ragdoll_targets", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
|
||||||
local should_follow_head = CreateConVar("zcnpci_target_should_follow_head", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
|
||||||
local stop_targeting_when_unconscious = CreateConVar("zcnpci_no_unconscious_targeting", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
|
||||||
|
|
||||||
local vector_offset_to_shoot_at = Vector(0, 0, 8)
|
|
||||||
|
|
||||||
local function UpdateRelationship(ent, me)
|
local function UpdateRelationship(ent, me)
|
||||||
if !IsValid(ent) or !ent:IsNPC() or (ent:GetClass() == "npc_ragdoll_target") then return end
|
if !IsValid(ent) or !ent:IsNPC() then return end
|
||||||
|
|
||||||
if ent:Disposition(me.dummy_entity) == D_HT then
|
if ent:Disposition(me.dummy_entity) == D_HT then
|
||||||
print("Ragdoll target of class "..me.ragdoll_to_follow.class_in_previous_life.." is hated by a "..ent:GetClass())
|
|
||||||
ent:AddEntityRelationship(me, D_HT, -1)
|
ent:AddEntityRelationship(me, D_HT, -1)
|
||||||
else
|
|
||||||
ent:AddEntityRelationship(me, D_NU, -1)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function RemoveRelationship(ent, me)
|
local function RemoveRelationship(ent, me)
|
||||||
if !IsValid(ent) or !ent:IsNPC() or (ent:GetClass() == "npc_ragdoll_target") then return end
|
if !IsValid(ent) or !ent:IsNPC() then return end
|
||||||
|
|
||||||
ent:AddEntityRelationship(me, D_NU, -1)
|
if ent:Disposition(me.dummy_entity) == D_HT then
|
||||||
ent:ClearEnemyMemory(me)
|
ent:AddEntityRelationship(me, D_NU, -1)
|
||||||
|
ent:ClearEnemyMemory(me)
|
||||||
|
|
||||||
if ent:GetEnemy() == me then
|
if ent:GetEnemy() == me then
|
||||||
ent:SetEnemy(nil)
|
ent:SetEnemy(nil)
|
||||||
ent:ClearSchedule()
|
ent:ClearSchedule()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ENT:Classify()
|
|
||||||
return CLASS_NONE
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Initialize()
|
function ENT:Initialize()
|
||||||
if SERVER then
|
if SERVER then
|
||||||
self:SetModel("models/maxofs2d/hover_basic.mdl")
|
self:SetModel("models/maxofs2d/hover_basic.mdl")
|
||||||
self:SetCollisionGroup(COLLISION_GROUP_NONE)
|
self:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
||||||
self:SetHullType(HULL_TINY_CENTERED)
|
self:SetHullType(HULL_TINY_CENTERED)
|
||||||
self:SetNoDraw(!debug_show_ragdoll_targets:GetBool())
|
self:SetNoDraw(!debug_show_ragdoll_targets:GetBool())
|
||||||
|
|
||||||
self.dummy_entity = ents.Create(self.ragdoll_to_follow.class_in_previous_life)
|
self.dummy_entity = ents.Create(self.ragdoll_to_follow.class_in_previous_life)
|
||||||
self.last_stop_targeting = nil
|
self.last_stop_targeting = nil
|
||||||
|
|
||||||
-- Have to use this collision group otherwise ragdoll will obstruct visibility of target
|
|
||||||
self.ragdoll_to_follow:SetCollisionGroup(COLLISION_GROUP_DEBRIS)
|
|
||||||
|
|
||||||
hook.Add("OnEntityCreated", "zcnpci-"..self:GetCreationID(), function(new_entity)
|
hook.Add("OnEntityCreated", "zcnpci-"..self:GetCreationID(), function(new_entity)
|
||||||
if !IsValid(new_entity) or !new_entity:IsNPC() then return end
|
if !IsValid(new_entity) or !new_entity:IsNPC() then return end
|
||||||
|
|
||||||
|
|
@ -64,27 +50,20 @@ end
|
||||||
function ENT:Think()
|
function ENT:Think()
|
||||||
if SERVER then
|
if SERVER then
|
||||||
local ragdoll = self.ragdoll_to_follow
|
local ragdoll = self.ragdoll_to_follow
|
||||||
if !IsValid(ragdoll) then self:Remove(); return end
|
if !IsValid(ragdoll) then return end
|
||||||
|
|
||||||
if should_follow_head:GetBool() then
|
self:SetPos(ragdoll:GetPos())
|
||||||
local head = ragdoll:GetPhysicsObjectNum(ragdoll:TranslateBoneToPhysBone(ragdoll:LookupBone("ValveBiped.Bip01_Head1")))
|
|
||||||
self:SetPos(head:GetPos() + vector_offset_to_shoot_at)
|
|
||||||
else
|
|
||||||
self:SetPos(ragdoll:GetPos())
|
|
||||||
end
|
|
||||||
|
|
||||||
self:SetNoDraw(!debug_show_ragdoll_targets:GetBool())
|
self:SetNoDraw(!debug_show_ragdoll_targets:GetBool())
|
||||||
|
|
||||||
if !ragdoll.organism then return true end
|
if !ragdoll.organism then return true end
|
||||||
|
|
||||||
if !ragdoll.organism.alive then self:Remove(); return end
|
local should_stop_targeting = (
|
||||||
|
|
||||||
local should_stop_targeting = !stop_targeting_when_unconscious:GetBool() or (
|
|
||||||
(ragdoll.organism.consciousness <= 0.4) or
|
(ragdoll.organism.consciousness <= 0.4) or
|
||||||
(ragdoll.organism.critical)
|
(ragdoll.organism.critical)
|
||||||
)
|
)
|
||||||
|
|
||||||
if true or (should_stop_targeting != self.last_stop_targeting) then
|
if should_stop_targeting != self.last_stop_targeting then
|
||||||
self.last_stop_targeting = should_stop_targeting
|
self.last_stop_targeting = should_stop_targeting
|
||||||
|
|
||||||
if should_stop_targeting then
|
if should_stop_targeting then
|
||||||
|
|
|
||||||
|
|
@ -1,147 +0,0 @@
|
||||||
AddCSLuaFile()
|
|
||||||
|
|
||||||
ENT.Type = "anim"
|
|
||||||
ENT.Base = "base_anim"
|
|
||||||
ENT.AutomaticFrameAdvance = true
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local bones_to_animate = {
|
|
||||||
"ValveBiped.Bip01_Pelvis",
|
|
||||||
"ValveBiped.Bip01_Spine2",
|
|
||||||
"ValveBiped.Bip01_Head1",
|
|
||||||
"ValveBiped.Bip01_R_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Foot",
|
|
||||||
"ValveBiped.Bip01_L_Foot",
|
|
||||||
"ValveBiped.Bip01_R_Upperarm",
|
|
||||||
"ValveBiped.Bip01_L_Upperarm",
|
|
||||||
"ValveBiped.Bip01_R_Forearm",
|
|
||||||
"ValveBiped.Bip01_L_Forearm",
|
|
||||||
"ValveBiped.Bip01_R_Hand",
|
|
||||||
"ValveBiped.Bip01_L_Hand",
|
|
||||||
}
|
|
||||||
|
|
||||||
function ENT:Initialize()
|
|
||||||
if SERVER then
|
|
||||||
print("I AM SERVERSIDE")
|
|
||||||
self:SetModel("models/dav0r/hoverball.mdl")
|
|
||||||
end
|
|
||||||
|
|
||||||
if CLIENT then
|
|
||||||
print("I AM CLIENTSIDE")
|
|
||||||
timer.Simple(0.2, function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Draw()
|
|
||||||
if CLIENT then
|
|
||||||
local old_ragdoll = self:GetNWEntity("parent")
|
|
||||||
local old_npc = self:GetNWEntity("parent_npc")
|
|
||||||
if IsValid(old_ragdoll) and IsValid(old_npc) then
|
|
||||||
if !self.ready_to_unfake then
|
|
||||||
self:SetModel(old_ragdoll:GetModel())
|
|
||||||
|
|
||||||
self.bone_list = {}
|
|
||||||
self.bone_list_end = {}
|
|
||||||
|
|
||||||
self:SetupBones()
|
|
||||||
|
|
||||||
local i = 0
|
|
||||||
while i < self:GetBoneCount() do
|
|
||||||
local name = self:GetBoneName(i)
|
|
||||||
if name == "__INVALIDBONE__" then
|
|
||||||
i = i + 1
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
table.insert(bones_to_animate, name)
|
|
||||||
|
|
||||||
|
|
||||||
local matrix = Matrix()
|
|
||||||
|
|
||||||
local position, angle = old_ragdoll:GetBonePosition(i)
|
|
||||||
if position == old_ragdoll:GetPos() then
|
|
||||||
get_matrix = old_ragdoll:GetBoneMatrix(i)
|
|
||||||
if get_matrix then
|
|
||||||
position = get_matrix:GetTranslation()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
matrix:Translate(position)
|
|
||||||
matrix:Rotate(angle)
|
|
||||||
|
|
||||||
self.bone_list[name] = matrix
|
|
||||||
|
|
||||||
local matrix = Matrix()
|
|
||||||
|
|
||||||
local position, angle = old_npc:GetBonePosition(i)
|
|
||||||
if position == old_npc:GetPos() then
|
|
||||||
get_matrix = old_npc:GetBoneMatrix(i)
|
|
||||||
if get_matrix then
|
|
||||||
position = get_matrix:GetTranslation()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
matrix:Translate(position)
|
|
||||||
matrix:Rotate(angle)
|
|
||||||
|
|
||||||
|
|
||||||
self.bone_list_end[name] = matrix
|
|
||||||
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
PrintTable(bones_to_animate)
|
|
||||||
|
|
||||||
--[[for i,name in pairs(bones_to_animate) do
|
|
||||||
local bone_index = old_ragdoll:LookupBone(name)
|
|
||||||
if bone_index == nil then continue end
|
|
||||||
|
|
||||||
self.bone_list[name] = Matrix(old_ragdoll:GetBoneMatrix(bone_index))
|
|
||||||
end]]
|
|
||||||
|
|
||||||
print("BONES:"..self:GetBoneCount())
|
|
||||||
|
|
||||||
self.ready_to_unfake = true
|
|
||||||
end
|
|
||||||
|
|
||||||
self:SetPos(old_ragdoll:GetPos())
|
|
||||||
|
|
||||||
self:SetupBones()
|
|
||||||
|
|
||||||
for name,matrix in pairs(self.bone_list) do
|
|
||||||
local bone_index = self:LookupBone(name)
|
|
||||||
if bone_index == -1 then
|
|
||||||
print(name.." does not exist, skipping...")
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--print(name)
|
|
||||||
--local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
|
|
||||||
if matrix:GetTranslation():DistToSqr(self:GetPos()) == 1 then continue end
|
|
||||||
|
|
||||||
self:SetBoneMatrix(bone_index, matrix)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:DrawModel()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Think()
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:OnRemove()
|
|
||||||
if CLIENT then
|
|
||||||
--[[if self.anim_ragdoll then
|
|
||||||
self.anim_ragdoll:Remove()
|
|
||||||
end]]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,92 +0,0 @@
|
||||||
AddCSLuaFile()
|
|
||||||
|
|
||||||
ENT.Type = "anim"
|
|
||||||
ENT.Base = "base_anim"
|
|
||||||
ENT.AutomaticFrameAdvance = true
|
|
||||||
|
|
||||||
local bones_to_animate = {
|
|
||||||
"ValveBiped.Bip01_Pelvis",
|
|
||||||
"ValveBiped.Bip01_Spine2",
|
|
||||||
"ValveBiped.Bip01_Head1",
|
|
||||||
"ValveBiped.Bip01_R_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Foot",
|
|
||||||
"ValveBiped.Bip01_L_Foot",
|
|
||||||
"ValveBiped.Bip01_R_Upperarm",
|
|
||||||
"ValveBiped.Bip01_L_Upperarm",
|
|
||||||
"ValveBiped.Bip01_R_Forearm",
|
|
||||||
"ValveBiped.Bip01_L_Forearm",
|
|
||||||
"ValveBiped.Bip01_R_Hand",
|
|
||||||
"ValveBiped.Bip01_L_Hand",
|
|
||||||
}
|
|
||||||
|
|
||||||
function ENT:Initialize()
|
|
||||||
if SERVER then
|
|
||||||
print("I AM SERVERSIDE")
|
|
||||||
self:SetModel("models/dav0r/hoverball.mdl")
|
|
||||||
end
|
|
||||||
|
|
||||||
if CLIENT then
|
|
||||||
print("I AM CLIENTSIDE")
|
|
||||||
timer.Simple(0.2, function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Draw()
|
|
||||||
if CLIENT then
|
|
||||||
local old_ragdoll = self:GetNWEntity("parent")
|
|
||||||
if IsValid(old_ragdoll) then
|
|
||||||
if !self.ready_to_unfake then
|
|
||||||
self:SetModel(old_ragdoll:GetModel())
|
|
||||||
|
|
||||||
self.bone_list = {}
|
|
||||||
|
|
||||||
self:SetupBones()
|
|
||||||
|
|
||||||
for i,name in pairs(bones_to_animate) do
|
|
||||||
local bone_index = old_ragdoll:LookupBone(name)
|
|
||||||
|
|
||||||
self.bone_list[name] = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
end
|
|
||||||
|
|
||||||
print("BONES:"..self:GetBoneCount())
|
|
||||||
|
|
||||||
self.ready_to_unfake = true
|
|
||||||
end
|
|
||||||
|
|
||||||
self:SetPos(old_ragdoll:GetPos())
|
|
||||||
|
|
||||||
for name,matrix in pairs(self.bone_list) do
|
|
||||||
local bone_index = self:LookupBone(name)
|
|
||||||
if bone_index == -1 then
|
|
||||||
print(name.." does not exist, skipping...")
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
print(name)
|
|
||||||
--local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
|
|
||||||
self:SetBoneMatrix(bone_index, matrix)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:DrawModel()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Think()
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:OnRemove()
|
|
||||||
if CLIENT then
|
|
||||||
if self.anim_ragdoll then
|
|
||||||
self.anim_ragdoll:Remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
AddCSLuaFile()
|
|
||||||
|
|
||||||
ENT.Type = "anim"
|
|
||||||
ENT.Base = "base_anim"
|
|
||||||
ENT.AutomaticFrameAdvance = true
|
|
||||||
|
|
||||||
local bones_to_animate = {
|
|
||||||
"ValveBiped.Bip01_Pelvis",
|
|
||||||
"ValveBiped.Bip01_Spine2",
|
|
||||||
"ValveBiped.Bip01_Head1",
|
|
||||||
"ValveBiped.Bip01_R_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Foot",
|
|
||||||
"ValveBiped.Bip01_L_Foot",
|
|
||||||
"ValveBiped.Bip01_R_Upperarm",
|
|
||||||
"ValveBiped.Bip01_L_Upperarm",
|
|
||||||
"ValveBiped.Bip01_R_Forearm",
|
|
||||||
"ValveBiped.Bip01_L_Forearm",
|
|
||||||
"ValveBiped.Bip01_R_Hand",
|
|
||||||
"ValveBiped.Bip01_L_Hand",
|
|
||||||
}
|
|
||||||
|
|
||||||
function ENT:Initialize()
|
|
||||||
if SERVER then
|
|
||||||
print("I AM SERVERSIDE")
|
|
||||||
self:SetModel("models/dav0r/hoverball.mdl")
|
|
||||||
end
|
|
||||||
|
|
||||||
if CLIENT then
|
|
||||||
print("I AM CLIENTSIDE")
|
|
||||||
timer.Simple(0.2, function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Draw()
|
|
||||||
if CLIENT then
|
|
||||||
local old_ragdoll = self:GetNWEntity("parent")
|
|
||||||
if IsValid(old_ragdoll) then
|
|
||||||
if !self.ready_to_unfake then
|
|
||||||
self:SetModel(old_ragdoll:GetModel())
|
|
||||||
|
|
||||||
self.bone_list = {}
|
|
||||||
self.bone_original_positions = {}
|
|
||||||
|
|
||||||
self:SetupBones()
|
|
||||||
|
|
||||||
for i,name in pairs(bones_to_animate) do
|
|
||||||
local bone_index = old_ragdoll:LookupBone(name)
|
|
||||||
|
|
||||||
self.bone_list[name] = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
self.bone_original_positions[name] = self:GetBoneMatrix(bone_index)
|
|
||||||
end
|
|
||||||
|
|
||||||
print("BONES:"..self:GetBoneCount())
|
|
||||||
|
|
||||||
self.ready_to_unfake = true
|
|
||||||
end
|
|
||||||
|
|
||||||
self:SetPos(old_ragdoll:GetPos())
|
|
||||||
|
|
||||||
for name,matrix in pairs(self.bone_list) do
|
|
||||||
local bone_index = self:LookupBone(name)
|
|
||||||
if bone_index == -1 then
|
|
||||||
print(name.." does not exist, skipping...")
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
print(name)
|
|
||||||
--local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
|
|
||||||
local original_position = self.bone_original_positions[name]:GetTranslation()
|
|
||||||
local goal_position = matrix:GetTranslation()
|
|
||||||
|
|
||||||
print((original_position - goal_position))
|
|
||||||
|
|
||||||
self:ManipulateBonePosition(bone_index, Vector(0, 0, 16))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:DrawModel()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Think()
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:OnRemove()
|
|
||||||
if CLIENT then
|
|
||||||
if self.anim_ragdoll then
|
|
||||||
self.anim_ragdoll:Remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
AddCSLuaFile()
|
|
||||||
|
|
||||||
ENT.Type = "anim"
|
|
||||||
ENT.Base = "base_anim"
|
|
||||||
ENT.AutomaticFrameAdvance = true
|
|
||||||
|
|
||||||
local bones_to_animate = {
|
|
||||||
"ValveBiped.Bip01_Pelvis",
|
|
||||||
"ValveBiped.Bip01_Spine2",
|
|
||||||
"ValveBiped.Bip01_Head1",
|
|
||||||
"ValveBiped.Bip01_R_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Thigh",
|
|
||||||
"ValveBiped.Bip01_L_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Calf",
|
|
||||||
"ValveBiped.Bip01_R_Foot",
|
|
||||||
"ValveBiped.Bip01_L_Foot",
|
|
||||||
"ValveBiped.Bip01_R_Upperarm",
|
|
||||||
"ValveBiped.Bip01_L_Upperarm",
|
|
||||||
"ValveBiped.Bip01_R_Forearm",
|
|
||||||
"ValveBiped.Bip01_L_Forearm",
|
|
||||||
"ValveBiped.Bip01_R_Hand",
|
|
||||||
"ValveBiped.Bip01_L_Hand",
|
|
||||||
}
|
|
||||||
|
|
||||||
function ENT:Initialize()
|
|
||||||
if SERVER then
|
|
||||||
print("I AM SERVERSIDE")
|
|
||||||
self:SetModel("models/dav0r/hoverball.mdl")
|
|
||||||
end
|
|
||||||
|
|
||||||
if CLIENT then
|
|
||||||
print("I AM CLIENTSIDE")
|
|
||||||
timer.Simple(0.2, function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Draw()
|
|
||||||
if CLIENT then
|
|
||||||
local old_ragdoll = self:GetNWEntity("parent")
|
|
||||||
if IsValid(old_ragdoll) then
|
|
||||||
if !self.ready_to_unfake then
|
|
||||||
self.ragdoll = ClientsideModel(old_ragdoll:GetModel())
|
|
||||||
self.ragdoll:SetModel(old_ragdoll:GetModel())
|
|
||||||
|
|
||||||
self.bone_list = {}
|
|
||||||
|
|
||||||
self.ragdoll:SetupBones()
|
|
||||||
|
|
||||||
for i,name in pairs(bones_to_animate) do
|
|
||||||
local bone_index = old_ragdoll:LookupBone(name)
|
|
||||||
|
|
||||||
self.bone_list[name] = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
end
|
|
||||||
|
|
||||||
print("BONES:"..self.ragdoll:GetBoneCount())
|
|
||||||
|
|
||||||
self.ready_to_unfake = true
|
|
||||||
end
|
|
||||||
|
|
||||||
self.ragdoll:SetPos(old_ragdoll:GetPos())
|
|
||||||
|
|
||||||
for name,matrix in pairs(self.bone_list) do
|
|
||||||
local bone_index = self.ragdoll:LookupBone(name)
|
|
||||||
if bone_index == -1 then
|
|
||||||
print(name.." does not exist, skipping...")
|
|
||||||
continue
|
|
||||||
end
|
|
||||||
|
|
||||||
print(name)
|
|
||||||
--local bone_matrix = old_ragdoll:GetBoneMatrix(bone_index)
|
|
||||||
|
|
||||||
self.ragdoll:SetBoneMatrix(bone_index, matrix)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
self:DrawModel()
|
|
||||||
self.ragdoll:DrawModel()
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:Think()
|
|
||||||
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ENT:OnRemove()
|
|
||||||
if CLIENT then
|
|
||||||
if self.anim_ragdoll then
|
|
||||||
self.anim_ragdoll:Remove()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -128,16 +128,14 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll)
|
||||||
end
|
end
|
||||||
|
|
||||||
if ent.npcfakeknockback then
|
if ent.npcfakeknockback then
|
||||||
if dmgpos and (phys_bone != -1) then
|
ragdoll:GetPhysicsObject():SetVelocity(ent.npcfakeknockback)
|
||||||
local phys = ragdoll:GetPhysicsObjectNum(phys_bone)
|
|
||||||
phys:SetVelocity(ent.npcfakeknockback)
|
|
||||||
else
|
|
||||||
ragdoll:GetPhysicsObject():SetVelocity(ent.npcfakeknockback)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local velocity = ragdoll:GetPhysicsObject():GetVelocity()
|
local velocity = ragdoll:GetPhysicsObject():GetVelocity()
|
||||||
|
|
||||||
|
print(velocity)
|
||||||
|
print(max_clamp)
|
||||||
|
|
||||||
-- For some reason, citizen types such as rebels, medics, refugees, etc. use a keyvalue.
|
-- For some reason, citizen types such as rebels, medics, refugees, etc. use a keyvalue.
|
||||||
-- That keyvalue does not transfer over to the ragdoll, despite it looking like the NPC,
|
-- That keyvalue does not transfer over to the ragdoll, despite it looking like the NPC,
|
||||||
-- and you have to manually save it to the ragdoll to be able to make it work.
|
-- and you have to manually save it to the ragdoll to be able to make it work.
|
||||||
|
|
@ -165,6 +163,7 @@ hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo)
|
||||||
if dmginfo:IsDamageType(DMG_BULLET + DMG_BUCKSHOT + DMG_BLAST + DMG_CLUB + DMG_SLASH + DMG_GENERIC) then
|
if dmginfo:IsDamageType(DMG_BULLET + DMG_BUCKSHOT + DMG_BLAST + DMG_CLUB + DMG_SLASH + DMG_GENERIC) then
|
||||||
-- Reset ragdoll get up timer -- don't want someone getting up mid-curbstomp
|
-- Reset ragdoll get up timer -- don't want someone getting up mid-curbstomp
|
||||||
ent.StartDie = CurTime()
|
ent.StartDie = CurTime()
|
||||||
|
print("I'M HIT FOR "..dmginfo:GetDamage())
|
||||||
end
|
end
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
@ -177,18 +176,20 @@ hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo)
|
||||||
if dmginfo:GetDamage() > 3 then
|
if dmginfo:GetDamage() > 3 then
|
||||||
table.insert(npcs_to_fake, ent)
|
table.insert(npcs_to_fake, ent)
|
||||||
|
|
||||||
--local attacker_angle = dmginfo:GetAttacker():EyeAngles()
|
local attacker_angle = dmginfo:GetAttacker():EyeAngles()
|
||||||
|
|
||||||
--local normal = attacker_angle:Forward(normal)
|
local normal = attacker_angle:Forward(normal)
|
||||||
|
|
||||||
--ent.npcfakeknockback = normal * 7 * 3
|
ent.npcfakeknockback = normal * dmginfo:GetDamage() * 0
|
||||||
end
|
end
|
||||||
elseif dmginfo:IsDamageType(DMG_CLUB + DMG_SLASH) then
|
elseif dmginfo:IsDamageType(DMG_CLUB + DMG_SLASH) then
|
||||||
local attacker = dmginfo:GetAttacker()
|
local attacker = dmginfo:GetAttacker()
|
||||||
if !IsValid(attacker) then return end
|
if !IsValid(attacker) then return end
|
||||||
|
|
||||||
local fists = attacker:HasWeapon("weapon_hands_sh")
|
local fists = attacker:HasWeapon("weapon_hands_sh")
|
||||||
if !fists then fists = attacker:HasWeapon("weapon_hg_coolhands") end
|
if !fists then fists = dmginfo:GetAttacker():HasWeapon("weapon_hg_coolhands") end
|
||||||
|
|
||||||
|
local attacker = dmginfo:GetAttacker()
|
||||||
|
|
||||||
-- Kicks should knock NPCs down
|
-- Kicks should knock NPCs down
|
||||||
if IsValid(dmginfo:GetInflictor()) and fists and attacker.InLegKick and ((attacker.InLegKick + 0.1) > CurTime()) then
|
if IsValid(dmginfo:GetInflictor()) and fists and attacker.InLegKick and ((attacker.InLegKick + 0.1) > CurTime()) then
|
||||||
|
|
@ -199,8 +200,6 @@ hook.Add("HomigradDamage", "zcnpci", function(ent, dmginfo)
|
||||||
local normal = attacker_angle:Forward(normal)
|
local normal = attacker_angle:Forward(normal)
|
||||||
|
|
||||||
ent.npcfakeknockback = normal * dmginfo:GetDamage() * 135
|
ent.npcfakeknockback = normal * dmginfo:GetDamage() * 135
|
||||||
|
|
||||||
last_dmgpos[ent] = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
|
||||||
|
|
@ -100,9 +100,6 @@ local minimum_down_time = CreateConVar("zcnpci_down_time", "5", {FCVAR_ARCHIVE,
|
||||||
local can_unfake = CreateConVar("zcnpci_unfake_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Whether an NPC can unfake")
|
local can_unfake = CreateConVar("zcnpci_unfake_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Whether an NPC can unfake")
|
||||||
local unfake_time = CreateConVar("zcnpci_unfake_time", "1.5", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Time it takes for an NPC to unfake")
|
local unfake_time = CreateConVar("zcnpci_unfake_time", "1.5", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Time it takes for an NPC to unfake")
|
||||||
|
|
||||||
-- Targeting
|
|
||||||
local npc_targeting_enabled = CreateConVar("zcnpci_npc_targeting_enabled", "1", {FCVAR_ARCHIVE, FCVAR_REPLICATED}, "Should NPCs target downed NPCs")
|
|
||||||
|
|
||||||
--[[-------------------------------------------------------------------------
|
--[[-------------------------------------------------------------------------
|
||||||
Tug function
|
Tug function
|
||||||
Applies a random impulse to one of the leg bones.
|
Applies a random impulse to one of the leg bones.
|
||||||
|
|
@ -198,7 +195,6 @@ function MODULE:Init()
|
||||||
self.StopProcessing = false
|
self.StopProcessing = false
|
||||||
self.LastThink = CurTime()
|
self.LastThink = CurTime()
|
||||||
self.LastFakeUpCheck = CurTime()
|
self.LastFakeUpCheck = CurTime()
|
||||||
self.LastPosCheck = target:GetPos()
|
|
||||||
|
|
||||||
self.bullseye = ents.Create("npc_ragdoll_target")
|
self.bullseye = ents.Create("npc_ragdoll_target")
|
||||||
self.bullseye:SetPos(target:GetPos())
|
self.bullseye:SetPos(target:GetPos())
|
||||||
|
|
@ -237,6 +233,7 @@ function MODULE:Think()
|
||||||
local phys = target:GetPhysicsObject()
|
local phys = target:GetPhysicsObject()
|
||||||
|
|
||||||
if target.FakeUp then
|
if target.FakeUp then
|
||||||
|
print("fucking it")
|
||||||
local parent = self.FakeParent
|
local parent = self.FakeParent
|
||||||
if !IsValid(parent) then return end
|
if !IsValid(parent) then return end
|
||||||
|
|
||||||
|
|
@ -297,8 +294,6 @@ end
|
||||||
Physics Simulation Hook (FIXED)
|
Physics Simulation Hook (FIXED)
|
||||||
---------------------------------------------------------------------------]]
|
---------------------------------------------------------------------------]]
|
||||||
function MODULE:PhysicsSimulate(phys, dt)
|
function MODULE:PhysicsSimulate(phys, dt)
|
||||||
if !SERVER then return end
|
|
||||||
|
|
||||||
local cur_time = CurTime()
|
local cur_time = CurTime()
|
||||||
local target = self:GetTarget()
|
local target = self:GetTarget()
|
||||||
if not IsValid(target) then self:Remove(); self.bullseye:Remove(); return false end
|
if not IsValid(target) then self:Remove(); self.bullseye:Remove(); return false end
|
||||||
|
|
@ -331,6 +326,7 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
local animation_progress = (CurTime() - self.FakeUpStart) / (self.FakeUpEnd - self.FakeUpStart)
|
local animation_progress = (CurTime() - self.FakeUpStart) / (self.FakeUpEnd - self.FakeUpStart)
|
||||||
|
|
||||||
for i, name in pairs(fakeup_bone_names) do
|
for i, name in pairs(fakeup_bone_names) do
|
||||||
|
print(name)
|
||||||
local object = target:GetPhysicsObjectNum(target:TranslateBoneToPhysBone(target:LookupBone(name)))
|
local object = target:GetPhysicsObjectNum(target:TranslateBoneToPhysBone(target:LookupBone(name)))
|
||||||
local parent_bone = parent:LookupBone(name)
|
local parent_bone = parent:LookupBone(name)
|
||||||
|
|
||||||
|
|
@ -391,23 +387,20 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
|
|
||||||
if !target.organism then
|
if !target.organism then
|
||||||
self:Remove()
|
self:Remove()
|
||||||
|
self.bullseye:Remove()
|
||||||
return false -- Cut the bullshit
|
return false -- Cut the bullshit
|
||||||
end
|
end
|
||||||
|
|
||||||
if (!target.organism.alive) then
|
if (!target.organism.alive) then
|
||||||
-- If the NPC is dead, they probably aren't coming back; don't bother bringing them back to life
|
-- If the NPC is dead, they probably aren't coming back; don't bother bringing them back to life
|
||||||
self:Remove()
|
self:Remove()
|
||||||
|
self.bullseye:Remove()
|
||||||
return false -- Cut the bullshit
|
return false -- Cut the bullshit
|
||||||
elseif (target.organism.consciousness <= 0.5) or ((target.organism.lleg >= 0.85) and (target.organism.rleg >= 0.85)) then
|
elseif (target.organism.consciousness <= 0.5) or ((target.organism.lleg >= 0.85) and (target.organism.rleg >= 0.85)) then
|
||||||
target.StartDie = cur_time
|
target.StartDie = cur_time
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
if (self.LastPosCheck:DistToSqr(target:GetPos()) > (32 ^ 2)) then
|
|
||||||
self.LastPosCheck = target:GetPos()
|
|
||||||
target.StartDie = cur_time
|
|
||||||
end
|
|
||||||
|
|
||||||
if ((CurTime() - self.LastFakeUpCheck) >= 1.0) and (can_unfake:GetBool()) then
|
if ((CurTime() - self.LastFakeUpCheck) >= 1.0) and (can_unfake:GetBool()) then
|
||||||
self.LastFakeUpCheck = CurTime()
|
self.LastFakeUpCheck = CurTime()
|
||||||
|
|
||||||
|
|
@ -472,9 +465,6 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
for i = 0, target:GetNumBodyGroups() - 1 do
|
for i = 0, target:GetNumBodyGroups() - 1 do
|
||||||
ent:SetBodygroup(i, target:GetBodygroup(i))
|
ent:SetBodygroup(i, target:GetBodygroup(i))
|
||||||
end
|
end
|
||||||
|
|
||||||
self.unfaker:Spawn()
|
|
||||||
self.unfaker:Activate()
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
target.FakeUp = true
|
target.FakeUp = true
|
||||||
|
|
@ -490,13 +480,6 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
target:SetNotSolid(true)
|
target:SetNotSolid(true)
|
||||||
target:SetMoveType(MOVETYPE_NONE)
|
target:SetMoveType(MOVETYPE_NONE)
|
||||||
|
|
||||||
self.unfaker = ents.Create("npc_ragdoll_unfaker")
|
|
||||||
self.unfaker:SetPos(target:GetPos())
|
|
||||||
self.unfaker:SetNWEntity("parent", target)
|
|
||||||
self.unfaker:SetNWEntity("parent_npc", ent)
|
|
||||||
|
|
||||||
|
|
||||||
target:SetRenderMode(RENDERMODE_NONE)
|
|
||||||
ent:SetRenderMode(RENDERMODE_NONE)
|
ent:SetRenderMode(RENDERMODE_NONE)
|
||||||
|
|
||||||
timer.Simple(self.FakeUpTime, function()
|
timer.Simple(self.FakeUpTime, function()
|
||||||
|
|
@ -512,6 +495,7 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
self:Remove()
|
self:Remove()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
self.bullseye:Remove()
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
@ -582,7 +566,7 @@ function MODULE:OnRemove()
|
||||||
local timer_name = "Fedhoria_FallingLegs_Twitch_" .. self:EntIndex()
|
local timer_name = "Fedhoria_FallingLegs_Twitch_" .. self:EntIndex()
|
||||||
timer_Remove(timer_name)
|
timer_Remove(timer_name)
|
||||||
|
|
||||||
if IsValid(self.unfaker) then self.unfaker:Remove() end
|
if IsValid(self.bullseye) then self.bullseye:Remove() end
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[-------------------------------------------------------------------------
|
--[[-------------------------------------------------------------------------
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue