Is a reliable, works 100% of the time, fall damage script even possible atm?

Greetings,

I am trying to make a reliable fall damage script, so far I’ve had no luck. I’ve made several of my own and tried half a dozen i’ve found online. StateChange is most problematic because the player doesn’t always “land” but instead switches to running or runningnophysics

2 main issues that keep popping up:

  1. It doesn’t work every time, depending on if the player jumped, was pushed etc.
  2. if i give the player a jump boost and he jumps up high and lands on a part that is higher than the part he jumped from it still registers as if he fell and not jumped up, if it registers at all

If anyone has discovered a solution that solves these two problems please share, thank you for your time

Detect changes in the Y. Solves all of your problems here. If the Y before jumping was greater than the Y upon landing, then the character fell. Separate the different thresholds into different damage levels.

1 Like

that was my first attempt. However i used state change which is unreliable, do you have an alternative?

I don’t understand how StateChange is unreliable. Instead of checking for “Landed”, check for “not FreeFall”

like i said, if you print state on change state you will notice that most of the time the landed event doesn’t fire, that’s what i meant by unreliable

Just check to see if the FreeFall event isn’t there instead of checking for “Landed”

You could connect the .Touched event for each part parented to the character(.Touched apparently works on terrain, although I think it fires when the player touches water also). You could also check the Humanoid’s FloorMaterial, and if it’s set to “Air” then the character isn’t touching the ground.

Then for damage, you could take damage based on HumanoidRootPart’s Y velocity(only damages the player when he falls), or HumanoidRootPart’s Velocity.Magnitude(which would allow damage from the player moving at high velocities in other directions).

1 Like

You can utilize the Humanoid.StateChanged event to achieve your goal. Every time if your humanoid state changes to freefall, you can get the y position once it changed, then once the state changes to Landed, you can get the Y value of the HumanoidRootPart when the Humanoid lands, and take the difference of the two Y values. Depending on the difference, you can scale your damage accordingly.

What I would do is do a combination of detecting velocity of the y axis of the torso and GetPropertyChangedSignal for FloorMaterial on the Humanoid. If the floor material is changed from air to some material and the velocity of the torso was some value then you could say they fell from a certain height.

2 Likes

You would then have to run something every frame(this wouldn’t be too bad, because there isn’t intense computing power going on):

1A. Check if player is off the ground via raycasting
1B. If player is not off the ground, repeat 1A until they are off the ground

    2. Get the velocity of the player, whilst raycasting downwards equal to the velocity(so if the velocity is "0, 5, 0", you would rayacst "5" studs downwards)

        3A. If it hits a part, wait for the player to hit the ground, then take corresponding damage
        3B. If not, keep doing #2 until 3A is met

I think comparing start and end heights would cause problems. Isn’t that what he’s doing already?

I’ve never needed to set a specific height for fall damage, but if you need to, you could calculate height from velocity with a little math:

local height = (velocity*velocity)/(2*workspace.Gravity)

I made a fall damage script. It worked every time I tested it, and doesn’t damage a player when he falls into the water.

--height at which the player starts to take damage
local minimumDamageHeight = 20
--height at which the player takes maximumDamage damage
local maximumDamageHeight = 100
--if height exceeds maximumDamageHeight,
--player will take over maximumDamage damage
local maximumDamage = 100

local velocity

-- linear interpolation function
local function lerp(a,b,t)
	return (1-t)*a+b*t
end

--inverse of lerp function
local function invLerp(a,b,v)
	return (v-a)/(b-a)
end

--remaps value, used for max and min damage heights.
local function remap(iMin,iMax,oMin,oMax,v)
	return lerp(oMin,oMax,invLerp(iMin,iMax,v))
end

-- fired when FloorMaterial changes
script.Parent.Humanoid:GetPropertyChangedSignal("FloorMaterial"):Connect(function()
	--calculate fall height from velocity
	local height = (velocity * velocity)/(2*workspace.Gravity)

	--remap damage based on variables
	local damage = remap(minimumDamageHeight,maximumDamageHeight,0,maximumDamage,height)
	--prevent negative damage
	damage = math.max(damage,0)
	--apply damage
	script.Parent.Humanoid:TakeDamage(damage)
end)

--fires before each physics update
game:GetService("RunService").Stepped:Connect(function(time,step)
	--update velocity variable
	velocity = script.Parent.HumanoidRootPart.Velocity.Y
end)

I put this in a LocalScript in StarterCharacterScripts.

1 Like

while this works great, what worries me is that it’s a local script, wouldn’t this make it vulnerable to client side manipulation?

Its not even a localscript, you put it in a CharacterAdded function.

1 Like

you just can’t depend on loops, they will not always be in sync with physics/movement.

your approach needs to be event based. (using custom wrapped events or provided events, doesn’t matter)

what do you mean? i don’t get it, it IS a local script

I tried to transfer it to a severscript inside StarterCharacterScripts, however even tho there are no errors it doesn’t work

It seems pretty easy for players to hack the client or the server(I’ve heard you can download programs to do it for you), so I don’t worry about it. In this case a client side script works better.

Probably the reason it doesn’t work in a server script is the .Stepped function. The server and client aren’t quite synced, so there might be a little delay(and so velocity is low by the time GetPropertyChangedSignal(“FloorMaterial”) gets fired.

The loop I use is called just before physics are calculated, so it is in sync. I tried getting the velocity only after an event was fired(tried multiple events), but it had already responded to collision and was set to 0. For fall damage, you need the velocity on the previous physics frame, which can’t be done with just events.

Here’s an article about roblox and hacking: