I want to code my cancel placement system (Enum.Keycode.Q) so that it stops the placement of sentries and resets the connections of ActivatedButton
However, when I cancel my sentry’s placement and then place a new one, it places a duplicate. This duplicate does NOT happen again unless I cancel another sentry again.
This duplicate problem does not happen when I unequip the weapon, then equip it again so I suspect there may be something wrong with my cancelling system.
Client Script to inspect
-- Services
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local UserInputService = game:GetService("UserInputService")
local RunService = game:GetService("RunService")
-- Events
local Events = ReplicatedStorage.Events
local ActivateAbility = Events:FindFirstChild("ActivateAbility")
local SpawnSentry = Events:FindFirstChild("SpawnSentry")
-- Other Variables
local player = Players.LocalPlayer
local gui = player.PlayerGui:WaitForChild("CharacterGui")
local Backpack = player:WaitForChild("Backpack")
local camera = workspace.CurrentCamera
local sentryToSpawn = nil
local selectedSentry = nil
local hoveredInstance = nil
local activatedRepair = nil
local activatedButton = nil
local destroyingConnection = nil
local canPlace = false
local rotation = 0
local lastTouch = tick()
local activatedButton = {}
local function MouseRaycast(excludedInstances)
local mousePosition = UserInputService:GetMouseLocation() -- gets mouse position on the screen
local mouseRay = camera:ViewportPointToRay(mousePosition.X, mousePosition.Y) -- gets mouse raycast
local raycastParams = RaycastParams.new()
raycastParams.FilterDescendantsInstances = {player.Character, excludedInstances}
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
local raycastResult = workspace:Raycast(mouseRay.Origin, mouseRay.Direction * 1000, raycastParams)
return raycastResult
end
local function RemovePlaceholderSentry()
if not sentryToSpawn then
return
end
sentryToSpawn:Destroy()
sentryToSpawn = nil
rotation = 0
end
local function AddPlaceholderSentry(attack)
RemovePlaceholderSentry()
sentryToSpawn = attack.Sentry.Value:Clone()
sentryToSpawn.Parent = workspace.Camera
for i, object in ipairs(sentryToSpawn:GetDescendants()) do
if object:IsA("BasePart") then
object.CollisionGroup = "SentryToSpawn"
object.Material = Enum.Material.ForceField
object.Massless = true
end
end
end
local function ColourPlaceholderSentry(colour)
for i, object in ipairs(sentryToSpawn:GetDescendants()) do
if object:IsA("BasePart") then
object.Color = colour
end
end
end
-- Function to handle the removal of weapons
local function handleWeaponDeletion()
-- Clear the ability buttons when a weapon is removed
for _, button in pairs(gui.Abilities:GetChildren()) do
if button:IsA("UIListLayout") or button.Name == "Template" then
continue
end
button:Destroy()
end
gui.Abilities.Visible = false
gui.ManageTools.Visible = false -- Reset ManageTools UI when the weapon is unequipped
for i, connection in activatedButton do
connection:Disconnect()
end
activatedButton = {}
-- while activatedButton do
-- activatedButton:Disconnect()
-- task.wait()
-- end
end
local function handleWeaponRemoval()
gui.Abilities.Visible = false
gui.ManageTools.Visible = false -- Reset ManageTools UI when the weapon is unequipped
for i, connection in activatedButton do
connection:Disconnect()
end
activatedButton = {}
-- while activatedButton do
-- activatedButton:Disconnect()
-- task.wait()
-- end
end
-- Function to handle the addition of weapons
local function handleWeaponAddition(weapon)
gui.Abilities.Visible = true
for _, attack in ipairs(weapon.Abilities:GetChildren()) do
local attackConfig = attack:GetAttributes()
local button = gui.Abilities:FindFirstChild(attack.Name)
-- Create a new button if it doesn't exist
if not button then
button = gui.Abilities.Template:Clone()
button.Name = attack.Name
button.Image = attack.Image.Texture
button.Ability.Text = attack.Name
button.Visible = true
button.Parent = gui.Abilities
end
-- for i, connection in activatedButton do
-- connection:Disconnect()
-- end
-- Function to run when the ability button is activated
local function onButtonActivated()
print(activatedButton)
-- Prevent multiple activations
if button.Active == false then
return
end
-- Handle ability cooldowns
local function handleCooldown(ability, cooldownDuration)
if cooldownDuration > 0 then
for _, manageTools in gui.ManageTools.List:GetChildren() do
if not manageTools:IsA("TextButton") or manageTools.Active == false then
continue
end
manageTools.Active = false
manageTools.Shadow.Visible = true
end
ability.Shadow.Cooldown.Visible = true
ability.GuiCooldown.Value = cooldownDuration
for remainingTime = cooldownDuration, 0, -0.1 do
ability.GuiCooldown.Value = remainingTime
ability.Shadow.Cooldown.Text = string.format("%.1f", remainingTime)
task.wait(0.1)
if ability.GuiCooldown.Value ~= remainingTime then
return
end
end
end
ability.Active = true
ability.Shadow.Visible = false
ability.Shadow.Cooldown.Visible = false
for _, manageTools in gui.ManageTools.List:GetChildren() do
if not manageTools:IsA("TextButton")then
continue
end
manageTools.Active = true
manageTools.Shadow.Visible = false
end
end
-- Process each ability button
for _, ability in pairs(button.Parent:GetChildren()) do
if not ability:IsA("ImageButton") then
continue
end
ability.Active = false
ability.Shadow.Visible = true
local holdCooldown = attack:GetAttribute("HoldCooldown")
if not holdCooldown then
coroutine.wrap(handleCooldown)(ability, attackConfig["Cooldown"])
else
coroutine.wrap(function()
local result = MouseRaycast(sentryToSpawn)
while not result or not result.Instance or not workspace.Maps:IsAncestorOf(result.Instance) do
result = MouseRaycast(sentryToSpawn)
RunService.RenderStepped:Wait()
end
if ability == button then
AddPlaceholderSentry(attack)
end
-- Wait for the hold cooldown to change
attack:GetAttributeChangedSignal("HoldCooldown"):Wait()
handleCooldown(ability, attackConfig["Cooldown"])
end)()
end
end
-- Fire the server event to activate the ability
ActivateAbility:FireServer(attack, weapon)
end
activatedButton[attack] = button.Activated:Connect(onButtonActivated)
-- table.insert(activatedButton, attack == button.Activated:Connect(onButtonActivated))
-- activatedButton = button.Activated:Connect(onButtonActivated)
end
end
-- Main function that runs when the player's weapon changes its parent
local function AncestryChanged(weapon)
if not weapon then
handleWeaponDeletion()
return
end
local weaponEquipped = Players:GetPlayerFromCharacter(weapon.Parent)
if not weaponEquipped or not weapon:FindFirstChild("Abilities") then
handleWeaponRemoval(weapon)
return
end
handleWeaponAddition(weapon)
end
-- Connect the functions to the appropriate events
Backpack.ChildAdded:Connect(AncestryChanged)
Backpack.ChildRemoved:Connect(AncestryChanged)
player.Character.ChildRemoved:Connect(AncestryChanged)
local function SpawnNewSentry()
if canPlace == true then
SpawnSentry:FireServer(sentryToSpawn.Name, sentryToSpawn.PrimaryPart.CFrame)
RemovePlaceholderSentry()
end
end
UserInputService.InputBegan:Connect(function(input, processed)
if processed then
return
end
if sentryToSpawn then
if input.UserInputType == Enum.UserInputType.MouseButton1 then
SpawnNewSentry()
elseif input.UserInputType == Enum.UserInputType.Touch then
local timeSinceLastTouch = tick() - lastTouch
if timeSinceLastTouch < 0.25 then
SpawnNewSentry()
end
lastTouch = tick()
elseif input.KeyCode == Enum.KeyCode.R then -- Rotating Keycode
rotation += 45
elseif input.KeyCode == Enum.KeyCode.Q then
-- Cancelling Sentry Placement
for i, connection in activatedButton do
connection:Disconnect()
end
activatedButton = {}
print(activatedButton)
RemovePlaceholderSentry()
for _, ability in pairs(gui.Abilities:GetChildren()) do
if not ability:IsA("ImageButton") then
continue
end
ability.Shadow.Visible = false
ability.Active = true
end
local weapon = player.Character:FindFirstChild("Mechanic") or player.Backpack:FindFirstChild("Mechanic")
handleWeaponAddition(weapon)
end
elseif hoveredInstance and gui.ManageTools.List.Repair.Active == false and input.UserInputType == Enum.UserInputType.MouseButton1 then
local model = hoveredInstance:FindFirstAncestorOfClass("Model")
if model and model.Parent == workspace.Sentries and model.Config:GetAttribute("Owner") == player.Name then
selectedSentry = model
activatedRepair = nil
else
selectedSentry = nil
end
end
end)
If you’ve reached the end and know what’s going on, please leave a reply down below