Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions prophealth/cl_plugin.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
local PLUGIN = PLUGIN

local math_floor = math.floor
local math_max = math.max

local function PropHealthThink(row)
local entity = row.ixEntity
local tooltip = row.ixTooltip

if (not IsValid(entity)) then return end

-- Fetch vars
local hp = math_max(0, entity:GetNetVar("propHP", 0))
local maxHP = entity:GetNetVar("propMaxHP", 100)

if (row.ixLastHP == hp and row.ixLastMax == maxHP) then return end

-- Update cache
row.ixLastHP = hp
row.ixLastMax = maxHP

-- Update UI
local text = L("propHealth") .. ": " .. math_floor(hp) .. " / " .. math_floor(maxHP)
row:SetText(text)
row:SizeToContents()

if (tooltip) then tooltip:SizeToContents() end
end

function PLUGIN:PopulateEntityInfo(entity, tooltip)
-- Check class string first (fastest check)
if (entity:GetClass() ~= "prop_physics") then return end

-- Check NetVar existence
if (not entity:GetNetVar("propHP")) then return end

local row = tooltip:AddRow("health")
row:SetBackgroundColor(Color(200, 50, 50))

-- Store references on the panel object itself
row.ixEntity = entity
row.ixTooltip = tooltip

-- Initialize cache variables
row.ixLastHP = -1
row.ixLastMax = -1

-- Assign the static Think function (Zero allocation)
row.Think = PropHealthThink
PropHealthThink(row)
end
75 changes: 75 additions & 0 deletions prophealth/sh_plugin.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
local PLUGIN = PLUGIN

PLUGIN.name = "Prop Health"
PLUGIN.author = "Max_auCube"
PLUGIN.description = "Add HP to props."

PLUGIN.license = [[

MIT License

Copyright (c) 2026 Max_auCube

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

]]

PLUGIN.readme = [[
Prop Health Plugin for Helix

This lightweight plugin adds a dynamic health and destruction system to all physics props.

Features:

- Mass-Based Health: A prop's maximum health is automatically calculated based on its physical weight (Mass * Config Multiplier). Heavier objects like concrete barriers are much harder to destroy than wooden crates.

- Explosive Destruction: When health reaches zero, the prop creates an explosion effect before being removed. **Can be Disabled**

- Real-Time Tooltip: Looking at a prop displays a live health counter in the standard Helix interaction menu that updates instantly during combat.

Configuration: You can adjust 'propsMinHP' (default 50) and 'propsHPMultiplier' (default 5) in your server configuration to balance durability.

*AI usage note: Code quality improvements.*
]]

ix.util.Include("sv_plugin.lua")
ix.util.Include("cl_plugin.lua")

ix.lang.AddTable("english", {
propHealth = "Health"
})

ix.lang.AddTable("french", {
propHealth = "Santé"
})

ix.config.Add("propsHPMultiplier", 5, "Multiplier for props HP.", nil, {
data = {min = 0, max = 10},
category = "Prop Health"
})

ix.config.Add("propsMinHP", 50, "Minimal HP for props.", nil, {
data = {min = 0, max = 1000},
category = "Prop Health"
})

ix.config.Add("propsExplode", true, "Toggles explosion effects on prop destruction.", nil, {
category = "Prop Health"
})

60 changes: 60 additions & 0 deletions prophealth/sv_plugin.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
local PLUGIN = PLUGIN

-- Helper function: Initializes HP and returns the value
-- Returns: maxHP (number)
local function InitPropHealth(entity)
local minHP = ix.config.Get("propsMinHP", 50)
local multiplier = ix.config.Get("propsHPMultiplier", 5)
local phys = entity:GetPhysicsObject()

local hp = minHP

if (IsValid(phys)) then
hp = math.max(minHP, phys:GetMass() * multiplier)
end

-- Sync both Max and Current HP
entity:SetNetVar("propMaxHP", hp)
entity:SetNetVar("propHP", hp)

return hp
end

function PLUGIN:EntityTakeDamage(entity, dmgInfo)
-- Filter: Only physics props, ignore map props
if (entity:GetClass() ~= "prop_physics") then return end
if (entity:CreatedByMap()) then return end

-- Fetch current state
local curHP = entity:GetNetVar("propHP")
local maxHP = entity:GetNetVar("propMaxHP")

-- Lazy Initialization (if prop spawned before plugin was added or bug)
if (not curHP) then
maxHP = InitPropHealth(entity)
curHP = maxHP
end

-- Calculate Damage
curHP = curHP - dmgInfo:GetDamage()

-- State Handling
if (curHP <= 0) then
-- Destruction
if (ix.config.Get("propsExplode", false)) then
local effectData = EffectData()
effectData:SetOrigin(entity:GetPos())
util.Effect("Explosion", effectData)
end

entity:Remove()
else
-- Apply Health Update
entity:SetNetVar("propHP", curHP)
end
end

-- Optimization: Pre-calculate HP on spawn to avoid overhead during combat
function PLUGIN:PlayerSpawnedProp(client, model, entity)
InitPropHealth(entity)
end