--[[ 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