Bullet damage dropoff

I was thinking about this and the code would be something like in cod where the bullet damage starts dropping off at around 50 meters or something.
I’m not sure if this would work or not since I don’t know if there is a way to tell when the bullet has traveled x distance. Or would it be if someone is 15 units away then bullet damage = SWEP.Primary.Damage *0.9 or something, although I have no idea of how gunshots work in source.


Is it possible to do this?



You should be able to use this or **[Util.TraceHull


You would be better off doing something with Bullet Callbacks. Something like this maybe?

[lua]-- set up our bullets source, direction, etc
bullet.Callback = function(att, tr, dmg)
if att and att:IsValid() then
local dist = (tr.HitPos - tr.StartPos):Length()
if dist > 50 then
if dist > 250 then
dmg:ScaleDamage(1 - ((dist-50)/200))
– shoot bullet[/lua]

You shoot the bullets with **[Entity.FireBullets


I know it’s an arbitrary value, but wow, that’s hardcore. :v:
50 Source units is horribly short, you’ll really have to stand right next to your target if you want to deal the maximum damage.
250 units is horribly short as well, that’s what I’d consider short range. So basically you have a gun which does no damage at all at medium and long range.


I’d say 50 meters are approximatively 1024 units.

16 units = 12 inches.
1 meter = ~39.4 inches

Therefor, 50 meters = ~3289 units ( 1.67 * 39.4 to get the number of units to a meter, times 50 ).

That wiki page isn’t right. If it’s 16 then a player that is 72 units tall would be a mere 4.5’, which is awfully short, don’t you think?

[li]16 units * 6’ = 96 units[/li][li]12 units * 6’ = 72 units[/li][/ul]

Now, which is more plausible?

Yea, I originally converted the 50 into meters, but when I rewrote it I forgot to put it back in.

And eventually bullet damage would be at zero.

So, if a bullet hit a target at 300 units away with a starting max damage of 50, then the damage would be:

50 - ((300 - 50)/200)
= 50 - 1.25
= 48.75

So with your code, at ~5 meters bullet damage would decrease by 1.25. That doesn’t seem too bad, although it can be easily changed. Unless I understood the code wrongly.

Is it possible for there to be a sort of be some sort of increase in bullet damage dropoff, like a upwards curve in bullet damage dropoff.


facepunch sucks at formatting.


now i don’t get why there are 2 ifs.


Theres an error indexing “bullet”

You’re doing it wrong. According to his post, bullet damage falloff starts kicking in when the distance exceeds 50 units. If the distance is higher than 250 units, bullets will become completely inefficient as their damage is reduced to zero.
If you’re at 150 units from your target, the falloff will be 1 - ((150-50)/200) = 0.5. So basically, bullets will only do half damage at 150 units. Which is indeed quite excessive.


Is this curve more suitable for you? Here’s the code for it.

local dist_min = 1024
local dist_max = 2048
local dmg_min = 0.25

local function BulletCallback(att, tr, dmg)
if ValidEntity(att) then
local dist = (tr.HitPos - tr.StartPos):Length()

	if dist > dist_max then
	elseif dist > dist_min then
		dmg:ScaleDamage(dmg_min + (1 - dmg_min) * math.sqrt(1 - ((dist - dist_min) / (dist_max - dist_min))))



Okay, so basically you blindly copied this code without understanding what it is for. You should post your whole SWEP:PrimaryAttack function so I show you what to do with it.

I have nothing under SWEP:PrimaryAttack. Thats a nice looking graph btw.

So if I increase the dist_max to say, 5000 units, won’t the slope be less steep since its at a constant speed stretched over 4000 units?

Wait, do you want to make a gun with bullet damage dropoff, or do you want the falloff to affect all weapons in the game?

Well, yes it will. Basically, all you’re doing is stretch the middle part, where it’s curving down.

So, if a bullet was at 50 damage max and then lets just say dist_min is 1000 and dist_max is 2000 (easier numbers to work with), at 1500 units,

0.25 + (1 - 0.25) * squareroot of (1 - (500 / 1000))))
= 1 * squareroot of 0.5
= 2.25?
Its either thats right or I suck at math since 2.25 is like 125 damage or something.


just one gun.

0.25 + (1 - 0.25) * squareroot of (1 - (500 / 1000))))
= 0.25 + 0.75 * sqrt(0.5)
= around 0.78

0.78 * 50 = 39 damage


Show me the code for that gun. Are you using a crappy gun base or what? It’s quite weird that you don’t even have a PrimaryAttack function.

Eh i just cooked up a 5 second swep. Its on tetabonitas base.

[lua]if SERVER then

SWEP.HoldType = "ar2"


if CLIENT then

SWEP.DrawAmmo			= true
SWEP.DrawCrosshair		= false
SWEP.ViewModelFOV		= 76
SWEP.ViewModelFlip		= true
SWEP.CSMuzzleFlashes	= true
SWEP.Slot				= 3
SWEP.SlotPos			= 1
SWEP.IconLetter			= "i"
SWEP.DrawWeaponInfoBox  = true

killicon.AddFont("weapon_rg_example", "CSKillIcons", SWEP.IconLetter, Color(255, 220, 0, 255))


SWEP.Base = “rg_base”

– Info –

SWEP.PrintName = “HK416”
SWEP.Author = “Flubadoo”
SWEP.Purpose = “Shoot things.”
SWEP.Instructions = “Hold your use key and press secondary fire to change fire modes.”
SWEP.Category = “Flubadoo’s Rifles”

– Misc. –

SWEP.Spawnable = true
SWEP.AdminSpawnable = true
SWEP.Weight = 5
SWEP.AutoSwitchTo = false
SWEP.AutoSwitchFrom = false
SWEP.DrawFireModes = true

– Primary Fire –

SWEP.Primary.Sound = Sound(“weapons/hk416/hk416-1.wav”)
SWEP.Primary.Damage = 16.7 – This determines both the damage dealt and force applied by the bullet.
SWEP.Primary.NumShots = 1
SWEP.Primary.ClipSize = 30
SWEP.Primary.DefaultClip = 90
SWEP.Primary.Ammo = “ar2”
SWEP.MuzzleVelocity = 875 – How fast the bullet travels in meters per second. For reference, an AK47 shoots at about 750, an M4 shoots at about 900, and a Luger 9mm shoots at about 350 (source: Wikipedia)
SWEP.FiresUnderwater = false

– Secondary Fire –

– Secondary Fire is used to switch ironsights and firemodes
SWEP.Secondary.ClipSize = -1 – best left at -1
SWEP.Secondary.DefaultClip = 1 – set to -1 if you don’t use secondary ammo
SWEP.Secondary.Ammo = “none” – Leave this if you want your SWEP to have grenades, otherwise set to “none” if you don’t use secondary ammo.

– Recoil, Spread, and Spray –

SWEP.RecoverTime = 0.5 – Time in seconds it takes the player to re-steady his aim after firing.

– The following variables control the overall accuracy of the gun and typically increase with each shot
– Recoil: how much the gun kicks back the player’s view.
SWEP.MinRecoil = 0.15
SWEP.MaxRecoil = 0.9
SWEP.DeltaRecoil = 0.45 – The recoil to add each shot. Same deal for spread and spray.

– Spread: the width of the gun’s firing cone. More spread means less accuracy.
SWEP.MinSpread = 0.0004
SWEP.MaxSpread = 0.1
SWEP.DeltaSpread = 0.009

– Spray: the gun’s tendancy to point in random directions. More spray means less control.
SWEP.MinSpray = 0
SWEP.MaxSpray = 1.5
SWEP.DeltaSpray = 0.25

– Ironsight/Scope –

– IronSightsPos and IronSightsAng are model specific paramaters that tell the game where to move the weapon viewmodel in ironsight mode.
SWEP.IronSightsPos = Vector (2.2421, -1.8675, 0.2953)
SWEP.IronSightsAng = Vector (0.0359, -0.1531, 0)
SWEP.IronSightZoom = 1.5 – How much the player’s FOV should zoom in ironsight mode.
SWEP.UseScope = false – Use a scope instead of iron sights.
SWEP.ScopeScale = 0.4 – The scale of the scope’s reticle in relation to the player’s screen size.
SWEP.ScopeZooms = {4,8,16} – The possible magnification levels of the weapon’s scope. If the scope is already activated, secondary fire will cycle through each zoom level in the table.
SWEP.DrawParabolicSights = true – Set to true to draw a cool parabolic sight (helps with aiming over long distances)

– Effects/Visual –

SWEP.ViewModel = “models/weapons/v_rif_hka1.mdl”
SWEP.WorldModel = “models/weapons/w_rif_aug.mdl”

SWEP.MuzzleEffect = “rg_muzzle_rifle” – This is an extra muzzleflash effect
– Available muzzle effects: rg_muzzle_grenade, rg_muzzle_highcal, rg_muzzle_hmg, rg_muzzle_pistol, rg_muzzle_rifle, rg_muzzle_silenced, none

SWEP.ShellEffect = “rg_shelleject_rifle” – This is a shell ejection effect
– Available shell eject effects: rg_shelleject, rg_shelleject_rifle, rg_shelleject_shotgun, none

SWEP.MuzzleAttachment = “1” – Should be “1” for CSS models or “muzzle” for hl2 models
SWEP.ShellEjectAttachment = “2” – Should be “2” for CSS models or “1” for hl2 models

– Modifiers –

– Modifiers scale the gun’s recoil, spread, and spray based on the player’s stance
SWEP.CrouchModifier = 0.8 – Applies if player is crouching.
SWEP.IronSightModifier = 0.9 – Applies if player is in iron sight mode.
SWEP.RunModifier = 1.4 – Applies if player is moving.
SWEP.JumpModifier = 1.6 – Applies if player is in the air (jumping)

– Note: the jumping and crouching modifiers cannot be applied simultaneously

– Fire Modes –

– You can choose from a list of firemodes, or add your own! \0/
SWEP.AvailableFireModes = {“Auto”,“Semi”} – What firemodes shall we use?
– “Auto”, “Burst”, “Semi”, and “Grenade” are firemodes that are available by default.

– RPM is the rounds per minute the gun can fire for each mode (if applicable)
SWEP.AutoRPM = 700
SWEP.SemiRPM = 700
SWEP.BurstRPM = 800 – Burst RPM affects the space between the shots during the burst. The space between bursts is determined by SemiRPM.
SWEP.DrawFireModes = true – Set to true to allow drawing of a visual indicator for the current firemode.

– Additional parameters for the “Grenade” firemode
SWEP.GrenadeDamage = 100
SWEP.GrenadeVelocity = 1400
SWEP.GrenadeRPM = 50

function SWEP:Reload()


if ( self.Weapon:Clip1() < self.Primary.ClipSize ) and self.Owner:GetAmmoCount(self.Primary.Ammo) > 0 then
-- When the current clip < full clip and the rest of your ammo > 0, then

	self.Owner:SetFOV( 0, 0.15 )
	-- Zoom = 0





this is the primayattack function from the base:

[lua]function SWEP:PrimaryAttack()

self.Weapon:SetNextSecondaryFire(CurTime() + self.Primary.Delay)
self.Weapon:SetNextPrimaryFire(CurTime() + self.Primary.Delay)

-- Fire function is defined under SWEP:SetFireMode()



Also, kinda like this (scroll down the hk416 stats):

Pfft, a gun base, boring… :eng99:

Here’s the easiest solution.

hook.Add(“EntityTakeDamage”, “DoBulletFalloff”, function(ent, inf, att, am, dmg)
if dmg:IsBulletDamage() then
local weapon

	if inf:IsWeapon() then
		weapon = inf
		weapon = att:GetActiveWeapon()
	if not (weapon.DamageFalloffMinDistance and weapon.DamageFalloffMaxDistance and weapon.MininumDamageFraction) then
	local startpos
	if att:IsPlayer() or att:IsNPC() then
		startpos = att:GetShootPos()
		startpos = weapon:GetPos()
	local dist = (dmg:GetDamagePosition() - startpos):Length()
	if dist > weapon.DamageFalloffMaxDistance then
	elseif dist > weapon.DamageFalloffMinDistance then
		dmg:ScaleDamage(weapon.MininumDamageFraction + (1 - weapon.MininumDamageFraction) * math.sqrt(1 - ((dist - weapon.DamageFalloffMinDistance) / (weapon.DamageFalloffMaxDistance - weapon.DamageFalloffMinDistance))))


You will put this inside of an autorun SERVERSIDE Lua file. I hope you know what that means. The name of the file doesn’t matter at all.

Then, inside of your weapon, you will add the following lines:

[lua]SWEP.DamageFalloffMinDistance = 1024
SWEP.DamageFalloffMaxDistance = 2048
SWEP.MininumDamageFraction = 0.25[/lua]

That should work.

I sincerely thank you for all the effort and time spent on making this.
:love: :love: :love: :love:


Oh yeah i think there is an extra parenthase(s)? near the last end. I’ll just remove it. and it works VERY well.

Don’t remove it, it’s a part of hook.Add. Most people do this:

[lua]function functionname()

hook.Add(“hookname”, “hookid”, functionname)[/lua]

I prefer doing this:

[lua]hook.Add(“hookname”, “hookid”, function() … end)[/lua]

Note the parenthesis after “end”. It’s much more compact that way.

Also glad it works. I didn’t even test it. :v:

lol just realized i tested it without removing the parentheses.


If I change mindistancefraction to 14.3 will the min damage be 14.3?


oh yeah how many units is 1 meter?

I’ve been running off this:

Maps, architecture and prop models use a scale of 1 foot = 16 units.

Which seems to not include player in that.

It’s not the minimum damage, it’s the minimum multiplier which can be applied to the damage. If it’s equal to 0.25, the minimum damage will be one quarter of the maximum damage.