186 lines
5.6 KiB
Lua
186 lines
5.6 KiB
Lua
local CollectionService = game:GetService("CollectionService")
|
|
local Debris = game:GetService("Debris")
|
|
local ServerStorage = game:GetService("ServerStorage")
|
|
|
|
local FORCE_GRANULARITY = 2
|
|
local allowTeamDamage = false
|
|
|
|
local teamDamage = ServerStorage:FindFirstChild("TeamDamage")
|
|
|
|
if teamDamage then
|
|
allowTeamDamage = teamDamage.Value
|
|
end
|
|
|
|
local function processExplosion(explosion)
|
|
local BLAST_RADIUS = explosion.BlastRadius
|
|
local BLAST_PRESSURE = explosion.BlastPressure
|
|
|
|
if explosion:FindFirstChild("BLAST_PRESSURE") then
|
|
BLAST_PRESSURE = explosion.BLAST_PRESSURE.Value
|
|
end
|
|
|
|
if BLAST_PRESSURE > 0 then
|
|
local damagedPlayerSet = {}
|
|
local blastCenter = explosion.Position
|
|
|
|
local function onExplosionHit(p, dist)
|
|
if explosion:FindFirstChild("Owner") then
|
|
local player = explosion.Owner.Value
|
|
if player then
|
|
local char = player.Character
|
|
if char and p:IsDescendantOf(char) then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
local isInCharacter = false
|
|
|
|
if p.Size.Magnitude / 2 < 20 then
|
|
--world->ticklePrimitive(p, true);
|
|
|
|
local doBreakjoints = true
|
|
local hitCharacter = p:FindFirstAncestorWhichIsA("Model")
|
|
local hitHumanoid = hitCharacter:FindFirstChild("Humanoid")
|
|
|
|
if hitCharacter and hitHumanoid then
|
|
-- flag as character
|
|
isInCharacter = true
|
|
|
|
-- don't breakjoints characters
|
|
doBreakjoints = false
|
|
|
|
-- work out what damage to do
|
|
local hitPlayer = game.Players:GetPlayerFromCharacter(hitCharacter)
|
|
local creatorTag = explosion:FindFirstChild("creator")
|
|
local myPlayer
|
|
|
|
if creatorTag then
|
|
myPlayer = creatorTag.Value
|
|
end
|
|
|
|
if hitPlayer and not damagedPlayerSet[hitPlayer] then
|
|
local doDamage = true
|
|
|
|
if not allowTeamDamage then
|
|
if myPlayer and hitPlayer ~= myPlayer then
|
|
if hitPlayer.Team and myPlayer.Team and hitPlayer.Team == myPlayer.Team then
|
|
doDamage = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if doDamage then
|
|
-- flag as damaged
|
|
damagedPlayerSet[hitPlayer] = true
|
|
|
|
-- assume the torso is a massless frictionless unit ball in a perfect vaccum
|
|
dist = math.min(math.max(dist - 0.8, 0), 1)
|
|
|
|
-- damage to do
|
|
local frac = (dist / BLAST_RADIUS)
|
|
|
|
-- do damage. See how much damage to do
|
|
if myPlayer == hitPlayer then
|
|
hitHumanoid:TakeDamage((BLAST_RADIUS * 20) - (frac * 38))
|
|
hitHumanoid:ChangeState("Ragdoll")
|
|
else
|
|
hitHumanoid:TakeDamage(100)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- breakjoints stuff
|
|
if doBreakjoints then
|
|
if not hitHumanoid and p:CanSetNetworkOwnership() then
|
|
p:SetNetworkOwner(nil)
|
|
end
|
|
|
|
for _,joint in pairs(p:GetJoints()) do
|
|
if not CollectionService:HasTag(joint, "GorillaGlue") then
|
|
joint:Destroy()
|
|
end
|
|
end
|
|
end
|
|
|
|
--Vector3 delta = (p->getCoordinateFrame().translation - position);
|
|
local delta = (p.Position - blastCenter)
|
|
|
|
--Vector3 normal =
|
|
-- (delta == Vector3::zero())
|
|
-- ? Vector3::unitY()
|
|
-- : delta.direction();
|
|
local normal = (delta == Vector3.new(0, 0, 0))
|
|
and Vector3.new(0, 1, 0)
|
|
or delta.unit
|
|
|
|
--float radius = p->getRadius();
|
|
local radius = p.Size.magnitude / 2
|
|
|
|
--float surfaceArea = radius * radius;
|
|
local surfaceArea = radius * radius
|
|
|
|
--Vector3 impulse = normal * blastPressure * surfaceArea * (1.0f / 4560.0f); // normalizing factor
|
|
local impulse = normal * BLAST_PRESSURE * surfaceArea * (1.0 / 4560.0)
|
|
|
|
-- How much force to apply (for characters, ramp it down towards the edge)
|
|
local frac;
|
|
|
|
if isInCharacter then
|
|
frac = 1 - math.max(0, math.min(1, (dist - 2) / BLAST_RADIUS))
|
|
else
|
|
frac = 1
|
|
end
|
|
|
|
--p->getBody()->accumulateLinearImpulse(impulse, p->getCoordinateFrame().translation);
|
|
local currentVelocity = p.Velocity
|
|
local deltaVelocity = impulse / p:GetMass() -- m * del-v = F * del-t = Impulse
|
|
local forceNeeded = workspace.Gravity * p:GetMass() -- F = ma
|
|
|
|
local bodyV = Instance.new('BodyVelocity')
|
|
bodyV.Velocity = currentVelocity + deltaVelocity
|
|
bodyV.MaxForce = Vector3.new(forceNeeded, forceNeeded, forceNeeded) * 10 * frac
|
|
bodyV.Parent = p
|
|
|
|
Debris:AddItem(bodyV, 0.2 / FORCE_GRANULARITY)
|
|
|
|
--p->getBody()->accumulateRotationalImpulse(impulse * 0.5 * radius); // a somewhat arbitrary, but nice torque
|
|
local rotImpulse = impulse * 0.5 * radius
|
|
local currentRotVelocity = p.RotVelocity
|
|
|
|
local momentOfInertia = (2 * p:GetMass() * radius * radius / 5) -- moment of inertia = 2/5*m*r^2 (assuming roughly spherical)
|
|
local deltaRotVelocity = rotImpulse / momentOfInertia
|
|
local torqueNeeded = 20 * momentOfInertia -- torque = r x F, want about alpha = 20 rad/s^2, alpha * P = torque
|
|
|
|
local rot = Instance.new('BodyAngularVelocity')
|
|
rot.MaxTorque = Vector3.new(torqueNeeded, torqueNeeded, torqueNeeded) * 10 * frac
|
|
rot.AngularVelocity = currentRotVelocity + deltaRotVelocity
|
|
rot.Parent = p
|
|
|
|
Debris:AddItem(rot, 0.2 / FORCE_GRANULARITY)
|
|
end
|
|
end
|
|
|
|
explosion.Hit:Connect(onExplosionHit)
|
|
end
|
|
end
|
|
|
|
local function onDescendantAdded(desc)
|
|
if desc:IsA("Explosion") then
|
|
local pressure = desc.BlastPressure
|
|
|
|
if pressure > 0 then
|
|
local blastPressure = Instance.new("NumberValue")
|
|
blastPressure.Name = "BLAST_PRESSURE"
|
|
blastPressure.Value = pressure
|
|
blastPressure.Parent = desc
|
|
|
|
desc.BlastPressure = 0
|
|
end
|
|
|
|
processExplosion(desc)
|
|
end
|
|
end
|
|
|
|
workspace.DescendantAdded:Connect(onDescendantAdded) |