-- src/StarterPlayer/StarterCharacterScripts/AxeController.client.lua -- Handles both fist punching and axe chopping local Players = game:GetService("Players") local UserInputService = game:GetService("UserInputService") local ReplicatedStorage = game:GetService("ReplicatedStorage") local CollectionService = game:GetService("CollectionService") local player = Players.LocalPlayer local mouse = player:GetMouse() local character = player.Character or player.CharacterAdded:Wait() local ChoppingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("ChoppingConfig")) local CraftingConfig = require(ReplicatedStorage:WaitForChild("Shared"):WaitForChild("CraftingConfig")) local ChopEvent = ReplicatedStorage:WaitForChild("Events"):WaitForChild("ChopEvent") local canSwing = true local function getCurrentWeapon() local axeType = nil if character then axeType = character:GetAttribute("EquippedAxe") end if not axeType or axeType == "" then axeType = player:GetAttribute("EquippedAxe") end -- No axe = use fists if not axeType or axeType == "" or axeType == "None" then return CraftingConfig.Fist, "Fist" end local stats = ChoppingConfig.AxeTypes[axeType] if stats then return stats, axeType end return CraftingConfig.Fist, "Fist" end local function playSwingAnimation(weaponType) local humanoid = character:FindFirstChildOfClass("Humanoid") if not humanoid then return end local camera = workspace.CurrentCamera if camera then task.spawn(function() local shake = weaponType == "Fist" and 1 or 2 for i = 1, 3 do camera.CFrame = camera.CFrame * CFrame.Angles(0, 0, math.rad(-shake + i * (shake * 0.6))) task.wait(0.03) end end) end end local function createHitEffect(position, weaponType) local part = Instance.new("Part") part.Size = Vector3.new(0.4, 0.4, 0.4) part.Position = position part.Anchored = true part.CanCollide = false part.Material = Enum.Material.Neon part.Shape = Enum.PartType.Ball part.Parent = workspace.Terrain if weaponType == "Fist" then part.BrickColor = BrickColor.new("Bright orange") else part.BrickColor = BrickColor.new("Bright yellow") end task.spawn(function() for i = 1, 5 do part.Size = part.Size * 1.3 part.Transparency = i / 5 task.wait(0.03) end part:Destroy() end) end local function onInputBegan(input, gameProcessed) if gameProcessed then return end if input.UserInputType == Enum.UserInputType.MouseButton1 then if not canSwing then return end if not character or not character:FindFirstChild("Head") then return end local weaponStats, weaponType = getCurrentWeapon() local rayOrigin = character.Head.Position local rayDirection = (mouse.Hit.Position - rayOrigin).Unit * weaponStats.Range local raycastParams = RaycastParams.new() raycastParams.FilterDescendantsInstances = {character} raycastParams.FilterType = Enum.RaycastFilterType.Exclude local raycastResult = workspace:Raycast(rayOrigin, rayDirection, raycastParams) if raycastResult and raycastResult.Instance then local hitPart = raycastResult.Instance -- Only chop tree segments if CollectionService:HasTag(hitPart, "TreeSegment") then playSwingAnimation(weaponType) createHitEffect(raycastResult.Position, weaponType) ChopEvent:FireServer(hitPart, raycastResult.Position) end end -- Cooldown applies even on miss (animation commitment) canSwing = false task.wait(weaponStats.SwingCooldown) canSwing = true end end player.CharacterAdded:Connect(function(char) character = char end) UserInputService.InputBegan:Connect(onInputBegan)