2
votes

I'm making a gun engine/system that doesn't use the tool objects.

Currently I have everything down; equipping firing de-equipping

The guns are models with modulescripts inside them. They hold the statistics and relevant functions to the gun (firing, welding) but I've come across a problem

When the player tries to equip a gun that's already equipped, he de-equips it (which should happen), but he can still fire the de-equipped gun. The shot/raycast comes from the last position of the gun before it was de-equipped.

If I equip the gun again and fire, it fires both the previously de-equipped gun(s) and the equipped gun.

How can I fix this?

The equip function (inside a local script)

local function equip(gun)
    --[[
        Check to see if the currently being equipped gun is the same as the already equipped gun. If so, destroy equipped gun and return
    --]]
    if curEquipped~=nil and gun.Name == curEquipped.Model.Name then
        print("HI!")
        player.Character:FindFirstChild(gun.Name):Destroy()    
        curEquipped:Weld(player.Character.Torso,false)
        curEquipped = nil
        return
    end
    local gunMod = gun.Gun
    local gunModule = require(gunMod) -- not confusing at all.
    local newGun = gunModule.new()
    --[[
        Setting curEquipped
    --]]
    if not curEquipped then
        curEquipped = newGun
    else
        curEquipped:Weld(player.Character.Torso,false)
        curEquipped.Model:Destroy()
        curEquipped = newGun
    end
    gun.Parent = player.Character
    newGun:Weld(player.Character.Torso,true)
    mouse.Button1Down:connect(function()
        fire(newGun)
    end)
end

The module script inside the gun I'm testing:

local gunStats = {}
gunStats.__index = gunStats

function gunStats.new()
    local newGun = {}
    setmetatable(newGun,gunStats)
    newGun.Welding = {}
    setmetatable(newGun.Welding,newGun)
    newGun.fireRate = 1
    newGun.Barrel = script.Parent.Barrel
    newGun.HandlePosition = script.Parent.HandlePos.Position
    newGun.MaxAccuracy = .6
    newGun.Accuracy = .2
    newGun.Recoil = 150
    newGun.Model = script.Parent
    newGun.Bullet = Instance.new("Part")
    newGun.Bullet.BrickColor = BrickColor.Yellow()
    newGun.Bullet.Size=Vector3.new(.2,.2,1)
    newGun.Bullet.Anchored = true
    newGun.Bullet.CanCollide = false
    newGun.mesh=Instance.new("SpecialMesh",newGun.Bullet)
    newGun.mesh.MeshType="Brick"
    newGun.mesh.Name = "Mesh"
    newGun.mesh.Scale = Vector3.new(.5,.5,1)
    newGun.IsWelded = false
    newGun.Welding.WeldLeftArm = CFrame.new(-0.35, 0.4, 0.8)*CFrame.fromEulerAnglesXYZ(math.rad(280), 0, math.rad(-90))
    return newGun
end

function gunStats:Weld(torso, bool)
    local ls,rs=torso["Left Shoulder"],torso["Right Shoulder"]
    local la,ra=torso.Parent["Left Arm"],torso.Parent["Right Arm"]  
    if bool then
        local arm = torso.Parent["Right Arm"]
        if self.Welding.WeldRightArm then
            rs.Part1=nil
            local weld = Instance.new("Weld", arm)
            weld.Part0 = torso
            weld.Part1 = weld.Parent
            weld.C1 = self.Welding.WeldRightArm --[[ Position of arm ]]--
        end
        arm = torso.Parent["Left Arm"]
        if self.Welding.WeldLeftArm then
            ls.Part1=nil 
            local weld = Instance.new("Weld", arm)
            weld.Part0 = torso
            weld.Part1 = weld.Parent
            weld.C1 = self.Welding.WeldLeftArm --[[ Position of arm]]--
        end
        local weld = Instance.new("Weld",script.Parent.PrimaryPart)
        weld.Part0= weld.Parent
        weld.Part1= torso.Parent["Left Arm"]
        weld.C1 = weld.C1 * CFrame.fromEulerAnglesXYZ(math.rad(90),math.rad(90),math.rad(90)) * CFrame.new(0,1,0)
    else
        for _, v in pairs(torso.Parent:GetChildren()) do
            if v.Name == "Left Arm" or v.Name == "Right Arm" and v:FindFirstChild("Weld") then
                v:FindFirstChild("Weld"):Destroy()
                ls.Part1=la
                rs.Part1=ra
            end
        end
    end
end


function gunStats:Fire(mouse)
    local function raycast(a,b)
        local ray=Ray.new(a,((a-b).Unit)*999)
        local hit,pos=workspace:FindPartOnRay(ray)
        return hit,pos 
    end

    local distance = (self.Barrel.Position - mouse).magnitude
    local spread=(self.MaxAccuracy)*(self.Recoil/100)+(self.Accuracy) 
    local aim=mouse+Vector3.new(
        math.random(-(spread/10)*distance,(spread/10)*distance),
        math.random(-(spread/10)*distance,(spread/10)*distance),
        math.random(-(spread/10)*distance,(spread/10)*distance)
    )
    local hit,pos=raycast(self.Barrel.Position,aim) 
    local b1=self.Bullet:clone()
    b1.Mesh.Scale=Vector3.new(b1.Mesh.Scale.X,b1.Mesh.Scale.Y,distance)
    b1.CFrame=CFrame.new(self.Barrel.Position, mouse) * CFrame.new(0, 0, -distance / 2)
b1.Parent=workspace:FindFirstChild("RayIgnore") and workspace["RayIgnore"] or error("No model named RayIgnore in workspace!")
game.Debris:AddItem(b1,.1)
end

return gunStats
2

2 Answers

2
votes

Why not just make a variable that says whether you can shoot or not?

True when equipped, and false when unequipped.

1
votes

When you create a new gunStats -table via the .new "constructor" give it a boolean stat called "Equipped" and initially set it to false.

When you call the equip -method, set "Equipped" to true.

I didn't see an unequip -method, which you should definitely make, but in that you should set "Equipped" to false.

Now when firing the weapon you just check if it is Equipped, and if it is, do things normally, if not, just call return. Actually a better way would be to check if the gun is equipped before even calling "Fire", in the Button1Down listener, but both ways are acceptable.