- local players = game:GetService("Players")
- local replicatedStorage = game:GetService("ReplicatedStorage")
- local serverStorage = game:GetService("ServerStorage")
- local animationSystem = replicatedStorage:WaitForChild("Modules"):WaitForChild("AnimationSystem")
- local attacks = script:WaitForChild("Attacks")
- local questSystem = replicatedStorage:WaitForChild("Modules"):WaitForChild("QuestSystem")
- local playSoundEffect = replicatedStorage:WaitForChild("Modules"):WaitForChild("PlaySoundEffect")
- local serverSettings = replicatedStorage:WaitForChild("ServerSettings")
- local module = {}
- function GetRarityColor(itemName)
- if replicatedStorage.Items:FindFirstChild(itemName) and replicatedStorage.Items[itemName]:FindFirstChild("Price") then
- local ItemPrice = replicatedStorage.Items[itemName].Price.Value
- if ItemPrice < 1000 then
- return Color3.fromRGB(255,255,255)
- elseif ItemPrice < 10000 then
- return Color3.fromRGB(255, 255, 127)
- elseif ItemPrice < 30000 then
- return Color3.fromRGB(85, 255, 127)
- elseif ItemPrice < 70000 then
- return Color3.fromRGB(255, 85, 85)
- elseif ItemPrice < 100000 then
- return Color3.fromRGB(255, 0, 255)
- else
- return Color3.fromRGB(0, 255, 255)
- end
- else
- return Color3.fromRGB(255,255,255)
- end
- end
- function module.SpawnEnemy(enemyName, position, folder, area)
- if replicatedStorage.EnemyTypes[serverStorage.Enemies[enemyName].Stats.EnemyType.Value] then
- local waitToRespawn = Instance.new("Model", folder)
- local areaFromWait = Instance.new("StringValue")
- areaFromWait.Name = "AreaFrom"
- areaFromWait.Value = area.Name
- areaFromWait.Parent = waitToRespawn
- game:GetService("Debris"):AddItem(waitToRespawn, math.random(5,15))
- local enemy = serverStorage.Enemies[enemyName]:Clone()
- for _,stat in pairs(replicatedStorage.EnemyTypes[enemy.Stats.EnemyType.Value]:GetChildren()) do
- stat:Clone().Parent = enemy.Stats
- end
- enemy.EnemyHumanoid.Health = enemy.EnemyHumanoid.MaxHealth -- just in case someone forgot to set health
- local rankTag = Instance.new("NumberValue")
- rankTag.Value = enemy.Stats.Rank.Value
- rankTag.Name = "Rank"
- rankTag.Parent = enemy.Stats
- local areaFrom = Instance.new("StringValue")
- areaFrom.Name = "AreaFrom"
- areaFrom.Value = area.Name
- areaFrom.Parent = enemy
- local originalPosition = Instance.new("Vector3Value")
- originalPosition.Value = position
- originalPosition.Name = "OriginalPosition"
- originalPosition.Parent = enemy.Stats
- if not enemy.PrimaryPart then
- enemy.PrimaryPart = enemy:FindFirstChild("HumanoidRootPart") -- Everything with a humanoid must have a root part
- end
- enemy:SetPrimaryPartCFrame(CFrame.new(position) * CFrame.Angles(0, math.rad(math.random(-360, 360)), 0))
- enemy.Parent = folder
- local nametag = game:GetService("ServerScriptService").RPGSystem.Nametag:Clone()
- nametag.Parent = enemy.Head
- nametag.NameLabel.Text = enemy.Name --.. " [" .. enemy.Stats.Rank.Value .. "]"
- if enemy.Stats.Defense.Value > 0 and serverSettings.EnemiesShowDefense.Value == true then
- nametag.Defense.Visible = true
- nametag.Defense.Label.Text = enemy.Stats.Rank.Value
- end
- local newAnimationSystem = animationSystem:Clone()
- newAnimationSystem.Parent = enemy.EnemyHumanoid
- require(newAnimationSystem).PlayAnimation(enemy.Stats.IdleAnimation.Value.Name)
- enemy.EnemyHumanoid.Running:Connect(function(speed)
- if speed > 0.1 then
- require(newAnimationSystem).PlayAnimation(enemy.Stats.WalkAnimation.Value.Name)
- else
- require(newAnimationSystem).StopAnimation(enemy.Stats.WalkAnimation.Value.Name)
- end
- end)
- enemy.EnemyHumanoid.HealthChanged:Connect(function()
- local function Loot()
- local alreadyGotLoot = {}
- if enemy:FindFirstChild("LootTags") then
- for _,tag in pairs(enemy.LootTags:GetChildren()) do
- if not table.find(alreadyGotLoot, tag.Name) then
- table.insert(alreadyGotLoot, tag.Name)
- local player = players:FindFirstChild(tag.Name)
- if player then
- if enemy.Stats:FindFirstChild("Drops") then -- Loot drops
- for _,itemDrop in pairs(enemy.Stats.Drops:GetChildren()) do
- local DropChance = math.random(1,1000)
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- DropChance /= 2
- end
- if DropChance <= itemDrop.DropChance.Value then
- if not itemDrop:FindFirstChild("DropType") or itemDrop.DropType.Value == "Item" then
- if player.Inventory:FindFirstChild(itemDrop.Name) then
- player.Inventory[itemDrop.Name].Value += 1
- if replicatedStorage.ServerSettings.LootNotifications.Value == true then
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. "! (2x Bonus)", Color3.fromRGB(255, 255, 0))
- else
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. "!", Color3.fromRGB(255, 255, 0))
- end
- end
- else
- if #player.Inventory:GetChildren() < player.Stats.BagSlot.Value then
- if not player.StarterGear:FindFirstChild(itemDrop.Name) then
- replicatedStorage.Items[itemDrop.Name]:Clone().Parent = player.StarterGear
- end
- if not player.Backpack:FindFirstChild(itemDrop.Name) then
- replicatedStorage.Items[itemDrop.Name]:Clone().Parent = player.Backpack
- end
- if replicatedStorage.ServerSettings.LootNotifications.Value == true then
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. "! (2x Bonus)", Color3.fromRGB(255, 255, 0))
- else
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. "!", Color3.fromRGB(255, 255, 0))
- end
- end
- if not player.Inventory:FindFirstChild(itemDrop.Name) then
- local itemSaved = Instance.new("IntValue")
- itemSaved.Name = itemDrop.Name
- itemSaved.Parent = player.Inventory
- itemSaved.Value = 1
- end
- else
- if replicatedStorage.ServerSettings.LootNotifications.Value == true then
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. " but your inventory is full! (2x Bonus)", Color3.fromRGB(255, 0, 4))
- else
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "Got " .. itemDrop.Name .. " but your inventory is full!", Color3.fromRGB(255, 0, 4))
- end
- end
- local itemDropped = replicatedStorage.ItemsFolders:FindFirstChild(itemDrop.Name, true):Clone()
- itemDropped.CanCollide = false
- local proximityPront = script.Part.Attachment:Clone()
- proximityPront.Parent = itemDropped
- proximityPront.ProximityPrompt.ObjectText = itemDropped.Name
- proximityPront.ProximityPrompt.Enabled = true
- itemDropped.CFrame = enemy.HumanoidRootPart.CFrame * CFrame.new(math.random(-10,10), 1,math.random(-10,10))
- local plasma = script.Plasma:Clone()
- local color = GetRarityColor(itemDropped.Name)
- plasma.Color = ColorSequence.new(color,color)
- plasma.Parent = itemDropped
- itemDropped.Parent = workspace.Loots
- game:GetService("Debris"):AddItem(itemDropped, 30)
- end
- end
- elseif itemDrop.DropType.Value == "Stat" then
- player.Stats[itemDrop.Name].Value = player.Stats[itemDrop.Name].Value + itemDrop.Amount.Value
- if replicatedStorage.ServerSettings.LootNotifications.Value == true then
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "+" .. itemDrop.Amount.Value .. " " .. itemDrop.Name .. " (2x Bonus)", Color3.fromRGB(0, 255, 255))
- else
- replicatedStorage.ClientRemotes.Notification:FireClient(player, "+" .. itemDrop.Amount.Value .. " " .. itemDrop.Name, Color3.fromRGB(0, 255, 255))
- end
- end
- else
- warn('Item drop type named"' .. itemDrop.DropType.Value .. '" does not match any existing drop types; enemy: ' .. enemy.Name)
- end
- end
- end
- end
- -- XP and Gold drops
- player.Stats.XP.Value = player.Stats.XP.Value + enemy.Stats.XP.Value
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2XP") and player.Boosts.X2LOOT.Value > 0 then
- player.Stats.XP.Value = player.Stats.XP.Value + enemy.Stats.XP.Value
- end
- player.Stats.Gold.Value = player.Stats.Gold.Value + enemy.Stats.Gold.Value
- if player:FindFirstChild("Boosts") and player.Boosts:FindFirstChild("X2LOOT") and player.Boosts.X2LOOT.Value > 0 then
- player.Stats.Gold.Value = player.Stats.Gold.Value + enemy.Stats.Gold.Value
- end
- -- Quest stuff
- require(questSystem).PlayerDefeatedEnemy(player, enemy.Name)
- -- codigo da moeda
- --for i = 1,math.floor(enemy.Stats.Gold.Value/2) do wait()
- -- local coins = game.ReplicatedStorage.Particles.Gold:Clone()
- -- coins.Parent = workspace
- -- game.Debris:AddItem(coins,20)
- -- coins.Anchored = true
- -- coins.CFrame = enemy:FindFirstChild('HumanoidRootPart').CFrame * CFrame.new(math.random(-6,6),math.random(-6,6),math.random(-6,6))
- -- coins.r.Position = coins.CFrame.Position
- -- coroutine.resume(coroutine.create(function()
- -- coins.Anchored = false
- -- wait(.25)
- -- coins.r.Position = player.Character:FindFirstChild('HumanoidRootPart').CFrame.Position
- -- for i = 1,10 do wait()
- -- coins.Transparency += 0.1
- -- coins.r.Position = player.Character:FindFirstChild('HumanoidRootPart').CFrame.Position
- -- end
- -- coins:Destroy()
- -- end))
- --end
- end
- end
- if players:FindFirstChild(tag.Name) and not players[tag.Name].Wiki.Monsters:FindFirstChild(enemy.Name) then
- local monster = Instance.new("IntValue", players:FindFirstChild(tag.Name).Wiki.Monsters)
- monster.Name = enemy.Name
- monster.Value = 1
- else
- players[tag.Name].Wiki.Monsters:FindFirstChild(enemy.Name).Value += 1
- end
- if players[tag.Name].Wiki.Monsters:FindFirstChild(enemy.Name).Value == serverStorage.Enemies[enemy.Name].Stats.Wiki.Value then
- replicatedStorage.ClientRemotes.Notification:FireClient(players[tag.Name], "You unlocked " .. enemy.Name .. " in Wiki!", Color3.fromRGB(0, 255, 0))
- end
- end
- end
- end
- if enemy.EnemyHumanoid.Health >= enemy.EnemyHumanoid.MaxHealth then
- nametag.Bar.Visible = false
- else
- nametag.Bar.Fill.Position = UDim2.new(1-(enemy.EnemyHumanoid.Health/enemy.EnemyHumanoid.MaxHealth), 0, 0, 0)
- nametag.Bar.Visible = true
- end
- if enemy.EnemyHumanoid.Health == 0 and nametag.Parent then
- Loot()
- nametag:Destroy()
- replicatedStorage.ClientRemotes.EnemyDied:FireAllClients(enemy)
- game:GetService("Debris"):AddItem(enemy, 2)
- end
- end)
- else
- warn("Tried to spawn " .. enemyName .. " but couldn't find a matching folder in EnemyTypes")
- end
- end
- function module.CalculateEnemyDamage(enemy, min, max)
- return math.clamp(math.random(min, max) - enemy.Stats.Defense.Value, 1, math.huge)
- end
- function module.CalculatePlayerDamage(player, min, max)
- local defense = 0
- if player and player:FindFirstChild("Stats") and player.Stats:FindFirstChild("CurrentArmor") and replicatedStorage.Items:FindFirstChild(player.Stats.CurrentArmor.Value) then
- defense = replicatedStorage.Items[player.Stats.CurrentArmor.Value].Defense.Value + (player.Attributes.Vitality.Value*2)
- end
- local minimo
- if min < 10 then
- minimo = 1
- else
- minimo = player.Attributes.Vitality.Value/1000*min*2
- end
- return math.clamp(math.random(min, max) - defense, math.floor(minimo), math.huge)
- end
- function module.DamageEnemy(player, item, enemyHumanoid, damageMultiplier)
- if enemyHumanoid.Health > 0 and not enemyHumanoid:FindFirstChild(player.Name) then
- local function TagEnemy(seconds)
- if not enemyHumanoid.Parent:FindFirstChild("LootTags") then
- local lootTags = Instance.new("Folder")
- lootTags.Name = "LootTags"
- lootTags.Parent = enemyHumanoid.Parent
- end
- local tag = Instance.new("Model")
- tag.Name = player.Name
- tag.Parent = enemyHumanoid
- game:GetService("Debris"):AddItem(tag, seconds)
- local lootTag = Instance.new("Model")
- lootTag.Name = player.Name
- if not enemyHumanoid.Parent.LootTags:FindFirstChild(player.Name) then
- lootTag.Parent = enemyHumanoid.Parent.LootTags
- end
- game:GetService("Debris"):AddItem(lootTag, 300)
- end
- local function LerpNumber(minimum, maximum, percentage)
- return (percentage * (maximum - minimum)) + minimum
- end
- TagEnemy(item.Cooldown.Value)
- if not damageMultiplier then
- damageMultiplier = 1
- end
- local plusDamage = 0
- if item.ItemType.Value == "Staff" then plusDamage = player.Attributes.Mythicality.Value end
- if item.ItemType.Value == "Sword" then plusDamage = player.Attributes.Power.Value end
- local minimum = item.MinimumDamage.Value
- local maximum = item.MaximumDamage.Value + plusDamage
- minimum = LerpNumber(minimum, maximum, player.Attributes.Power.Value / serverSettings.PowerCap.Value) -- The minumum increases with more power; max power is only maximum damage
- local damage = math.floor(module.CalculateEnemyDamage(enemyHumanoid.Parent, minimum, maximum) * damageMultiplier)
- enemyHumanoid.Health = enemyHumanoid.Health - damage
- replicatedStorage.ClientRemotes.DamageDone:FireClient(player, enemyHumanoid.Parent, damage)
- end
- end
- function module.FindClosestPlayer(enemy, useChaseRange) -- Returns closest player in the AttackRange or nil if none are found
- if enemy.Name == "Model" then return end
- local range = enemy.Stats.AttackRange.Value
- if useChaseRange then
- range = enemy.Stats.ChaseRange.Value
- end
- local closest = nil
- for _,player in pairs(players:GetChildren()) do
- if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid") and enemy:FindFirstChild("HumanoidRootPart") and player.Character.Humanoid.Health > 0 then
- if not closest or (player.Character.HumanoidRootPart.Position - enemy.HumanoidRootPart.Position).magnitude < (closest.Character.HumanoidRootPart.Position - enemy.HumanoidRootPart.Position).magnitude then
- if (player.Character.HumanoidRootPart.Position - enemy.HumanoidRootPart.Position).magnitude < range then
- closest = player
- end
- end
- end
- end
- return closest
- end
- function module.FindPlayersInRadius(position, radius) -- Returns a table of players in the AttackRange or nil if none are found
- local inRange = nil
- for _,player in pairs(players:GetChildren()) do
- if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid") and player.Character.Humanoid.Health > 0 then
- if (player.Character.HumanoidRootPart.Position - position).magnitude < radius then
- if not inRange then
- inRange = {}
- end
- table.insert(inRange, player)
- end
- end
- end
- return inRange
- end
- function module.GetAllPlayerCharacters() -- Returns a table of all player characters, useful for whitelists
- local characters = {}
- for _,player in pairs(players:GetChildren()) do
- if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
- table.insert(characters, player.Character)
- end
- end
- return characters
- end
- function module.Attack(enemy)
- if enemy:FindFirstChild("EnemyHumanoid") and enemy.EnemyHumanoid.Health > 0 and enemy:FindFirstChild("HumanoidRootPart") and enemy:FindFirstChild("Stats") and not enemy:FindFirstChild("AttackCooldown") then
- local enemyType = enemy.Stats.EnemyType.Value
- if require(attacks)[enemyType] then
- local tag = Instance.new("Model") -- Does not let the enemy attack until the set AttackCooldown is over
- tag.Name = "AttackCooldown"
- tag.Parent = enemy
- require(attacks)[enemyType](enemy)
- wait(replicatedStorage.EnemyTypes[enemyType].AttackCooldown.Value)
- tag:Destroy()
- else
- warn(enemy.Name .. [[ tried to attack but the Attacks module didn't have an attack that matches the enemy type "]] .. enemyType .. [["]])
- end
- end
- end
- function module.Follow(enemy, targetPart)
- local chaseRange = enemy.Stats.ChaseRange.Value -- How many studs away a player must be before the enemy decides to start chasing
- local closestRange = enemy.Stats.ClosestRange.Value -- The minumum distance the enemy can be from the player
- local attackRange = enemy.Stats.AttackRange.Value -- How many studs away the enemy will try to attack a player
- if (targetPart.Position - enemy.HumanoidRootPart.Position).magnitude <= chaseRange then
- local pointToSeek = targetPart.Position+(CFrame.new(targetPart.Position, enemy.HumanoidRootPart.Position).LookVector*closestRange)
- enemy.EnemyHumanoid:MoveTo(pointToSeek)
- if (targetPart.Position - enemy.HumanoidRootPart.Position).magnitude <= attackRange then
- module.Attack(enemy)
- end
- elseif (targetPart.Position - enemy.Stats.OriginalPosition.Value).magnitude > 10 then
- enemy.EnemyHumanoid:MoveTo(enemy.Stats.OriginalPosition.Value)
- end
- end
- return module