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 Rework #1739

Merged
merged 27 commits into from
Jan 29, 2025
Merged
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
3 changes: 3 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 All @@ -38,6 +39,7 @@ All notable changes to TTT2 will be documented here. Inspired by [keep a changel
- Fixed a few errors in shop error messages (by @Histalek)
- Fixed `markerVision`'s registry table being able to contain duplicate obsolete entries, thus fixing potential syncing issues with markers (by @TW1STaL1CKY)
- Fixed issue in new Ammo dropping that could cause an error when dropping for modified weapon bases. (by @MrXonte)
- Fixed C4 not showing the correct inflictor when the player is killed (by @TimGoll)

### Changed

Expand All @@ -59,6 +61,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
83 changes: 26 additions & 57 deletions gamemodes/terrortown/entities/entities/ttt_c4/shared.lua
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function ENT:Initialize()
end

if not self:GetRadius() then
self:SetRadius(1000)
self:SetRadius(1500)
end

if not self:GetDmg() then
Expand Down 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,14 @@ 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())
MrXonte marked this conversation as resolved.
Show resolved Hide resolved
gameEffects.ExplosiveSphereDamage(
dmgowner,
ents.Create("weapon_ttt_c4"),
self:GetDmg(),
pos,
r_outer,
r_inner
)

local effect = EffectData()
effect:SetStart(pos)
Expand Down Expand Up @@ -903,9 +857,24 @@ else -- CLIENT

local color = COLOR_WHITE

if mvData:GetEntityDistance() > ent:GetRadius() then
--Calculating damage falloff with inverse square method
--100% from 0 to innerRadius
--100% to 0% from innerRadius to outerRadius
--0% from outerRadius to infinity
local dFraction = math.max(
1.0
- math.max(
(mvData:GetEntityDistance() - ent:GetRadiusInner())
/ (ent:GetRadius() - ent:GetRadiusInner()),
0.0
),
0.0
)
local dmg = math.Round(ent:GetDmg() * dFraction * dFraction)

if dmg <= 0 then
mvData:AddDescriptionLine(TryT("c4_marker_vision_safe_zone"), COLOR_GREEN)
elseif mvData:GetEntityDistance() > ent:GetRadiusInner() then
elseif dmg < 100 then
mvData:AddDescriptionLine(TryT("c4_marker_vision_damage_zone"), COLOR_ORANGE)

color = COLOR_ORANGE
Expand Down
70 changes: 70 additions & 0 deletions lua/ttt2/libraries/game_effects.lua
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,76 @@ 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 attacker The player that causes this explosion.
-- @param Entity inflictor 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.
-- @internal
-- @realm server
function gameEffects.ExplosiveSphereDamage(
attacker,
inflictor,
damage,
origin,
outerRadius,
innerRadius
)
-- 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)
local plys = player.GetAll()
for i = 1, #plys do
local ply = plys[i]

if not IsValid(ply) or not ply:IsTerror() then
continue
end

diff = origin - (ply:GetPos() + ply:OBBCenter())
--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 * dFraction)

local dmginfo = DamageInfo()
dmginfo:SetDamage(dmg)
dmginfo:SetAttacker(attacker)
dmginfo:SetInflictor(inflictor)
dmginfo:SetDamageType(DMG_BLAST)
dmginfo:SetDamageForce(diff)
dmginfo:SetDamagePosition(ply:GetPos() + ply:OBBCenter())
ply:TakeDamageInfo(dmginfo)
end
end

-- vFIRE INTEGRATION

if SERVER then
Expand Down