Help with scripting a sword

Yes, you definitely need a remote event. You are correct that you could use a remote event to change the bool value, and then run the hit code on the server, but this will not be perfect either since the players bool will have slight delay and may not be perfectly matched to their attack animation (ex. A player attacks, but the bool takes longer to register than the hit, and thus no damage is dealt).

So what was the alternative we decided on (in basic terms) that can run it without issues?

If this is not simple enough of an explanation, I will do my best to make if in fewer, simpler terms.

Thank you for the reminder. I have everything back to normal (I think) and the sword plays the animations but does not deal damage.
My current server script is the one you made above, with anti-lag and anti-exploit.
My current local script is this:
local CanAttack = true

local Attack_Animations = script.Parent:WaitForChild("Animations")

local Attack_Num = 1

local Anim_Name = "Attack"

local Audio = script.Parent.Handle.Swing

local trail = script.Parent.SwordBlade.Trail

script.Parent.Equipped:Connect(function()

local idle = script.Parent.Parent.Humanoid:LoadAnimation(script.Parent.Animations.Idle)

idle:Play()

script.Parent.Unequipped:Connect(function()

idle:Stop()

end)

end)

script.Parent.Activated:Connect(function()

game.ReplicatedStorage.Damage:FireServer()

local Animation = script.Parent.Parent.Humanoid:LoadAnimation(Attack_Animations[Anim_Name..Attack_Num])

if CanAttack == true then

Animation:Play()

Audio.PlaybackSpeed = math.random(90,110)/100

Audio:Play()

trail.Enabled = true

CanAttack = false

wait(0.65)

Animation:Stop()

Audio:Stop()

trail.Enabled = false

CanAttack = true

if Attack_Num == 1 then

Attack_Num = Attack_Num + 1

else if Attack_Num == 2 then

Attack_Num = 1

end

end

end

end)

It keeps pasting and formatting weird, sorry if something is off.

We made some changes earlier in this thread that you need to incorporate into your local script. If you are still not sure what needs to be done after reading the below code, don’t hesitate to ask!

Edit: is there a way to highlight text? It would be helpful for pointing out the specific lines to be noted.

Everything works, but it just doesn’t deal damage. The problem would have to be in the server script, I’m guessing. Also, if you select/highlight over text with your mouse you can quote certain areas.

Nevermind once again, I fixed it. In your code in the server script, you accidentally had the inequality sign as greater than instead of less than. So it would only deal damage if you were 40 studs or more away.
Edit: The sword still deals idle damage

1 Like

Haha! Good catch! Glad it is working for you now, I apologize for the typo.

My mistake, I should’ve tested before posting. The sword does idle damage, which can be fixed by adding a line in the local script.

blade.Touched:Connect(function(hit)
	if CanAttack == false then  --Add this.
		game.ReplicatedStorage.Damage:FireServer(hit)
	end
end)

That was one of the things I was referring to for you local script fixes. We covered that earlier in this article. Glad you were able to fix that on your own!

How could I add more weapons, now that I have that one working? The server script applies for every weapon in the game, and what if I wanted to change damage?

I would create a table on the server with each of the weapons names and damages. Then when the deal damage function is called on the server, deal the damage of the table[weapon.Name].

damageTable = {}
damageTable[weapon.Name] = 30
1 Like

I don’t really know how tables work, and how I could integrate that into my current code. For example, if I have another tool named Longsword, how could I add that?

As long as each of the weapons has a unique name, you can create a dictionary of their names and damages like so.

local weaponsAndDamages = {}
weaponsAndDamages ["Longsword"] = 30
weaponsAndDamages ["Spear"] = 25
weaponsAndDamages ["Dagger"] = 15
weaponsAndDamages ["Great Sword"] = 50

Then in your damaging code;

hit.Parent.Humanoid:TakeDamage(weaponsAndDamages[Weapon.Name])
1 Like

Another problem, how can I change the attack rate? In the serverscript, we made sure the last attack was 0.5 or more seconds ago so it can’t be spammed by exploiters. In the great sword for example, it would be a much slower attack opposed to a dagger.
edit: I’m guessing another table will work, so that is what I will try.

--working code--
local weaponsAndDamages = {}
weaponsAndDamages [“Sword”] = 35
weaponsAndDamages [“Spear”] = 35
weaponsAndDamages [“Dagger”] = 27
weaponsAndDamages [“Longsword”] = 55

local weaponsAndRates = {}
weaponsAndRates ["Sword"] = 0.5
weaponsAndRates ["Spear"] = 0.5
weaponsAndRates ["Dagger"] = 0.3
weaponsAndRates ["Longsword"] = 1

local lastAttack = {}
game.ReplicatedStorage.Damage.OnServerEvent:Connect(function(player, hit)
    local weapon = player.Character:FindFirstChildWhichIsA("Tool") -- obtain the sword of the player attacking
    if hit.Parent:FindFirstChild("Humanoid") ~= nil and player.Character ~= nil then
        if hit.Parent.Humanoid.Health > 0 and player.Character.Humanoid.Health > 0 then -- check if the users are alive, we don't want dead players dealing damage, or players dealing damage to dead players.
            if lastAttack[player.Name] == nil or tick() - lastAttack[player.Name] > weaponsAndRates[weapon.Name] then
                if (hit.Parent.HumanoidRootPart.Position-player.Character.HumanoidRootPart.Position).magnitude < 40 then -- went with 40 just in case of serious latency. You can tweak this if wanted.
                    lastAttack[player.Name] = tick()
                    if weapon ~= nil then -- make sure it's not nil
                  		hit.Parent.Humanoid:TakeDamage(weaponsAndDamages[weapon.Name])
                        weapon.Handle.Hit:Play() -- You want to play the hit noise on the sword of the player who is attacking, not the sword in the StarterPack.
                    end
                end
            end
        end
    end
end)

Good job! You can further simplify this by combing your dictionaries!

local weaponStats = {}
weaponStats ["Sword"] = {["Damage"] = 35, ["Rate"] = 0.5}
weaponStats ["Spear"] = {["Damage"] = 35, ["Rate"] = 0.5}
weaponStats ["Dagger"] = {["Damage"] = 27, ["Rate"] = 0.3}
weaponStats ["Longsword"] = {["Damage"] = 55, ["Rate"] = 0.1}

-- to refer to Rate
weaponStats[Weapon.Name]["Rate"]
-- to refer to Damage
weaponStats[Weapon.Name]["Damage"]

Edit: If you have solved the problem you made this topic for, you should select a post as the solution so other users can see it without reading every post. It also helps people to tell what posts already have answers so they can focus on others!

1 Like

The sound is a bit buggy. It will play the audios occasionally but most of the time it is completely silent. (attacking noise and hit noise don’t play consistently.) Do you know what could be causing this? Below is the local script for reference, and I already pasted the working server script above.

--//Idle Animation\\--
script.Parent.Equipped:Connect(function()
local idle = script.Parent.Parent.Humanoid:LoadAnimation(script.Parent.Animations.Idle)
idle:Play()
script.Parent.Unequipped:Connect(function()
idle:Stop()
end)
end)

--//Attacking Animations\\--
local UserInputService = game:GetService("UserInputService")
local Tool = script.Parent
local CanAttack = true
local Anim_Name = "Attack"
local Audio = script.Parent.Handle.Swing
local Attack_Animations = script.Parent:WaitForChild("Animations")
local Attack_Num = 1
local blade = script.Parent.SwordBlade

blade.Touched:Connect(function(hit)
	if CanAttack == false then
		game.ReplicatedStorage.Damage:FireServer(hit)
	end
end)

UserInputService.InputBegan:Connect(function(InputObject)
	if InputObject.UserInputType == Enum.UserInputType.MouseButton1 then
		local Animation = script.Parent.Parent.Humanoid:LoadAnimation(Attack_Animations[Anim_Name..Attack_Num])
		if CanAttack == true then
            CanAttack = false
			Animation:Play()
			Audio.PlaybackSpeed = math.random(0.9,1.1)
			Audio:Play()
			blade.Trail.Enabled = true
			wait(0.5)
			CanAttack = true
			blade.Trail.Enabled = false
			if Attack_Num == 1 then
				Attack_Num = Attack_Num + 1
				else if Attack_Num == 2 then
					Attack_Num = 1
				end
			end
		end
	end
end)

after further testing, it has something to do with having the playbackspeed and my math.random. I have to use division to get the numbers because they aren’t integers.

1 Like