local RE = game:GetService("ReplicatedStorage").Remotes.AbilityRemote1
local AniRE = game:GetService("ReplicatedStorage").Remotes.AniRemote
local VFXRE = game:GetService("ReplicatedStorage").Remotes.VFXRemote -- New RemoteEvent for VFX
local HitM = require(game.ServerScriptService.Modules.MuchachoHitbox)
local AbilityData = require(game.ServerScriptService.Modules.AbilityData)
local ds = game:GetService("Debris")
local VFXModule = require(game.ServerScriptService.Modules.VFXModule)
local SoundRE = game:GetService("ReplicatedStorage").Remotes.SoundRE
local playerCooldowns = {}
RE.OnServerEvent:Connect(function(Player, MoveName)
local Character = Player.Character
local Humanoid = Character:FindFirstChild("Humanoid")
local HRP = Character:FindFirstChild("HumanoidRootPart")
if Humanoid.Health == 0 then return end
local ownedFolder = Player:FindFirstChild("ownedFolder")
local moveObject = ownedFolder:FindFirstChild("PowerPunch")
if not Player or not Player.Character then return end
if playerCooldowns[Player] then return end
if MoveName ~= "PowerPunch" then return end
if moveObject.Value == false then print("move not owned") return end
playerCooldowns[Player] = true
if not Humanoid or not HRP then return end
local HitB = HitM.CreateHitbox()
local HData = AbilityData:GetWeapon(MoveName)
local params = OverlapParams.new()
params.FilterType = Enum.RaycastFilterType.Exclude
params.FilterDescendantsInstances = {Character}
HitB.Offset = HData.HitboxOffset
HitB.Size = HData.HitboxSize
HitB.CFrame = HRP
HitB.OverlapParams = params
HitB.Visualizer = false
SoundRE:FireAllClients(Player, HData.SoundID2)
local AniID = HData.AniID
if AniID then
AniRE:FireClient(Player, AniID)
else
print(MoveName, "No animation found")
end
local bv = Instance.new("BodyVelocity")
bv.Parent = HRP
bv.MaxForce = Vector3.new(99999, 99999, 99999)
bv.Velocity = HRP.CFrame.LookVector * 250
ds:AddItem(bv, 0.05)
HitB.Touched:Connect(function(hit, EHum)
print(hit)
SoundRE:FireAllClients(Player, HData.SoundID)
local bv2 = Instance.new("BodyVelocity", hit)
bv2.MaxForce = Vector3.new(99999, 99999, 99999)
local lookVector = HRP.CFrame.LookVector
local horizontalVector = Vector3.new(lookVector.X, 0, lookVector.Z).unit
bv2.Velocity = horizontalVector * Vector3.new(200000000000, 500, 1)
local vfxPosition = hit.Position
local vfxName = VFXModule.PowerPunchShock.Name
local vfxDuration = 2
VFXRE:FireAllClients(vfxName, vfxPosition, vfxDuration)
EHum:TakeDamage(HData.Damage)
local creator = Instance.new("ObjectValue")
creator.Name = "creator"
creator.Value = Player
creator.Parent = EHum
ds:AddItem(creator, 30)
bv:Destroy()
ds:AddItem(bv2, 0.4)
end)
local CD = HData.CD
-- Start hitbox
coroutine.wrap(function()
HitB:Start()
task.wait(0.75)
HitB:Stop()
end)()
print("powerPunchFired")
RE:FireClient(Player, MoveName,HData.CD)
task.wait(CD)
playerCooldowns[Player] = nil
end)
I have like 5 different abilities coded like poop, and I’m just wondering if there’s a better way to do this or how more experienced scripters would write abilities. My guess is module scripts but I’m horrible at writing them so I’m not sure how to further use OOP to optimise my code.
first, instead of typing huge numbers, do math.huge (unless it’s a specific huge number)
instead of getting ReplicatedStorage, make one variable local ReplicatedStorage = game:GetService("ReplicatedStorage") and use that variable to make your code look cleaner.
probably unrelated, but BodyVelocity is also deprecated, I suggest you using LinearVelocity or something else.
if you want more code readability i suggest you make space for your code like this:
local Character = Player.Character
local Humanoid = Character:FindFirstChild("Humanoid")
local HRP = Character:FindFirstChild("HumanoidRootPart")
if Humanoid.Health == 0 then return end
local ownedFolder = Player:FindFirstChild("ownedFolder")
local moveObject = ownedFolder:FindFirstChild("PowerPunch")
if not Player or not Player.Character then return end
if playerCooldowns[Player] then return end
if MoveName ~= "PowerPunch" then return end
if moveObject.Value == false then print("move not owned") return end
playerCooldowns[Player] = true
it looks SO much better rather than having them all compact.
I’m a little confused here, your remote Reference is AbilityRemote1, I’m guessing each ability / skill has it’s own remote? But at the same time you receive MoveName in OnServerEvent.
I suggest making AbilityModule that handles all abilities / skills usage with one remote, vfx and main script also seperated.
Also don’t use .Touched for hitbox since it’s really exploitable, I suggest using GetPartBoundsInBox
I used to have this problem but i fixed it by making systems that use folders to determine items and one single module script that uses these folders to set up the abilities rather than putting them in one script (example of an enemy system i made)
Oh, originally I was going to do each ability have its own remote, but I sorta scrapped that since having like 200 remotes didn’t really appeal to me, so I’m only using one remote for every move.
I don’t think I can use GetPartBoundsInBox for the module I’m using, but I’ll consider it next time when scripting!
The script itself works fine, I was just wondering if there were better ways to code it because I feel like what I’ve written is messy and redundant code
A good tip for game dev is just to code everything like you are giving it to someone else to use (i started doing this and my scripts became much cleaner)
I actually got the opposite advice when I was first starting out which was just to write the code and not worry about it being messy. I rarely work with other people or even post about anything at all so I’ve just followed that ever since. Anyways thanks for sharing again!
Its fine to have messy code, take undertale for example (the code is all over the place), but if you want to make your life easier for yourself in future then write clean code for big systems but little things are ok to be messy