0% found this document useful (0 votes)
29 views12 pages

Roblox Combat Script: Hitbox & Clash System

The document outlines a Lua script for a combat system in a game, specifically detailing the structure and functions related to handling player interactions, damage calculations, and visual effects during combat. It includes functions for managing hit detection, blocking, parrying, and clash effects, as well as configurations for damage output based on player actions. The script is designed to work within a specific folder structure in Roblox, ensuring proper functionality and integration with other game components.

Uploaded by

yihitosama
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
29 views12 pages

Roblox Combat Script: Hitbox & Clash System

The document outlines a Lua script for a combat system in a game, specifically detailing the structure and functions related to handling player interactions, damage calculations, and visual effects during combat. It includes functions for managing hit detection, blocking, parrying, and clash effects, as well as configurations for damage output based on player actions. The script is designed to work within a specific folder structure in Roblox, ensuring proper functionality and integration with other game components.

Uploaded by

yihitosama
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as TXT, PDF, TXT or read online on Scribd

-- Parent REQUIRED: this Script must be a child of the RemoteEvent named "Server"

-- Structure expected:
-- HitboxSettingsRapierStyle (Folder)
-- Server (RemoteEvent)
-- Handler (Script) ← this file
-- A1..A6, ParryAnim, GBFX/BlockFX/PBFX folders, DmgCounter, HitFX, PunchSound,
DirtParticle, Slide, SmokeWave, Rock, GB, etc.

local ReplicatedStorage = game:GetService("ReplicatedStorage")


local TweenService = game:GetService("TweenService")
local Players = game:GetService("Players")

local CombatFolder = ReplicatedStorage:WaitForChild("Combat")

-- Values (safe shim so we never crash if CreateValue signature differs)


local okValues, Values = pcall(function()
return require(CombatFolder:WaitForChild("Values"))
end)
local function createValue(className, parent, name, initialValue, lifetimeSeconds)
if okValues and type(Values) == "table" and type([Link]) ==
"function" then
local fn = [Link]
local ok1 = pcall(function() fn(className, parent, name, initialValue,
lifetimeSeconds) end)
if ok1 then return end
pcall(function() fn(Values, className, parent, name, initialValue,
lifetimeSeconds) end)
return
end
local instOk, inst = pcall([Link], className)
if not instOk then return end
[Link] = name or className
if inst:IsA("BoolValue") and typeof(initialValue) == "boolean" then
[Link] = initialValue
elseif inst:IsA("NumberValue") and typeof(initialValue) == "number" then
[Link] = initialValue
elseif inst:IsA("StringValue") and typeof(initialValue) == "string" then
[Link] = initialValue
end
[Link] = parent
if typeof(lifetimeSeconds) == "number" and lifetimeSeconds > 0 then
[Link]:AddItem(inst, lifetimeSeconds)
end
end

local StunController = require(CombatFolder:WaitForChild("StunController"))


local HitConfirmed = CombatFolder:WaitForChild("HitConfirmed")
local PostureService = require(CombatFolder:WaitForChild("PostureService"))

local function hasActiveFlag(model, name)


local inst = model:FindFirstChild(name)
if not inst then return false end
if inst:IsA("BoolValue") then
return [Link] == true
end
return true
end

local DamageConfig = {
M1ByCombo = { [1]=5, [2]=5, [3]=5, [4]=5, [5]=10 },
A6PerHit = 3, -- 4 hits => total 12
}

-- Stress per blocked hit (tune for rapier cadence)


local STRESS_PER_BLOCKED_HIT = 20

local function getServerDamage(comboNumber)


comboNumber = tonumber(comboNumber) or 1
if comboNumber == 6 then
return DamageConfig.A6PerHit
end
return DamageConfig.M1ByCombo[comboNumber] or DamageConfig.M1ByCombo[1]
end

local function Curve(t,p0,p1,p2)


local A = p0:Lerp(p1,t)
local B = p1:Lerp(p2,t)
return A:Lerp(B,t)
end

local function attackerHardBlocked(attackerChar)


if not attackerChar then return true end
return hasActiveFlag(attackerChar, "Stun")
or hasActiveFlag(attackerChar, "Parried")
or hasActiveFlag(attackerChar, "StopStun")
end

-- CLASH SYSTEM helpers


local function facingEachOther(HumRP, EhumRP)
if not HumRP or not EhumRP then return false end
local toTarget = ([Link] - [Link])
local toAttacker = ([Link] - [Link])
if [Link] < 0.001 or [Link] < 0.001 then return
false end
toTarget = [Link]
toAttacker = [Link]
local f1 = [Link]:Dot(toTarget) > 0.5
local f2 = [Link]:Dot(toAttacker) > 0.5
return f1 and f2
end

local function doClashFX(attackerPlr, attackerChar, targetPlr, targetChar, Hum,


HumRP, Ehum, EhumRP, scriptRef)
if not HumRP or not EhumRP then return end
local midPos = ([Link] + [Link]) * 0.5
local soundAnchor = [Link]("Part")
[Link] = "ClashSoundAnchor"
[Link] = true
[Link] = false
[Link] = 1
[Link] = [Link](0.2, 0.2, 0.2)
[Link] = [Link](midPos)
[Link] = workspace
[Link]:AddItem(soundAnchor, 2)

local clashVFX = scriptRef:FindFirstChild("ClashVFX")


if clashVFX then
local fxTemplate = clashVFX:FindFirstChild("HitFX") or clashVFX
local fxA = fxTemplate:Clone(); [Link] = HumRP;
[Link]:AddItem(fxA, 2)
for _, obj in ipairs(fxA:GetChildren()) do
local emit = obj:GetAttribute("EmitCount")
if emit then obj:Emit(emit) end
end
local fxB = fxTemplate:Clone(); [Link] = EhumRP;
[Link]:AddItem(fxB, 2)
for _, obj in ipairs(fxB:GetChildren()) do
local emit = obj:GetAttribute("EmitCount")
if emit then obj:Emit(emit) end
end
end

local clashSound = scriptRef:FindFirstChild("ClashSound")


if clashSound then
local snd = clashSound:Clone()
[Link] = soundAnchor
snd:Play()
[Link]:AddItem(snd, 3)
end

do
local DmgCounter = scriptRef:WaitForChild("DmgCounter"):Clone()
[Link] = workspace
[Link] = midPos
[Link] = "Clash"
[Link].TextColor3 = [Link](255,255,127)
[Link].TextStrokeColor3 =
[Link](255,255,255)
local info = TweenService:Create([Link],
[Link](.1, [Link], [Link], 0, true, 0),
{TextColor3 = [Link](255,255,255)})
info:Play()
[Link]:AddItem(DmgCounter, .4)
local P1 = midPos
local P2 = midPos + [Link]([Link](-3,3), [Link](2,10),
[Link](-3,3))
local P3 = P2 + [Link](0, -15, 0)
[Link](function()
for i = 0, 1, 0.045 do
local newpos = Curve(i, P1, P2, P3)
[Link] = newpos
[Link]()
end
end)
end

[Link](function()
[Link](0.2)
local tracksA = Hum:GetPlayingAnimationTracks()
local tracksB = Ehum:GetPlayingAnimationTracks()
for _, tr in ipairs(tracksA) do pcall(function() tr:AdjustSpeed(0) end)
end
for _, tr in ipairs(tracksB) do pcall(function() tr:AdjustSpeed(0) end)
end
delay(0.25, function()
for _, tr in ipairs(tracksA) do pcall(function()
tr:AdjustSpeed(1) end) end
for _, tr in ipairs(tracksB) do pcall(function()
tr:AdjustSpeed(1) end) end
end)
end)

do
local dirAtoB = ([Link] - [Link])
if [Link] > 0.001 then
dirAtoB = [Link]
local KB = 18
local t = 0.2
local BVtgt = [Link]("BodyVelocity")
[Link] = [Link](dirAtoB.X, 0, dirAtoB.Z) * KB
[Link] = [Link](30000, 0, 30000)
[Link] = EhumRP
[Link]:AddItem(BVtgt, t)
local BVatk = [Link]("BodyVelocity")
[Link] = [Link](-dirAtoB.X, 0, -dirAtoB.Z) * KB
[Link] = [Link](30000, 0, 30000)
[Link] = HumRP
[Link]:AddItem(BVatk, t)
end
end

[Link](attackerChar, 0.15)
[Link](targetChar, 0.15)
if attackerPlr then [Link]:FireClient(attackerPlr, "CLASH") end
if targetPlr then [Link]:FireClient(targetPlr, "CLASH") end
end

local function doGBFX(attackerChar, targetChar, Ehum, EhumRP, HumRP, scriptRef)


-- ... INCHANGÉ ...
local BlockFX = scriptRef:WaitForChild("GBFX"):WaitForChild("HitFX"):Clone()
[Link] = EhumRP
[Link]:AddItem(BlockFX,2)

-- Stop blocking, stop victim anims, play GB anim


for _,bv in ipairs(targetChar:GetChildren()) do
if [Link] == "Blocking" then bv:Destroy() end
end
for _,tr in ipairs(Ehum:GetPlayingAnimationTracks()) do tr:Stop() end
local GB = Ehum:LoadAnimation(scriptRef:WaitForChild("GB"))
GB:Play()
delay(1.5,function() if [Link] then GB:Stop() end end)

local Sound = scriptRef:WaitForChild("BB"):Clone()


[Link] = EhumRP
Sound:Play()
[Link]:AddItem(Sound,3)

local DmgCounter = scriptRef:WaitForChild("DmgCounter"):Clone()


[Link] = workspace
[Link] = [Link]
[Link] = "Broken"
TweenService:Create([Link],
[Link](.1,[Link],[Link],0,true,0),
{TextColor3 = [Link](255,255,255)}):Play()
[Link]:AddItem(DmgCounter,.4)
local P1 = [Link]
local P2 = [Link] + [Link]([Link](-3,3),
[Link](2,10), [Link](-3,3))
local P3 = P2 + [Link](0,-15,0)
[Link](function()
for i = 0,1,0.045 do
local newpos = Curve(i,P1,P2,P3)
[Link] = newpos
[Link]()
end
end)

local BV = [Link]("BodyVelocity",EhumRP)
[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV,.2)

local BV2 = [Link]("BodyVelocity",HumRP)


[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV2,.2)

for _,fx in ipairs(BlockFX:GetChildren()) do


local EmitCount = fx:GetAttribute("EmitCount")
if EmitCount then fx:Emit(EmitCount) end
end
[Link](targetChar, 0.2)
end

local function processHit(attackerPlr, attackerChar, targetChar, Hum, HumRP, A2,


Last, Air, ComboNumber, scriptRef)
local Ehum = targetChar:FindFirstChild("Humanoid")
local EhumRP = targetChar:FindFirstChild("HumanoidRootPart")
if not Ehum or not EhumRP or not Hum or not HumRP then return end

-- === CLASH SYSTEM === (prioritaire, ajouté)


do
local atkSwing = attackerChar:FindFirstChild("Swinging")
local tgtSwing = targetChar:FindFirstChild("Swinging")
local targetIsParrying = targetChar:FindFirstChild("PB")
local targetIsBlocking = targetChar:FindFirstChild("Blocking")
local attackerIsParrying = attackerChar:FindFirstChild("PB")
local attackerIsBlocking = attackerChar:FindFirstChild("Blocking")
if atkSwing and tgtSwing
and not targetIsParrying and not targetIsBlocking
and not attackerIsParrying and not attackerIsBlocking
and facingEachOther(HumRP, EhumRP)
then
local gotA = [Link](attackerChar, 0.2)
local gotB = [Link](targetChar, 0.2)
if gotA and gotB then
local targetPlr =
Players:GetPlayerFromCharacter(targetChar)
doClashFX(attackerPlr, attackerChar, targetPlr, targetChar,
Hum, HumRP, Ehum, EhumRP, scriptRef)
return
end
end
end
-- ... LE RESTE DE LA LOGIQUE ORIGINALE INCHANGÉE ...
local isMultiHit = (tonumber(ComboNumber) == 6)
local lockDuration = isMultiHit and (Last and 0.15 or 0.05) or 0.18
if not [Link](targetChar, lockDuration) then
return
end

if ComboNumber and ComboNumber >= 1 and ComboNumber <= 3 then


HitConfirmed:FireClient(attackerPlr, ComboNumber)
end

local LookVector1 = ([Link] - [Link]).Unit


local LookVector2 = [Link]
local DotProduct = [Link]([Link](LookVector2:Dot(LookVector1), -1,
1))

if targetChar:FindFirstChild("PB") then
local BlockFX =
scriptRef:WaitForChild("PBFX"):WaitForChild("HitFX"):Clone()
[Link] = EhumRP
[Link]:AddItem(BlockFX,2)

local AnimTracks = Hum:GetPlayingAnimationTracks()


[Link]:FireClient(attackerPlr,"PB")
[Link](function()
for _,track in ipairs(AnimTracks) do
[Link](.2)
track:AdjustSpeed(0)
delay(0.2, function() track:AdjustSpeed(1) end)
end
end)

Ehum:LoadAnimation(scriptRef:WaitForChild("ParryAnim")):Play()

local Sound = scriptRef:WaitForChild("PB"):Clone()


[Link] = EhumRP
Sound:Play()
[Link]:AddItem(Sound,3)

local DmgCounter = scriptRef:WaitForChild("DmgCounter"):Clone()


[Link] = workspace
[Link] = [Link]
[Link] = "Parry"
[Link].TextColor3 = [Link](255, 255, 127)
[Link].TextStrokeColor3 = [Link](255, 255,
255)
TweenService:Create([Link],
[Link](.1,[Link],[Link],0,true,0),
{TextColor3 = [Link](255,255,255)}):Play()
[Link]:AddItem(DmgCounter,.4)
local P1 = [Link]
local P2 = [Link] + [Link]([Link](-3,3),
[Link](2,10), [Link](-3,3))
local P3 = P2 + [Link](0,-15,0)
[Link](function()
for i = 0,1,0.045 do
local newpos = Curve(i,P1,P2,P3)
[Link] = newpos
[Link]()
end
end)

for _,fx in ipairs(BlockFX:GetChildren()) do


local EmitCount = fx:GetAttribute("EmitCount")
if EmitCount then fx:Emit(EmitCount) end
end

[Link](attackerChar)
createValue("BoolValue", attackerChar, "StopStun", false, 1)
return
end

if targetChar:FindFirstChild("Blocking") and DotProduct > 1 then


local _, _, broke = [Link](targetChar,
STRESS_PER_BLOCKED_HIT)
if broke then
doGBFX(attackerChar, targetChar, Ehum, EhumRP, HumRP, scriptRef)
return
end

local BlockFX =
scriptRef:WaitForChild("BlockFX"):WaitForChild("HitFX"):Clone()
[Link] = EhumRP
[Link]:AddItem(BlockFX,2)

local Sound = scriptRef:WaitForChild("Blocked"):Clone()


[Link] = EhumRP
Sound:Play()
[Link]:AddItem(Sound,1)

local DmgCounter = scriptRef:WaitForChild("DmgCounter"):Clone()


[Link] = workspace
[Link] = [Link]
[Link] = "Blocked"
[Link].TextColor3 = [Link](199,199,199)
[Link].TextStrokeColor3 =
[Link](152,152,152)
TweenService:Create([Link],
[Link](.1,[Link],[Link],0,true,0),
{TextColor3 = [Link](255,255,255)}):Play()
[Link]:AddItem(DmgCounter,.4)
local P1 = [Link]
local P2 = [Link] + [Link]([Link](-3,3),
[Link](2,10), [Link](-3,3))
local P3 = P2 + [Link](0,-15,0)
[Link](function()
for i = 0,1,0.045 do
local newpos = Curve(i,P1,P2,P3)
[Link] = newpos
[Link]()
end
end)

local BV = [Link]("BodyVelocity",EhumRP)
[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV,.2)
local BV2 = [Link]("BodyVelocity",HumRP)
[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV2,.2)

for _,fx in ipairs(BlockFX:GetChildren()) do


local EmitCount = fx:GetAttribute("EmitCount")
if EmitCount then fx:Emit(EmitCount) end
end
[Link](targetChar, 0.15)
return
end

-- Normal hit
local appliedDamage = getServerDamage(ComboNumber)

local stunDur = (Air and not Last) and 0.9 or 0.6


[Link](targetChar, "Stun", stunDur)
if tonumber(ComboNumber) == 6 then
if Last then [Link](targetChar, 0.15) end
else
[Link](targetChar, 0.12)
end

local DmgCounter = scriptRef:WaitForChild("DmgCounter"):Clone()


[Link] = workspace
[Link] = [Link]
[Link] = "-"..appliedDamage
TweenService:Create([Link],
[Link](.1,[Link],[Link],0,true,0),
{TextColor3 = [Link](255,255,255)}):Play()
[Link]:AddItem(DmgCounter,.4)
local P1 = [Link]
local P2 = [Link] + [Link]([Link](-3,3),
[Link](2,10), [Link](-3,3))
local P3 = P2 + [Link](0,-15,0)
[Link](function()
for i = 0,1,0.045 do
local newpos = Curve(i,P1,P2,P3)
[Link] = newpos
[Link]()
end
end)

if A2 then
Ehum:LoadAnimation(A2):Play()
end
local Sound = scriptRef:WaitForChild("PunchSound"):Clone()
[Link] = EhumRP
Sound:Play()
[Link]:AddItem(Sound,1)

if Last == false and Air == false then


local BV = [Link]("BodyVelocity",EhumRP)
[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV,.2)

elseif Last == true and Air == false then


local BV = [Link]("BodyVelocity",EhumRP)
[Link] = [Link] * 50
[Link] = [Link](55000,55000,55000)
[Link]:AddItem(BV,.4)

local rp = [Link]()
[Link] = [Link]
[Link] = {attackerChar,[Link]}
[Link] = true
local NewRay = workspace:Raycast([Link], [Link](0,-5,0),
rp)
if NewRay then
for _,vName in ipairs({"Left Leg","Right Leg"}) do
local trueColor = [Link]
local DirtParticle =
scriptRef:WaitForChild("DirtParticle"):Clone()
[Link] = [Link]{
[Link](0,trueColor),
[Link](0.5,trueColor),
[Link](1,trueColor),
}
[Link]:AddItem(DirtParticle,1)
local limb = [Link]:FindFirstChild(vName)
if limb then
local Slide = scriptRef:WaitForChild("Slide"):Clone()
[Link] = EhumRP
[Link]:AddItem(Slide,1)
[Link] = limb
delay(.5,function() [Link] = true end)
end
end
end
end

if Air == false then


local BV2 = [Link]("BodyVelocity",HumRP)
[Link] = [Link] * 10
[Link] = [Link](15000,15000,15000)
[Link]:AddItem(BV2,.2)
end

if A2 and typeof(A2) == "Instance" and A2:IsA("Animation") and [Link] ==


"TargetSlam" and Last == true then
local rp = [Link]()
[Link] = [Link]
[Link] = {attackerChar, [Link]}
[Link] = true
local hit = workspace:Raycast([Link], [Link](0,-60,0),
rp)
if hit then
if EhumRP:FindFirstChild("HoldBP") then [Link]:Destroy()
end
if HumRP:FindFirstChild("HoldBP") then [Link]:Destroy() end
local BVdown = [Link]("BodyVelocity", EhumRP)
[Link] = [Link](0,-60,0)
[Link] = [Link](55000,55000,55000)
[Link]:AddItem(BVdown, .25)

[Link](0.12, function()
local SmokeWave =
scriptRef:WaitForChild("SmokeWave"):Clone()
[Link] = workspace
[Link] = [Link] + [Link](0,.7,0)
[Link]:AddItem(SmokeWave, 1.5)
[Link]:Emit(20)
[Link]:Emit(10)
[Link]:Play()
end)
end
return
end

if Air == true and Last == false then


local BV = [Link]("BodyVelocity",EhumRP)
[Link] = [Link] * 30
[Link] = [Link](55000,55000,55000)
[Link]:AddItem(BV,.6)

local BV2 = [Link]("BodyVelocity",HumRP)


[Link] = [Link] * 30
[Link] = [Link](55000,55000,55000)
[Link]:AddItem(BV2,.6)

createValue("BoolValue", attackerChar, "Using Move", false, .31)

delay(.3,function()
local BP = [Link]("BodyPosition",EhumRP)
[Link] = [Link]
[Link] = [Link](200000,200000,200000)
BP.P = 400
[Link] = "HoldBP"
[Link]:AddItem(BP,2.0)

local BP2 = [Link]("BodyPosition",HumRP)


[Link] = [Link]
[Link] = [Link](200000,200000,200000)
BP2.P = 400
[Link] = "HoldBP"
[Link]:AddItem(BP2,2.0)
end)
end

if Air == true and Last == true then


local StartPos = ([Link] * 20) + [Link]
local Direction = [Link](0,-40,0)
local RayParams = [Link]()
[Link] = {attackerChar,[Link]}
[Link] = [Link]
[Link] = true
local Raycast = workspace:Raycast(StartPos,Direction,RayParams)
if Raycast then
if EhumRP:FindFirstChild("HoldBP") then [Link]:Destroy()
end
if HumRP:FindFirstChild("HoldBP") then [Link]:Destroy() end
local function Lerp(i,A,B) return A:Lerp(B,i) end
[Link](function()
for i = 0,1,.03 do
local newpos =
Lerp(i,[Link],[Link] + [Link](0,3,0))
[Link]:MoveTo(newpos)
[Link]()
end
end)
delay(.15,function()
local NumOFParts = 14
createValue("BoolValue", attackerChar, "BigShake",
false, .1)
local SmokeWave =
scriptRef:WaitForChild("SmokeWave"):Clone()
[Link] = workspace
[Link] = [Link] + [Link](0,.7,0)
[Link]:AddItem(SmokeWave,2)
[Link]:Emit(50)
[Link]:Emit(25)
[Link]:Play()
end)
end
end

local HitFX = scriptRef:WaitForChild("HitFX"):WaitForChild("HitFX"):Clone()


[Link] = EhumRP
[Link]:AddItem(HitFX,1)
for _,fx in ipairs(HitFX:GetChildren()) do
if [Link] == "Crescents" then fx:Emit(5) end
if [Link] == "Gradient" then fx:Emit(1) end
if [Link] == "Shards" then fx:Emit(10) end
if [Link] == "Specs" then fx:Emit(10) end
end

Ehum:TakeDamage(getServerDamage(ComboNumber))
end

-- Important: [Link] must be the RemoteEvent named "Server"


[Link]:Connect(function(plr, Type, A1, A2, size, Last, Air,
ComboNumber, ClientTargets, BoxCFrame)
local Char = [Link]
if not Char then return end
local Hum = Char:FindFirstChild("Humanoid")
local HumRP = Char:FindFirstChild("HumanoidRootPart")
if not Hum or not HumRP then return end

local scriptRef = script -- assets resolved relative to this script

-- Attacker animation replication


if Type == "Animation" and A1 ~= nil then
Hum:LoadAnimation(A1):Play()
createValue("BoolValue", Char, "Swinging", false, .2)
return
end

if Type ~= "ClientHit" then


return
end
if attackerHardBlocked(Char) then
return
end
-- Validate client-provided targets and box
if typeof(ClientTargets) ~= "table" or #ClientTargets == 0 then
return
end

-- Small no-jump window


createValue("BoolValue", Char, "NoJump", false, 1)

local seen = {}
local applied = 0
local MAX_CLIENT_TARGETS = 5

for _, hrp in ipairs(ClientTargets) do


if applied >= MAX_CLIENT_TARGETS then break end
if typeof(hrp) == "Instance" and hrp:IsA("BasePart") and
hrp:IsDescendantOf(workspace) then
local targetChar = hrp:FindFirstAncestorOfClass("Model")
if targetChar and not seen[targetChar] then
seen[targetChar] = true
if serverValidateTarget(Char, targetChar, BoxCFrame, size)
then
applied += 1
local ok, err = pcall(processHit, plr, Char,
targetChar, Hum, HumRP, A2, Last, Air, ComboNumber, scriptRef)
if not ok then
warn("[RapierStyle] processHit error: ", err)
end
end
end
end
end
end)

You might also like