103 lines
3.6 KiB
Plaintext
Raw Normal View History

2025-06-29 23:59:43 +08:00
--[[
Evercyan @ March 2023
DamageLib
DamageLib houses code relating to damage for weapons, and any additional sources of damage
you may add to your game. It is recommended to have all code for damage run through here for consistency.
If you're looking to adjust crit multiplier, gamepass rewards (ex. x3 damage), etc, you can do this under DamageLib:DamageMob().
]]
--> Services
local CollectionService = game:GetService("CollectionService")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local ServerStorage = game:GetService("ServerStorage")
--> Dependencies
local Mobs = require(ServerStorage.Modules.MobLib.MobList)
--> Variables
local DamageCd = {}
local Random = Random.new()
--------------------------------------------------------------------------------
local DamageLib = {}
function DamageLib:TagMobForDamage(Player: Player, Mob, Damage: number)
if Mob.isDead then return end
local PlayerTags = Mob.Instance:FindFirstChild("PlayerTags")
if not PlayerTags then
PlayerTags = Instance.new("Configuration")
PlayerTags.Name = "PlayerTags"
PlayerTags.Parent = Mob.Instance
end
local ExistingTag = PlayerTags:GetAttribute(Player.UserId)
if ExistingTag then
PlayerTags:SetAttribute(Player.UserId, ExistingTag + Damage)
else
PlayerTags:SetAttribute(Player.UserId, Damage)
end
end
function DamageLib:DamageMob(Player: Player, Mob): number?
if Mob.isDead then return end
local pData = ReplicatedStorage.PlayerData:FindFirstChild(Player.UserId)
local Level = pData and pData:FindFirstChild("Stats") and pData.Stats:FindFirstChild("Level")
if not Level or (Level.Value < Mob.Config.Level[2]) then
return
end
-- Make sure the equipped tool can be found, so we can safely grab the damage from it.
-- Never pass damage as a number through a remote, as the client can manipulate this data.
local Character = Player.Character
local Tool = Character and Character:FindFirstChildOfClass("Tool")
local ItemConfig = Tool and Tool:FindFirstChild("ItemConfig") and require(Tool.ItemConfig)
if not ItemConfig or not ItemConfig.Damage then return end
-- Damage Cooldown
if DamageCd[Player.UserId] then return end
DamageCd[Player.UserId] = true
task.delay(ItemConfig.Cooldown - 0.03, function() -- We subtract just a tad so inconsistencies with timing on the client (ie. time to raycast) is less likely to stop a hit from going through
DamageCd[Player.UserId] = nil
end)
-- Calculate damage
local Damage = typeof(ItemConfig.Damage) == "table" and Random:NextInteger(unpack(ItemConfig.Damage)) or ItemConfig.Damage
local isCrit = Random:NextInteger(1, 10) == 1
if isCrit then
Damage *= 2
end
self:TagMobForDamage(Player, Mob, Damage)
Mob.Enemy.Health = math.clamp(Mob.Enemy.Health - Damage, 0, Mob.Enemy.MaxHealth)
ReplicatedStorage.Remotes.PlayerDamagedMob:FireClient(Player, Mob.Instance, Damage)
return Damage
end
ReplicatedStorage.Remotes.DamageMob.OnServerInvoke = function(Player, MobInstance: Model)
if MobInstance and typeof(MobInstance) == "Instance" and CollectionService:HasTag(MobInstance, "Mob") then
local Mob = Mobs[MobInstance]
if Mob then
-- Follow
local Enemy = Mob.Instance:FindFirstChild("Enemy")
if Enemy and (not Enemy.WalkToPart or not Enemy.WalkToPart:IsDescendantOf(Player.Character)) then
local HumanoidRootPart = Mob.Instance:FindFirstChild("HumanoidRootPart")
if HumanoidRootPart then
HumanoidRootPart.Anchored = false
HumanoidRootPart:SetNetworkOwner(Player)
Enemy:MoveTo(Player.Character:GetPivot().Position)
end
end
return DamageLib:DamageMob(Player, Mob)
end
end
end
return DamageLib