Phantom Forces Script | GRENADE PREDICTION

Created by integerisqt

Features:

  • GRENADE PREDICTION
local pfCamera;
local cfModule;
local char;
local oldLoadGrenade;
local network;
local oldSend;
local roundsystem;
local beamStorage = Instance.new("Part", workspace.Terrain);
beamStorage.Anchored = true;
beamStorage.Transparency = 1;
beamStorage.CanCollide = false;
local runService = game:GetService("RunService");


--grenade constants
local castResolution = 1/60;
local nadeAcceleration = Vector3.new(0, -80, 0);
local bounceElasticity = 0.2;
local frictionConstant = 0.08;

local function isBadNumber(x)
    return x ~= x or math.abs(x) == 1 / 0;
end


local function bezier(origin, velocity, acceleration, time)
    local p3 = origin + time*(0.5*acceleration*time + velocity);
    local p2 = p3 - time*(acceleration*time + velocity)/3;
    local p1 = (origin*7/3) - p2 - p3/3 + (acceleration*time*time)/3 + (time*velocity*4/3);


    local curve0 = (p1 - origin).Magnitude;
    local curve1 = -((p2 - p3).Magnitude);


    local b = (origin - p3).Unit;
    local r1 = (p1 - origin).Unit;
    local u1 = r1:Cross(b).Unit;
    local r2 = (p2 - p3).Unit;
    local u2 = r2:Cross(b).Unit;
    b = u1:Cross(r1);

    return curve0, curve1, CFrame.fromMatrix(origin, r1, u1, b), CFrame.fromMatrix(p3, r2, u2, b);
end

local function nadeBeam(origin, velocity, acceleration, time)
    local curve0, curve1, cfA, cfB = bezier(origin, velocity, acceleration, time);

    local beam = Instance.new("Beam");
    local a0 = Instance.new("Attachment");
    local a1 = Instance.new("Attachment");

    a0.CFrame = cfA;
    a1.CFrame = cfB;

    a0.Parent = beamStorage;
    a1.Parent = beamStorage;

    beam.Attachment0 = a0;
    beam.Attachment1 = a1;
    beam.CurveSize0 = curve0;
    beam.CurveSize1 = curve1;
    beam.Segments = 10000;
    beam.Color = ColorSequence.new(Color3.new(1, 1, 1));
    beam.Transparency = NumberSequence.new(0);
    beam.Width0 = 0.05;
    beam.Width1 = 0.05;
    beam.FaceCamera = true;
    beam.Parent = beamStorage;
end


local function generateNadeArguments(flyingNade, nadeData, remainingSecond)
    local aimCf = pfCamera.cframe * CFrame.Angles(math.rad(nadeData.throwangle or 0), 0, 0);
    local position = flyingNade.Position;
    local velocity = aimCf.LookVector * nadeData.throwspeed + char.rootpart.Velocity;
    do
        --do a check incase nade clips inside a wall
        local p = pfCamera.basecframe.p;
        local _, pos, norm = workspace:FindPartOnRayWithWhitelist(Ray.new(p, position - p), roundsystem.raycastwhitelist);
        position = pos + 0.01*norm;
    end
    local av0 = (pfCamera.cframe - pfCamera.cframe.p) * Vector3.new(19.539, -5, 0);
    local rot0 = flyingNade.CFrame - flyingNade.CFrame.p;
    local offset = Vector3.new();
    local lastbounce = false;
    local glassCount = 0;
    local frames = {
        {
            t0 = 0,
            p0 = position,
            v0 = velocity,
            offset = offset,
            rot0 = rot0,
            rotv = av0,
            glassbreaks = {}
        }
    };

    for i = 1, remainingSecond/castResolution + 1 do
        local newPosition = position + castResolution*velocity + castResolution*castResolution/2*nadeAcceleration;
        local hit, pos, norm = workspace:FindPartOnRayWithWhitelist(Ray.new(position, newPosition - position - 0.05 * offset), roundsystem.raycastwhitelist);
        local time = i*castResolution;
        if hit and hit.Name ~= "Window" and hit.Name ~= "Col" then
            rot0 = flyingNade.CFrame - flyingNade.CFrame.p;
            offset = 0.2*norm;
            av0 = norm:Cross(velocity) / 0.2;
            local delta = pos - position;
            local fixpls = 1 - 0.001 / delta.Magnitude;
            fixpls = fixpls < 0 and 0 or fixpls;
            position = position + fixpls*delta + 0.05*norm;
            local normvel = norm:Dot(velocity)*norm;
            local tanvel = velocity - normvel;
            local geometricdeceleration;
            local d1 = -norm:Dot(nadeAcceleration);
            local d2 = -(1 + bounceElasticity) * norm:Dot(velocity);
            geometricdeceleration = 1 - frictionConstant * (10 * (d1 < 0 and 0 or d1) * castResolution + (d2 < 0 and 0 or d2)) / tanvel.Magnitude;
            geometricdeceleration = geometricdeceleration < 0 and 0 or geometricdeceleration;
            velocity = geometricdeceleration * tanvel - bounceElasticity * normvel;
            if velocity.Magnitude < 1 then
                frames[#frames + 1] = {
                    t0 = time - castResolution*newPosition:Dot(pos)/newPosition:Dot(position), --magnitude/magnitude = dot/dot
                    p0 = position,
                    v0 = Vector3.new(),
                    rot0 = cfModule.fromaxisangle(time * av0) * rot0,
                    b = true,
                    offset = 0.2 * norm,
                    rotv = Vector3.new(),
                    glassbreaks = {}
                };
                break;
            end
            frames[#frames + 1] = {
                t0 = time - castResolution*newPosition:Dot(pos)/newPosition:Dot(position),
                p0 = position,
                v0 = velocity,
                rot0 = cfModule.fromaxisangle(time * av0) * rot0,
                b = lastbounce,
                offset = 0.2 * norm,
                rotv = av0,
                glassbreaks = {}
            };
            lastbounce = true;
        else
            position = newPosition;
            velocity = velocity + castResolution*nadeAcceleration;
            lastbounce = false;
            if hit and hit.Name == "Window" and glassCount < 5 then
                glassCount = glassCount + 1;
                frames[#frames].glassbreaks[#frames[#frames].glassbreaks + 1] = {
                    t = time,
                    part = hit
                };
            end
        end
    end
    return frames;
end




for i,v in ipairs(getgc(true)) do
    if type(v) == "table" then
        if rawget(v, "basecframe") then
            pfCamera = v;
        elseif rawget(v, "fromaxisangle") then
            cfModule = v;
        elseif rawget(v, "jump") then
            char = v;
            oldLoadGrenade = v.loadgrenade;
        elseif rawget(v, "send") then
            network = v;
            oldSend = v.send;
        elseif rawget(v, "raycastwhitelist") then
            roundsystem = v;
        end
    end
end


char.loadgrenade = function(...)
    local _, nadeName = ...;
    local self = oldLoadGrenade(...);
    local oldEquip = self.setequipped;
    local oldThrow = self.throw;
    local oldCreatenade;
    local nadeData;
    local start, blowUp;
    local connection;
    local frames;
    local appliedConnection = false;
    for i,v in next, debug.getupvalues(oldThrow) do
        if type(v) == "function" and debug.getinfo(v).name == "createnade" then
            oldCreatenade = v;
            print("createnade found");
            debug.setupvalue(oldThrow, i, function(...)
                v(...);
                for j,k in next, debug.getupvalues(v) do
                    if type(k) == "table" and rawget(k, "frames") then
                        k.frames = frames;
                    end
                end
            end);
            break;
        end
    end
    for i,v in next, debug.getupvalues(oldEquip) do
        if type(v) == "table" and rawget(v, "type") and rawget(v, "crosssize") then
            nadeData = v;
            print("nade data found");
            break;
        end
    end



    self.setequipped = function(this, on)
        if on then
            local lastRan = tick();
            start = lastRan;
            blowUp = start + 5;
            connection = runService.RenderStepped:Connect(function()
                if not char.alive then
                    if connection then
                        connection:Disconnect();
                        beamStorage:ClearAllChildren();
                    end
                end
                local now = tick();
                if lastRan <= now then
                    lastRan = now + castResolution - (now - lastRan)%castResolution;
                    local remaining = blowUp - now;
                    local flyingNade = debug.getupvalue(oldCreatenade, 2);
                    if flyingNade then
                        if not appliedConnection then
                            --gay but kys
                            appliedConnection = true;
                            flyingNade.AncestryChanged:Connect(function(_, new)
                                if new == nil then
                                    beamStorage:ClearAllChildren();
                                end
                            end);
                        end
                        frames = generateNadeArguments(flyingNade, nadeData, remaining);
                        beamStorage:ClearAllChildren();
                        for j,currentFrame in next, frames do
                            local nextFrame = frames[j + 1];
                            if nextFrame then
                                local origin = currentFrame.p0 + currentFrame.offset;
                                local time = nextFrame.t0 - currentFrame.t0;
                                local acceleration = currentFrame.b and Vector3.new() or nadeAcceleration;
                                local velocity = ((nextFrame.p0 + nextFrame.offset) - origin - 0.5*acceleration*time*time)/time;
                                nadeBeam(origin, velocity, acceleration, time);
                            end
                        end
                    end
                end
            end);
        end
        return oldEquip(this, on);
    end

    self.throw = function(...)
        appliedConnection = false;
        if connection then
            connection:Disconnect();
            --beamStorage:ClearAllChildren();
        end
        if frames then
            oldSend(network, "newgrenade", nadeName, {
                time = tick(),
                blowuptime = blowUp - tick(),
                frames = frames
            });
        end
        return oldThrow(...);
    end
    return self;
end

network.send = function(self, name, ...)
    if name == "newgrenade" then
        return;
    end
    return oldSend(self, name, ...);
end

ENJOY!

Warning: DO NOT DOWNLOAD anything from this page, you’re only here to copy the script!

Share This Post

Share on facebook
Share on linkedin
Share on twitter
Share on email

More Scripts!

TOP 10 TRENDING SCRIPTS