How do I make a weapon that have a Critical Hit Chance?

Please help me, I’m also using a clientcast module:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")

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

local Modules = ReplicatedStorage:WaitForChild("Modules")
local ClientCast = require(Modules:WaitForChild("ClientCast"))

local Tool = script.Parent
local Handle = Tool:WaitForChild("Handle")
local Trail = Handle:WaitForChild("Trail")

local Character = nil
local Player = nil
local Torso = nil

local Humanoid = nil
local Animator = nil

local IdleTrack = nil
local AttackAnimations = {}
local Debounce = {}

local ToolEquipped = false
local SlashCaster = nil

local Cooldown = 1
local Damage = 20

for Count = -0.8, 2.4, .1 do
	local DmgPoint = Instance.new("Attachment", Handle)
	DmgPoint.Name = "DmgPoint"
	DmgPoint.Position = Vector3.new(0, 0, Count)
end

local function CheckIfAlive()
	return (((Player and Player.Parent and Character and Character.Parent and Humanoid and Humanoid.Parent and Humanoid.Health > 0 and Torso and Torso.Parent) and true) or false)
end

local function IsTeamMate(Player1, Player2)
	return (Player1 and Player2 and not Player1.Neutral and not Player2.Neutral and Player1.TeamColor == Player2.TeamColor)
end

local function Yield(Seconds) -- Custom made function alternative to wait()
	local StartTime = tick()
	repeat RunService.Heartbeat:Wait() until tick() - StartTime >= Seconds
end

local function TagHumanoid(humanoid, player)
	local Creator_Tag = Instance.new("ObjectValue")
	Creator_Tag.Name = "creator"
	Creator_Tag.Value = player
	Debris:AddItem(Creator_Tag, 2)
	Creator_Tag.Parent = humanoid
end

local function UntagHumanoid(humanoid)
	for i, v in pairs(humanoid:GetChildren()) do
		if v:IsA("ObjectValue") and v.Name == "creator" then
			v:Destroy()
		end
	end
end

local function Equipped()
	Character = Tool.Parent
	Player = Players:GetPlayerFromCharacter(Character)
	Humanoid = Character:FindFirstChildOfClass("Humanoid")
	Torso = Character:FindFirstChild("Torso") or Character:FindFirstChild("UpperTorso")
	Animator = Humanoid:FindFirstChildOfClass("Animator")
	
	if not CheckIfAlive() then
		return
	end
	if Animator then
		IdleTrack = Animator:LoadAnimation(Tool.Idle)
		AttackAnimations[1] = Animator:LoadAnimation(Tool.Slash)
		AttackAnimations[2] = Animator:LoadAnimation(Tool.Overhead)
	end
	if IdleTrack then
		IdleTrack:Play()
	end
	
	SlashCaster = ClientCast.new(Handle, RaycastParams.new())
	SlashCaster.HumanoidCollided:Connect(function(RaycastResult, humanoid)
		if not CheckIfAlive() or not ToolEquipped then
			return
		end
		local RightArm = Character:FindFirstChild("Right Arm") or Character:FindFirstChild("RightHand")
		if not RightArm then
			return
		end
		local RightGrip = RightArm:FindFirstChild("RightGrip") or RightArm:FindFirstChild("Handle")
		if not RightGrip or (RightGrip.Part0 ~= Handle and RightGrip.Part1 ~= Handle) then
			return
		end
		local character = humanoid.Parent
		if character == Character then
			return
		end
		if not humanoid or humanoid.Health == 0 then
			return
		end
		local player = Players:GetPlayerFromCharacter(character)
		if player and (player == Player or IsTeamMate(Player, player)) then
			return
		end
		if Debounce[humanoid] then
			return
		end
		Debounce[humanoid] = true
		UntagHumanoid(humanoid)
		TagHumanoid(humanoid, Player)
		humanoid:TakeDamage(Damage)
		Handle.Hit:Play()
		Yield(Cooldown / 2)
		Debounce[humanoid] = false
	end)
	
	SlashCaster:SetOwner(Player)
	ToolEquipped = true
	Handle.Equip:Play()
end

local function Activated()
	if not Tool.Enabled or not ToolEquipped or not CheckIfAlive() then
		return
	end
	
	if AttackAnimations then
		AttackAnimations[math.random(1, #AttackAnimations)]:Play()
	end
	
	Tool.Enabled = false
	SlashCaster:Start()
	
	delay(0.15, function()
		Handle.Slash:Play()
		Trail.Enabled = true
	end)
	
	Yield(Cooldown)
	SlashCaster:Stop()
	Trail.Enabled = false
	Tool.Enabled = true
end

local function Unequipped()
	if IdleTrack then
		IdleTrack:Stop()
	end
	if AttackAnimations then
		AttackAnimations[1]:Stop()
		AttackAnimations[2]:Stop()
	end
	ToolEquipped = false
	SlashCaster:Stop()
end

Tool.Equipped:Connect(Equipped)
Tool.Activated:Connect(Activated)
Tool.Unequipped:Connect(Unequipped)

try using

local CHitChance = math.random(1,other number)
      if CHitChance == 1 then
              -- insert critical hit code here
      else
             -- typical hit code here
end

i dont know if this is what you were thinking but i use it for RNG events

thats not how it look like that

I think getting a percentage is better, like, if u get a random number and the random number is below the given percentage, the action will run, like →

local CHitChance = math.random(1, 100)
      if CHitChance >= 10 then
              -- insert critical hit code here
      else
             -- typical hit code here
end

This way u get a better control of the chance of critical damage!!

1 Like

Alright let me try it out hope this will work

I’ve invented myself a Percentage Randomizing function which based on Weighted Percentage and Number Initializing. You will have to create a table like this

function PercentageRandomizing(LootTable)
	if LootTable then
		local Total_Percentage = 0
		for _, total_percent in pairs(LootTable) do
			Total_Percentage += total_percent
		end
		
		if Total_Percentage == 100 then
			local WeightedLootTable = {}

			-- Get Multiplys

			local WeightedMultiplys = 1
			for _, percentage in pairs(LootTable) do
				if percentage < 1 then
					local TotalMultiplied = 0

					for i = 0, 10 do
						if percentage < 1 then
							percentage *= 10
							TotalMultiplied += 1
						end
					end
					if TotalMultiplied > WeightedMultiplys then
						WeightedMultiplys = TotalMultiplied
					end
				end
			end

			-- Multiplying WeightedTable
			
			for item, percentage in pairs(LootTable) do
				local WeightedPercentage = percentage
				for i = 0, WeightedMultiplys do
					WeightedPercentage *= 10
				end
				
				WeightedLootTable[item] = WeightedPercentage
			end
			
			-- Doing a Double Check
			
			local Smallest_Percent = math.huge
			for _, percentage in pairs(WeightedLootTable) do
				if percentage < Smallest_Percent then
					Smallest_Percent = percentage
				end
			end
			
			if Smallest_Percent > 10 then
				for item, percentage in pairs(WeightedLootTable) do
					WeightedLootTable[item] = percentage / 10
				end
			end
			
			-- Randomizing
			
			local sum = 0

			for k, v in pairs(WeightedLootTable) do
				sum = sum + v
			end

			local r = math.random(sum)

			for k, v in pairs(WeightedLootTable) do
				r = r - v

				if r <= 0 then
					return k
				end
			end
		end
	else
		warn("Randomizing requires a loot table!")
	end
end

local CriticalChance = {
  ["Normal"] = 90, -- 90%
  ["Critical"] = 9.999, -- 9.999%
  ["Insta-Kill"] = 0.001 -- 0.001%
}

local RandomResult = PercentageRandomizing(CriticalChance)
print(RandomResult)

You will have to add up for it to be 100% and this also works with decimal.

2 Likes

This is lot more easy to use, it based on Weighted Percentage which are more accurate and works with decimal.

That looks great, but i don’t think it’s worth it just to critical chance, i think this would work way better when dealing with item drops though, inside of a ModuleScript of course.

Yes but its made out for Percentage Randomizing, alot more easy to use.

1 Like

Way more accurate, i wouldn’t say easier, but if it works, then perfect, it all depends on how you want something to be, i said it wasn’t needed, cuz he doesn’t need that accurancy that your function gives, but this depends on him aswell, just saying that i wouldn’t do something that sophisticated just for critical chance. Very well coded btw good job!!

1 Like