Sword Abilities not working correctly

I want a system where you activate a special ability using either the text button [Most likely on ipad/phone/consoles] or where PC players press a key for it to activate i got one to work but the other is refusing to work and i have no ideas as to why

this is my code that is having problems:

-- AbilityServer
local TweenService = game:GetService("TweenService")
local Debris       = game:GetService("Debris")
local RunService   = game:GetService("RunService")

local tool = script.Parent
local cfg  = tool:WaitForChild("Config")

-- Remotes
local ShockRE = tool:WaitForChild("AbilityEvent")        -- Shockwave (E)
local SlamRE  = tool:WaitForChild("GroundSlamEvent")     -- Ground Slam (Q)

-- Shockwave config
local RADIUS    = cfg:WaitForChild("Radius").Value
local DAMAGE    = cfg:WaitForChild("Damage").Value
local KNOCKBACK = cfg:WaitForChild("Knockback").Value
local CD_SHOCK  = cfg:WaitForChild("Cooldown").Value

-- Slam config
local SLAM_RADIUS  = cfg:WaitForChild("SlamRadius").Value
local SLAM_DAMAGE  = cfg:WaitForChild("SlamDamage").Value
local SLAM_STUN    = cfg:WaitForChild("SlamStun").Value
local SLAM_UP      = cfg:WaitForChild("SlamUpForce").Value
local SLAM_DELAY   = cfg:WaitForChild("SlamDelay").Value
local CD_SLAM      = cfg:WaitForChild("SlamCooldown").Value

-- Cash
local REWARD = cfg:WaitForChild("KillReward").Value

local lastShock, lastSlam = {}, {}

-- Helpers -------------------------------------------------------
local function addCash(plr, amt)
	local ls = plr:FindFirstChild("leaderstats")
	local cash = ls and ls:FindFirstChild("Cash")
	if cash then cash.Value += amt end
end
local function awardKill(plr) if plr then addCash(plr, REWARD) end end

local function tagHum(h, killer)
	local tag = h:FindFirstChild("KillerTag")
	if not tag then
		tag = Instance.new("ObjectValue")
		tag.Name = "KillerTag"
		tag.Parent = h
		h.Died:Connect(function()
			if tag.Value then awardKill(tag.Value) end
			tag:Destroy()
		end)
		Debris:AddItem(tag, 8)
	end
	tag.Value = killer
end

local function ring(cf, size)
	local p = Instance.new("Part")
	p.Anchored, p.CanCollide = true, false
	p.Material = Enum.Material.Neon
	p.Color = Color3.new(1,1,1)
	p.Transparency = 0.5
	p.Size = Vector3.new(1,0.2,1)
	p.CFrame = cf
	Instance.new("CylinderMesh", p)
	p.Parent = workspace

	TweenService:Create(p, TweenInfo.new(0.25, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
		{Size = Vector3.new(size*2,0.2,size*2), Transparency = 0.2}):Play()
	task.delay(0.25, function()
		TweenService:Create(p, TweenInfo.new(0.15), {Transparency = 1}):Play()
		task.delay(0.15, function() p:Destroy() end)
	end)
end

local function hitHumanoids(originPos, r, ignoreChar, damage, killer, extraFn)
	local params = OverlapParams.new()
	params.FilterType = Enum.RaycastFilterType.Exclude
	params.FilterDescendantsInstances = {ignoreChar}

	local hit = {}
	for _, part in ipairs(workspace:GetPartBoundsInRadius(originPos, r, params)) do
		local hum = part.Parent and part.Parent:FindFirstChildOfClass("Humanoid")
		if hum and hum.Health > 0 and not hit[hum] then
			hit[hum] = true
			tagHum(hum, killer)

			local oldHP = hum.Health
			if damage > 0 then hum:TakeDamage(damage) end
			if oldHP > 0 and oldHP - damage <= 0 then awardKill(killer) end

			if extraFn then extraFn(hum) end
		end
	end
end
-- ---------------------------------------------------------------

-- Shockwave (E)
ShockRE.OnServerEvent:Connect(function(plr)
	local now = os.clock()
	if lastShock[plr] and now - lastShock[plr] < CD_SHOCK then return end
	lastShock[plr] = now

	local char = plr.Character
	local root = char and char:FindFirstChild("HumanoidRootPart")
	if not root then return end

	ring(root.CFrame, RADIUS)

	hitHumanoids(root.Position, RADIUS, char, DAMAGE, plr, function(h)
		local er = h.Parent:FindFirstChild("HumanoidRootPart")
		if er then
			local dir = (er.Position - root.Position).Unit
			local bv  = Instance.new("BodyVelocity")
			bv.MaxForce = Vector3.new(1e6,1e6,1e6)
			bv.Velocity = dir * KNOCKBACK + Vector3.new(0,20,0)
			bv.Parent = er
			Debris:AddItem(bv, 0.25)
		end
	end)
end)

-- Ground Slam (Q) with landing detection
local function stun(h, secs)
	local ws, jp = h.WalkSpeed, h.JumpPower
	h.WalkSpeed, h.JumpPower = 0, 0
	task.delay(secs, function()
		if h and h.Parent then
			h.WalkSpeed, h.JumpPower = ws, jp
		end
	end)
end

SlamRE.OnServerEvent:Connect(function(plr)
	local now = os.clock()
	if lastSlam[plr] and now - lastSlam[plr] < CD_SLAM then return end
	lastSlam[plr] = now

	local char = plr.Character
	local root = char and char:FindFirstChild("HumanoidRootPart")
	local hum  = char and char:FindFirstChildOfClass("Humanoid")
	if not root or not hum then return end

	-- launch up
	local bv = Instance.new("BodyVelocity")
	bv.MaxForce = Vector3.new(1e6,1e6,1e6)
	bv.Velocity = Vector3.new(0, SLAM_UP, 0)
	bv.Parent   = root
	Debris:AddItem(bv, 0.25)

	-- minimum air time
	task.wait(SLAM_DELAY)

	-- wait for landing or timeout
	local landed  = false
	local timeout = 1.5
	local t0 = os.clock()

	local stateConn
	stateConn = hum.StateChanged:Connect(function(_, newState)
		if newState == Enum.HumanoidStateType.Landed
			or newState == Enum.HumanoidStateType.Running
			or newState == Enum.HumanoidStateType.RunningNoPhysics then
			landed = true
		end
	end)

	while not landed and os.clock() - t0 < timeout do
		local params = RaycastParams.new()
		params.FilterType = Enum.RaycastFilterType.Exclude
		params.FilterDescendantsInstances = {char}
		local hit = workspace:Raycast(root.Position, Vector3.new(0,-6,0), params)
		if hit then landed = true break end
		RunService.Heartbeat:Wait()
	end
	if stateConn then stateConn:Disconnect() end

	-- impact
	local slamPos = root.Position
	ring(root.CFrame, SLAM_RADIUS)

	hitHumanoids(slamPos, SLAM_RADIUS, char, SLAM_DAMAGE, plr, function(h)
		stun(h, SLAM_STUN)
		local er = h.Parent:FindFirstChild("HumanoidRootPart")
		if er then
			local dir = (er.Position - slamPos).Unit
			local kb = Instance.new("BodyVelocity")
			kb.MaxForce = Vector3.new(1e6,1e6,1e6)
			kb.Velocity = dir * 30 + Vector3.new(0,35,0)
			kb.Parent = er
			Debris:AddItem(kb, 0.25)
		end
	end)
end)

If you have any questions feel free to ask below

well the fact that the server isn’t even receiving the other presses likely means that the issue is on the client sided code

mind sharing the code that makes “Q pressed, firing server” logs as well as the other code for the shock instead, and also the mobile buttons so we can fix this?

1 Like

Thank you I will share the code now the buttons appear for any device to tell the user what buttons it is to use they work for any device but its more useful for console/mobile users, sorry for the late reply as I live in the U.K, here is the code:

-- AbilityClient.lua  (LocalScript inside Katana)
local Players = game:GetService("Players")
local CAS     = game:GetService("ContextActionService")

local tool     = script.Parent
local shockRE  = tool:WaitForChild("AbilityEvent")       -- Shockwave remote
local slamRE   = tool:WaitForChild("GroundSlamEvent")    -- Ground Slam remote

-- Action names must be unique per tool
local SHOCK_ACTION = "UseShock_" .. tool:GetDebugId()
local SLAM_ACTION  = "UseSlam_"  .. tool:GetDebugId()

local function onShock(actionName, inputState, inputObject)
    if inputState == Enum.UserInputState.Begin then
        print("[CLIENT] E pressed, firing Shockwave")
        shockRE:FireServer()
    end
end

local function onSlam(actionName, inputState, inputObject)
    if inputState == Enum.UserInputState.Begin then
        print("[CLIENT] Q pressed, firing GroundSlam")
        slamRE:FireServer()
    end
end

tool.Equipped:Connect(function()
    -- bind E and Q
    CAS:BindAction(SHOCK_ACTION, onShock, false, Enum.KeyCode.E)
    CAS:BindAction(SLAM_ACTION,  onSlam,  false, Enum.KeyCode.Q)
    print("[CLIENT] Tool equipped, actions bound")
end)

tool.Unequipped:Connect(function()
    -- unbind so we don’t leak
    CAS:UnbindAction(SHOCK_ACTION)
    CAS:UnbindAction(SLAM_ACTION)
    print("[CLIENT] Tool unequipped, actions unbound")
end)

well, considering you are using ContextActionService and NOT UserInputService, only one input key can be bounded at a time because it sinks the input; this means the E keycode is being used in another place.

you can remedy this by binding the action at a higher level using BindActionAtPriority

-CAS:BindAction(SHOCK_ACTION, onShock, false, Enum.KeyCode.E)
+CAS:BindActionAtPriority(SHOCK_ACTION, onShock, false, 2000, Enum.KeyCode.E)
-CAS:BindAction(SLAM_ACTION,  onSlam,  false, Enum.KeyCode.Q)
+CAS:BindActionAtPriority(SLAM_ACTION,  onSlam,  false, 2000, Enum.KeyCode.Q)

full snippet:

CAS:BindActionAtPriority(SHOCK_ACTION, onShock, false, 2000, Enum.KeyCode.E)
CAS:BindActionAtPriority(SLAM_ACTION,  onSlam,  false, 2000, Enum.KeyCode.Q)
1 Like

I tried this but it didnt seem to work, maybe i have other scripts interfering

you can use the Ctrl + Shift + F feature and search for every other script that uses ContextActionService, and maybe then you’ll be able to figure out what’s sinking it

i don’t think it’s a corescript sinking it because the keycode E is only used contextually and does not link to a globally used keybind so i’m pretty certain it is another script in your game

1 Like

Sorry for my late reply, I was able to get the character to fling in the air in a stable manor, but the effect for when the player lands on button Q doesn’t work as intended, its meant to fire a red circle out when they land but it doesn’t do this.

local tool      = script.Parent
local abilityRE = tool:WaitForChild("AbilityEvent")
local TweenService = game:GetService("TweenService")

-- Raycast helper to find the ground point
local function getGroundPosition(origin, character)
	local params = RaycastParams.new()
	params.FilterDescendantsInstances = { character }
	params.FilterType = Enum.RaycastFilterType.Blacklist
	local ray = workspace:Raycast(origin, Vector3.new(0, -500, 0), params)
	return ray and ray.Position
end

abilityRE.OnServerEvent:Connect(function(player, abilityName)
	local char     = player.Character
	if not char then return end
	local hrp      = char:FindFirstChild("HumanoidRootPart")
	local humanoid = char:FindFirstChild("Humanoid")
	if not (hrp and humanoid) then return end

	if abilityName == "Shockwave" then
		-- your existing Shockwave code

	elseif abilityName == "Slam" then
		-- flag so only the next land triggers the ring
		local slamActive = true

		-- listen for landing
		local conn
		conn = humanoid.StateChanged:Connect(function(_, newState)
			if newState == Enum.HumanoidStateType.Landed and slamActive then
				slamActive = false
				conn:Disconnect()

				-- find exact ground point
				local groundPos = getGroundPosition(hrp.Position, char)
				if not groundPos then
					groundPos = hrp.Position - Vector3.new(0, hrp.Size.Y/2 + 0.1, 0)
				end

				-- create part (base size = full final diameter)
				local ringPart = Instance.new("Part")
				ringPart.Anchored    = true
				ringPart.CanCollide  = false
				ringPart.CastShadow  = false
				ringPart.Size        = Vector3.new(20, 1, 20)
				ringPart.CFrame      = CFrame.new(groundPos) * CFrame.Angles(math.rad(90), 0, 0)
				ringPart.Material    = Enum.Material.Neon
				ringPart.BrickColor  = BrickColor.new("Really red")
				ringPart.Color       = Color3.fromRGB(255, 0, 0)
				ringPart.Transparency= 0
				ringPart.TopSurface    = Enum.SurfaceType.SmoothNoOutlines
				ringPart.BottomSurface = Enum.SurfaceType.SmoothNoOutlines
				ringPart.SideSurface   = Enum.SurfaceType.SmoothNoOutlines
				ringPart.Parent     = workspace

				-- add a CylinderMesh that's initially tiny (5% scale)
				local mesh = Instance.new("CylinderMesh")
				mesh.Scale = Vector3.new(0.05, 1, 0.05)
				mesh.Parent = ringPart

				-- tween the mesh to full size and the part to fade out
				local ti = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
				local meshTween = TweenService:Create(mesh, ti, { Scale = Vector3.new(1, 1, 1) })
				local partTween = TweenService:Create(ringPart, ti, { Transparency = 1 })

				meshTween:Play()
				partTween:Play()
				partTween.Completed:Connect(function()
					ringPart:Destroy()
				end)
			end
		end)

		-- now launch upward
		humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
		local bv = Instance.new("BodyVelocity")
		bv.Velocity = Vector3.new(0, 100, 0)  -- tweak height
		bv.MaxForce = Vector3.new(0, 1e5, 0)
		bv.P        = 1000
		bv.Parent   = hrp
		task.delay(0.35, function() if bv.Parent then bv:Destroy() end end)
	end
end)
``` I have other code that could be interfering if you want to see them ask