Modded & extended NPC support for organisms, new menu tabs, unconsciousness force multiplier
This commit is contained in:
parent
66f34f8aa1
commit
b56cbd1d24
5 changed files with 140 additions and 25 deletions
18
README.md
18
README.md
|
|
@ -2,22 +2,26 @@
|
||||||
|
|
||||||
Adds better NPC integration for the Garry's Mod addon Z-City. While Z-City has a convar that enables the custom health system on NPCs, it really isn't the best or most advanced thing in the world. This has irritated me since I first started using Z-City. Therefore, I've decided to take care of the problem myself with my own plugin.
|
Adds better NPC integration for the Garry's Mod addon Z-City. While Z-City has a convar that enables the custom health system on NPCs, it really isn't the best or most advanced thing in the world. This has irritated me since I first started using Z-City. Therefore, I've decided to take care of the problem myself with my own plugin.
|
||||||
|
|
||||||
- NPCs can now be alive while ragdolled, and can move around in that state.
|
- NPCs can be ragdolled like players can, and will wiggle around on the ground. They can get back up, too!
|
||||||
- NPCs can collapse due to unconsciousness or pain.
|
- It takes all elements of Z-City's health system into account, such as unconsciousness and pain.
|
||||||
- NPCs can get back up after being ragdolled.
|
- Various configurable settings are included, allowing you to tweak the mod to your liking.
|
||||||
- Various configurableperformance settings are included, with the biggest one being automatic corpse removal.
|
|
||||||
|
|
||||||
This plugin is based off of Kazarei's Euphoria, which in turn is a fork of Fedhoria by Rama. Credits to them for making the cool thing.
|
This mod is built to perform reasonably well, thus it includes optimizations, configurable performance settings, and an automatic corpse remover.
|
||||||
|
|
||||||
|
This addon is based off of Kazarei's Euphoria, which in turn is a fork of Fedhoria by Rama. Credits to them for making the cool thing.
|
||||||
|
|
||||||
## Known issues
|
## Known issues
|
||||||
|
|
||||||
- Kicking NPCs does not knock them down. The same goes for many melee attacks. This is not something I can easily fix -- I would have to override code in Z-City, which I would rather not do.
|
- Kicking NPCs does not knock them down. The same goes for many melee attacks. This is not something I know how to easily fix -- I would have to override code in Z-City, which I would rather not do. If you do know how to easily fix this, reach out, I would love to add it.
|
||||||
|
- Bandages, tourniquets, etc. that are on the ragdoll or NPC body will not be there when they get back up.
|
||||||
|
|
||||||
- NPCs currently instantly get up, with no animation. I plan on remedying this in the future.
|
- NPCs currently instantly get up, with no animation. I plan on remedying this in the future.
|
||||||
- Enemy NPCs will not target living downed NPCs. This is an issue I plan on fixing.
|
- Enemy NPCs will not target living downed NPCs like how they do players. This will be fixed.
|
||||||
|
|
||||||
## Incompatibilities
|
## Incompatibilities
|
||||||
|
|
||||||
- Any mod that modifies the behavior of death ragdolls (Reagdoll, Artagdoll, Fedhoria)
|
- Any mod that modifies the behavior of death ragdolls (Reagdoll, Artagdoll, Fedhoria)
|
||||||
|
- Mods that automatically remove death ragdolls (it will delete all ragdolled NPCs, even if they're still alive! Try the built-in automatic corpse removal instead.)
|
||||||
|
|
||||||
## Future plans
|
## Future plans
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,34 @@
|
||||||
|
local function PopulateCustomNPCSBXToolMenu(pnl)
|
||||||
|
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: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:CheckBox("Allow modded NPCs", "zcnpci_allow_modded_npcs")
|
||||||
|
pnl:ControlHelp("Enable or disables applying custom health system to modded NPCs.")
|
||||||
|
|
||||||
|
pnl:CheckBox("Auto enable for all humanoid NPCs", "zcnpci_auto_enable_humanoid_npcs")
|
||||||
|
pnl:ControlHelp("If enabled, NPCs will automatically have the health system applied to them if they have a standard humanoid skeleton.")
|
||||||
|
|
||||||
|
pnl:Help("List of enabled modded NPC classes")
|
||||||
|
|
||||||
|
local text = vgui.Create("DTextEntry")
|
||||||
|
text:SetMultiline(true)
|
||||||
|
text:SetTall(200)
|
||||||
|
text:SetValue(modded_npc_whitelist:GetString())
|
||||||
|
|
||||||
|
text.OnChange = function (self)
|
||||||
|
RunConsoleCommand("zcnpci_set_modded_npc_whitelist", text:GetValue())
|
||||||
|
end
|
||||||
|
|
||||||
|
pnl:AddItem(text)
|
||||||
|
|
||||||
|
pnl:Help("One NPC class per line. No spaces or other characters. Can only be set by a superadmin or server operator.")
|
||||||
|
end
|
||||||
|
|
||||||
local function PopulateRagdollSBXToolMenu(pnl)
|
local function PopulateRagdollSBXToolMenu(pnl)
|
||||||
pnl:CheckBox("Enabled", "zcnpci_enabled")
|
|
||||||
pnl:ControlHelp("Enable or disable the addon.")
|
|
||||||
|
|
||||||
pnl:Help(" ")
|
|
||||||
|
|
||||||
pnl:Help(" ")
|
|
||||||
|
|
||||||
pnl:NumSlider("Stumble time", "zcnpci_stumble_time", 0, 10, 3)
|
pnl:NumSlider("Stumble time", "zcnpci_stumble_time", 0, 10, 3)
|
||||||
pnl:ControlHelp("How long the ragdoll should try to stumble for.")
|
pnl:ControlHelp("How long the ragdoll should try to stumble for.")
|
||||||
|
|
||||||
|
|
@ -55,20 +78,40 @@ local function PopulatePerformanceSBXToolMenu(pnl)
|
||||||
pnl:ControlHelp("If on, bodies near death (severe blood loss, comas, etc.) will be clearable.")
|
pnl:ControlHelp("If on, bodies near death (severe blood loss, comas, etc.) will be clearable.")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function PopulateMainSBXToolMenu(pnl)
|
||||||
|
pnl:CheckBox("Enabled", "zcnpci_enabled")
|
||||||
|
pnl:ControlHelp("Enable or disable the addon.")
|
||||||
|
|
||||||
|
pnl:Help("This addon was developed by ToasterPanic.")
|
||||||
|
|
||||||
|
pnl:Help("It is based on Kazarei's Euphoria, which in turn is a fork of Fedhoria by Rama. Their work powers the ragdoll movement.")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
if engine.ActiveGamemode() == "sandbox" then
|
if engine.ActiveGamemode() == "sandbox" then
|
||||||
hook.Add("AddToolMenuCategories", "ZCNPCICategory", function()
|
hook.Add("AddToolMenuCategories", "ZCNPCICategory", function()
|
||||||
spawnmenu.AddToolCategory("Utilities", "zcnpci", "Z-City NPCi")
|
spawnmenu.AddToolCategory("Utilities", "zcnpci", "Z-City NPCi")
|
||||||
end)
|
end)
|
||||||
|
|
||||||
hook.Add("PopulateToolMenu", "ZCNPCIMenuSettings", function()
|
hook.Add("PopulateToolMenu", "ZCNPCIMenuSettings", function()
|
||||||
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "RagdollSettings", "Ragdoll", "", "", function(pnl)
|
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "ModdedNPCSettings", "Custom NPCs", "", "", function(pnl)
|
||||||
pnl:ClearControls()
|
pnl:ClearControls()
|
||||||
PopulateRagdollSBXToolMenu(pnl)
|
PopulateCustomNPCSBXToolMenu(pnl)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "PerformanceSettings", "Performance", "", "", function(pnl)
|
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "PerformanceSettings", "Performance", "", "", function(pnl)
|
||||||
pnl:ClearControls()
|
pnl:ClearControls()
|
||||||
PopulatePerformanceSBXToolMenu(pnl)
|
PopulatePerformanceSBXToolMenu(pnl)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "RagdollSettings", "Ragdoll", "", "", function(pnl)
|
||||||
|
pnl:ClearControls()
|
||||||
|
PopulateRagdollSBXToolMenu(pnl)
|
||||||
|
end)
|
||||||
|
|
||||||
|
spawnmenu.AddToolMenuOption("Utilities", "zcnpci", "MainSettings", "Main", "", "", function(pnl)
|
||||||
|
pnl:ClearControls()
|
||||||
|
PopulateMainSBXToolMenu(pnl)
|
||||||
|
end)
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
@ -14,12 +14,40 @@ local treat_crippled_as_dead = CreateConVar("zcnpci_treat_crippled_as_dead", 1,
|
||||||
local treat_unconscious_as_dead = CreateConVar("zcnpci_treat_unconscious_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
local treat_unconscious_as_dead = CreateConVar("zcnpci_treat_unconscious_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
local treat_near_death_as_dead = CreateConVar("zcnpci_treat_near_death_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
local treat_near_death_as_dead = CreateConVar("zcnpci_treat_near_death_as_dead", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
|
||||||
|
local allow_extended_base_npcs = CreateConVar("zcnpci_allow_extended_base_npcs", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
local allow_modded_npcs = CreateConVar("zcnpci_allow_modded_npcs", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
local auto_enable_humanoid_npcs = CreateConVar("zcnpci_auto_enable_humanoid_npcs", 1, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
local modded_npc_whitelist = CreateConVar("zcnpci_modded_npc_whitelist", "NPC-classes-here!", bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
|
||||||
|
-- The way I have to set up the npc whitelist client-side makes it so the host can't configure it without console commands, so we have to do this shit
|
||||||
|
local set_modded_npc_whitelist = concommand.Add("zcnpci_set_modded_npc_whitelist", function(ply, cmd, args)
|
||||||
|
if !IsValid(ply) or !args[1] then return end
|
||||||
|
|
||||||
|
if !ply:IsSuperAdmin() then return end
|
||||||
|
|
||||||
|
modded_npc_whitelist:SetString(args[1])
|
||||||
|
end)
|
||||||
|
|
||||||
local debug_ragdoll_all = CreateConVar("zcnpci_debug_ragdoll_all", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
local debug_ragdoll_all = CreateConVar("zcnpci_debug_ragdoll_all", 0, bit.bor(FCVAR_ARCHIVE, FCVAR_REPLICATED))
|
||||||
|
|
||||||
local last_dmgpos = {}
|
local last_dmgpos = {}
|
||||||
local last_hitgroup = {}
|
local last_hitgroup = {}
|
||||||
local last_attacker = {}
|
local last_attacker = {}
|
||||||
|
|
||||||
|
-- These NPCs do not have organisms by default, despite being humanoid characters built into the game.
|
||||||
|
local base_npc_whitelist = {
|
||||||
|
"npc_kleiner",
|
||||||
|
"npc_breen",
|
||||||
|
"npc_barney",
|
||||||
|
"npc_alyx",
|
||||||
|
"npc_eli",
|
||||||
|
"npc_gman",
|
||||||
|
"npc_magnusson",
|
||||||
|
"npc_mossman",
|
||||||
|
"npc_odessa",
|
||||||
|
"npc_monk"
|
||||||
|
}
|
||||||
|
|
||||||
local corpses = {}
|
local corpses = {}
|
||||||
|
|
||||||
local last_corpse_tick = CurTime()
|
local last_corpse_tick = CurTime()
|
||||||
|
|
@ -68,6 +96,25 @@ hook.Add("CreateEntityRagdoll", "zcnpci", function(ent, ragdoll)
|
||||||
|
|
||||||
ragdoll.class_in_previous_life = ent:GetClass()
|
ragdoll.class_in_previous_life = ent:GetClass()
|
||||||
|
|
||||||
|
if !ragdoll.organism then
|
||||||
|
ragdoll.inventory = {}
|
||||||
|
ragdoll.inventory.Weapons = {}
|
||||||
|
|
||||||
|
hg.organism.Add(ragdoll)
|
||||||
|
table.Merge(ragdoll.organism, ent.organism)
|
||||||
|
|
||||||
|
hook.Run("RagdollDeath", ent, ragdoll)
|
||||||
|
|
||||||
|
--table.Merge(zb.net.list[rag], zb.net.list[ent])
|
||||||
|
|
||||||
|
ragdoll.organism.owner = ragdoll
|
||||||
|
ragdoll:CallOnRemove("organism", hg.organism.Remove, ragdoll)
|
||||||
|
ragdoll.organism.owner.fullsend = true
|
||||||
|
hg.send_bareinfo(ragdoll.organism)
|
||||||
|
|
||||||
|
ent.organism = nil
|
||||||
|
end
|
||||||
|
|
||||||
timer.Simple(0, function()
|
timer.Simple(0, function()
|
||||||
ragdoll.organism.alive = true
|
ragdoll.organism.alive = true
|
||||||
|
|
||||||
|
|
@ -209,6 +256,29 @@ end)
|
||||||
last_dmgpos[ent] = dmginfo:GetDamagePosition()
|
last_dmgpos[ent] = dmginfo:GetDamagePosition()
|
||||||
end)]]
|
end)]]
|
||||||
|
|
||||||
|
hook.Add("OnEntityCreated", "zcnpci", function(ent)
|
||||||
|
if !IsValid(ent) then return end
|
||||||
|
|
||||||
|
local add_organism = false
|
||||||
|
|
||||||
|
if allow_modded_npcs:GetBool() then
|
||||||
|
local modded_npc_whitelist_string = modded_npc_whitelist:GetString()
|
||||||
|
modded_npc_whitelist_string = string.Replace(modded_npc_whitelist_string, "\n", " ")
|
||||||
|
|
||||||
|
local modded_npc_whitelist_table = string.Split(modded_npc_whitelist_string, " ")
|
||||||
|
|
||||||
|
if table.HasValue(modded_npc_whitelist_table, ent:GetClass()) then add_organism = true end
|
||||||
|
end
|
||||||
|
|
||||||
|
if allow_extended_base_npcs:GetBool() and table.HasValue(base_npc_whitelist, ent:GetClass()) then add_organism = true end
|
||||||
|
|
||||||
|
if add_organism then
|
||||||
|
hg.organism.Add(ent)
|
||||||
|
hg.organism.Clear(ent.organism)
|
||||||
|
ent.organism.fakePlayer = true
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
local once = true
|
local once = true
|
||||||
|
|
||||||
--RagMod/TTT support
|
--RagMod/TTT support
|
||||||
|
|
|
||||||
|
|
@ -259,8 +259,8 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
return true -- We use standard physics.
|
return true -- We use standard physics.
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Logic for the disappearance timer
|
-- Force multiplier
|
||||||
local f = 1 -- Force multiplier (default: 1)
|
local f = target.organism.consciousness
|
||||||
|
|
||||||
local minimum_down_timer = 0
|
local minimum_down_timer = 0
|
||||||
if self.StartDie then
|
if self.StartDie then
|
||||||
|
|
@ -276,7 +276,7 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
-- 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()
|
||||||
return false -- Cut the bullshit
|
return false -- Cut the bullshit
|
||||||
elseif (target.organism.consciousness <= 0.3) 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
|
||||||
self.StartDie = cur_time
|
self.StartDie = cur_time
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
@ -288,6 +288,7 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
(target.class_in_previous_life != nil) and
|
(target.class_in_previous_life != nil) and
|
||||||
!(target.organism.llegamputated or target.organism.rlegamputated or target.organism.larmamputated or target.organism.rarmamputated) and
|
!(target.organism.llegamputated or target.organism.rlegamputated or target.organism.larmamputated or target.organism.rarmamputated) and
|
||||||
(target.organism.pain <= 80) and
|
(target.organism.pain <= 80) and
|
||||||
|
(target.organism.consciousness > 0.65) and
|
||||||
!target:IsOnFire()
|
!target:IsOnFire()
|
||||||
) then
|
) then
|
||||||
local ent = ents.Create(target.class_in_previous_life)
|
local ent = ents.Create(target.class_in_previous_life)
|
||||||
|
|
|
||||||
|
|
@ -180,11 +180,8 @@ function MODULE:PhysicsSimulate(phys, dt)
|
||||||
|
|
||||||
-- --- логика идет нахуй
|
-- --- логика идет нахуй
|
||||||
|
|
||||||
-- логика для таймера
|
-- Force multiplier
|
||||||
local f = 1 -- сила есть ума не надо (по умолчанию 1)
|
local f = target.organism.consciousness
|
||||||
--[[if self.StartDie then
|
|
||||||
f = math_Clamp(1 - (cur_time - self.StartDie) / die_time:GetFloat(), 0, 1)
|
|
||||||
end]]
|
|
||||||
|
|
||||||
-- ебаная логика для regmod
|
-- ебаная логика для regmod
|
||||||
if ragmod and ragmod:IsRagmodRagdoll(target) then
|
if ragmod and ragmod:IsRagmodRagdoll(target) then
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue