Super-Nostalgia-Zone/Server/Scripts/Explosions.server.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)