heres server script
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Debris = game:GetService("Debris")
local DAMAGE = 12.5
local REACH = 8
local COOLDOWN = 0.4
local EQUIP_ANIM_ID = "rbxassetid://128332336030490"
local ATTACK_ANIM_ID = "rbxassetid://109333098941141"
local HIT_SOUND_ID = "rbxassetid://7171761940"
local KatanaRemote = ReplicatedStorage:FindFirstChild("KatanaHit")
local StateRemote = ReplicatedStorage:FindFirstChild("KatanaState")
local ShowDamageRemote = ReplicatedStorage:FindFirstChild("ShowDamage")
local lastAttack = {}
local animData = {}
local function getCharacterHum(player)
local char = player.Character
if not char then return nil, nil end
local hum = char:FindFirstChildOfClass("Humanoid")
local hrp = char:FindFirstChild("HumanoidRootPart") or char:FindFirstChild("Torso")
return hum, hrp
end
local function getKatanaTool(player)
local char = player.Character
if not char then return nil end
for _, child in ipairs(char:GetChildren()) do
if child:IsA("Tool") and child.Name == "Katana" then
return child
end
end
return nil
end
local function stopAllTracks(player)
local data = animData[player]
if not data then return end
if data.idleTrack then
data.idleTrack:Stop(0)
data.idleTrack = nil
end
if data.attackTrack then
data.attackTrack:Stop(0)
data.attackTrack = nil
end
end
local function ensureAnimData(player)
local data = animData[player]
if data then
return data
end
local hum = select(1, getCharacterHum(player))
if not hum then return nil end
data = {
hum = hum,
idleTrack = nil,
attackTrack = nil,
}
animData[player] = data
hum.Died:Connect(function()
stopAllTracks(player)
end)
return data
end
local function playIdle(player)
local data = ensureAnimData(player)
if not data or not data.hum then return end
stopAllTracks(player)
local idleAnim = Instance.new("Animation")
idleAnim.AnimationId = EQUIP_ANIM_ID
local track = data.hum:LoadAnimation(idleAnim)
track.Looped = true
track.Priority = Enum.AnimationPriority.Idle
track:Play()
data.idleTrack = track
end
local function playAttack(player)
local data = ensureAnimData(player)
if not data or not data.hum then return end
if data.attackTrack then
data.attackTrack:Stop(0)
end
local anim = Instance.new("Animation")
anim.AnimationId = ATTACK_ANIM_ID
local track = data.hum:LoadAnimation(anim)
track.Looped = false
track.Priority = Enum.AnimationPriority.Action4
track:Play()
data.attackTrack = track
end
local function playHitSound(player)
local _, hrp = getCharacterHum(player)
if not hrp then return end
local tool = getKatanaTool(player)
local parent = tool and tool:FindFirstChild("Handle") or hrp
local sound = Instance.new("Sound")
sound.SoundId = HIT_SOUND_ID
sound.Volume = 1
sound.Parent = parent
sound:Play()
Debris:AddItem(sound, 3)
end
StateRemote.OnServerEvent:Connect(function(player, state)
if type(state) ~= "string" then return end
if state == "Equipped" then
if getKatanaTool(player) then
playIdle(player)
end
elseif state == "Unequipped"
or state == "Removed"
or state == "CharRemoving" then
stopAllTracks(player)
end
end)
KatanaRemote.OnServerEvent:Connect(function(player, targetPart)
if typeof(player) ~= "Instance" or not player:IsA("Player") then return end
if not targetPart or not targetPart:IsA("BasePart") then return end
local now = tick()
if lastAttack[player] and now - lastAttack[player] < COOLDOWN then
return
end
lastAttack[player] = now
local hum, hrp = getCharacterHum(player)
if not hum or not hrp then return end
if not getKatanaTool(player) then
return
end
local victimModel = targetPart:FindFirstAncestorOfClass("Model")
if not victimModel then return end
local victimHum = victimModel:FindFirstChildOfClass("Humanoid")
if not victimHum or victimHum.Health <= 0 then return end
if victimModel == player.Character then
return
end
local dist = (hrp.Position - targetPart.Position).Magnitude
if dist > REACH then
return
end
playAttack(player)
victimHum:TakeDamage(DAMAGE)
playHitSound(player)
if ShowDamageRemote then
ShowDamageRemote:FireAllClients(
targetPart.Position + Vector3.new(0, 2, 0),
DAMAGE,
false
)
end
end)
Players.PlayerRemoving:Connect(function(player)
stopAllTracks(player)
animData[player] = nil
lastAttack[player] = nil
end)
here local
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local player = Players.LocalPlayer
local tool = script:FindFirstAncestorOfClass("Tool")
local hitRemote = ReplicatedStorage:WaitForChild("KatanaHit")
local stateRemote = ReplicatedStorage:WaitForChild("KatanaState")
local ATTACK_COOLDOWN = 0.4
local mouse = player:GetMouse()
local canAttack = true
local function sendState(state)
if stateRemote then
stateRemote:FireServer(state)
end
end
tool.Equipped:Connect(function()
sendState("Equipped")
end)
tool.Unequipped:Connect(function()
sendState("Unequipped")
end)
tool.AncestryChanged:Connect(function(_, newParent)
local char = player.Character
local backpack = player:FindFirstChild("Backpack")
if not newParent then
sendState("Removed")
return
end
if newParent ~= char and newParent ~= backpack then
sendState("Removed")
end
end)
player.CharacterRemoving:Connect(function()
sendState("CharRemoving")
end)
tool.Activated:Connect(function()
if not canAttack then return end
local target = mouse.Target
if target and target:IsA("BasePart") then
hitRemote:FireServer(target)
end
canAttack = false
task.delay(ATTACK_COOLDOWN, function()
canAttack = true
end)
end)
