Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

C4 Damage Rework #1738

Closed
wants to merge 14 commits into from
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ All notable changes to TTT2 will be documented here. Inspired by [keep a changel
- Added option to use right click to enable/disable roles in the role layering menu (by @TimGoll)
- Added option to enable team name next to role name on the HUD (by @milkwxter)
- Added score event for winning with configurable role parameter (by @MrXonte)
- Added ExplosiveSphereDamage game effect for easy calculation of explosion damage through walls (by @MrXonte)

### Fixed

Expand Down Expand Up @@ -59,6 +60,7 @@ All notable changes to TTT2 will be documented here. Inspired by [keep a changel
- Moved all role-related admin options into the "Roles" menu (by @nike4613)
- Improved description of role layering (by @nike4613)
- Improved the role layering menu by showing which role is enabled and which is disabled (by @TimGoll)
- Reworked C4 damage calculation with new gameEffect ExplosiveSphereDamage (by @MrXonte)

## [v0.14.0b](https://github.com/TTT-2/TTT2/tree/v0.14.0b) (2024-09-20)

Expand Down
63 changes: 9 additions & 54 deletions gamemodes/terrortown/entities/entities/ttt_c4/shared.lua
Original file line number Diff line number Diff line change
Expand Up @@ -145,55 +145,6 @@ function ENT.SafeWiresForTime(t)
end
end

---
-- @param Entity dmgowner
-- @param Vector center
-- @param number radius
-- @realm shared
function ENT:SphereDamage(dmgowner, center, radius)
-- It seems intuitive to use FindInSphere here, but that will find all ents
-- in the radius, whereas there exist only ~16 players. Hence it is more
-- efficient to cycle through all those players and do a Lua-side distance
-- check.

local r = radius * radius -- square so we can compare with dot product directly

-- pre-declare to avoid realloc
local d = 0.0
local diff = nil
local dmg = 0

local plys = playerGetAll()
for i = 1, #plys do
local ply = plys[i]
if ply:Team() ~= TEAM_TERROR then
continue
end

-- dot of the difference with itself is distance squared
diff = center - ply:GetPos()
d = diff:Dot(diff)

if d >= r then
continue
end

-- deadly up to a certain range, then a quick falloff within 100 units
d = math.max(0, math.sqrt(d) - 490)
dmg = -0.01 * (d * d) + 125

local dmginfo = DamageInfo()
dmginfo:SetDamage(dmg)
dmginfo:SetAttacker(dmgowner)
dmginfo:SetInflictor(self)
dmginfo:SetDamageType(DMG_BLAST)
dmginfo:SetDamageForce(center - ply:GetPos())
dmginfo:SetDamagePosition(ply:GetPos())

ply:TakeDamageInfo(dmginfo)
end
end

local c4boom = Sound("c4.explode")

---
Expand Down Expand Up @@ -244,11 +195,15 @@ function ENT:Explode(tr)
r_outer = r_outer / 2.5
end

-- damage through walls
self:SphereDamage(dmgowner, pos, r_inner)

-- explosion damage
util.BlastDamage(self, dmgowner, pos, r_outer, self:GetDmg())
gameEffects.ExplosiveSphereDamage(
dmgowner,
self,
self:GetDmg(),
pos,
r_outer,
r_inner,
true
)

local effect = EffectData()
effect:SetStart(pos)
Expand Down
69 changes: 68 additions & 1 deletion lua/ttt2/libraries/game_effects.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,73 @@ function gameEffects.RadiusDamage(dmginfo, pos, radius, inflictor)
end
end

-- Creates explosion damage in a sphere through walls. Very useful for making explosives that aren't line of sight based.
-- @param Player dmgowner The player that causes this explosion.
-- @param Entity source The entity that causes this explosion.
-- @param number damage The maximum damage done by this explosion.
-- @param Vector origin The center of the explosion.
-- @param number outerRadius The outer border for the explosion damage and its falloff.
-- @param number innerRadius The inner border for the explosion damage where falloff starts.
-- @param boolean exponentialFalloff If the damage falloff should be FALSE: Linear, TRUE: exponential.
-- @internal
-- @realm server
function gameEffects.ExplosiveSphereDamage(
dmgowner,
source,
damage,
origin,
outerRadius,
innerRadius,
exponentialFalloff
)
-- It seems intuitive to use FindInSphere here, but that will find all ents
-- in the radius, whereas there exist only ~16 players. Hence it is more
-- efficient to cycle through all those players and do a Lua-side distance
-- check.

if outerRadius < innerRadius then
ErrorNoHalt(
"[Game Effects Explosive Sphere Damage] Outer radius too high! Setting both radi to outer radius."
)
innerRadius = outerRadius
end

-- pre-declare to avoid realloc
local d = 0.0
local dFraction = 0.0
local diff = nil
local dmg = 0
local radiDiff = (outerRadius - innerRadius)
for _, ply in pairs(player.GetAll()) do
if IsValid(ply) and ply:Team() == TEAM_TERROR then
diff = origin - ply:GetPos()
--we are using Length on purpose here. We would need a sqrt somewhere anyway and with this we dont need to square the radi
d = diff:Length()
--we now turn this into a % of damage based of the value of d
--100% from 0 to innerRadius
--100% to 0% from innerRadius to outerRadius
--<0% from outerRadius to infinity
dFraction = 1.0 - math.max((d - innerRadius) / radiDiff, 0.0)

--Next Iteration if we are outside the radius
if dFraction < 0.0 then
continue
end

dmg = math.Round(damage * dFraction * ((exponentialFalloff and dFraction) or 1))

local dmginfo = DamageInfo()
dmginfo:SetDamage(dmg)
dmginfo:SetAttacker(dmgowner)
dmginfo:SetInflictor(source)
dmginfo:SetDamageType(DMG_BLAST)
dmginfo:SetDamageForce(diff)
dmginfo:SetDamagePosition(ply:GetPos())
ply:TakeDamageInfo(dmginfo)
end
end
end

-- vFIRE INTEGRATION

if SERVER then
Expand Down Expand Up @@ -185,4 +252,4 @@ if SERVER then
hook.Remove("EntityTakeDamage", "vFireFixExplosion")
hook.Add("EntityTakeDamage", "vFireFixExplosionReplacement", vFireTakeDamageReplacement)
end)
end
end
Loading