Загрузка данных
-- CatPlacementServer
-- Помести в ServerScriptService
local Players = game:GetService("Players")
local ServerStorage = game:GetService("ServerStorage")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local catTools = ServerStorage:WaitForChild("CatTools")
local MAX_CATS = 16
local PICKUP_HOLD_DURATION = 1
local PLACEMENT_DISTANCE = 35
-- Создаем RemoteEvent автоматически
local placeEvent = ReplicatedStorage:FindFirstChild("PlaceCatEvent")
if not placeEvent then
placeEvent = Instance.new("RemoteEvent")
placeEvent.Name = "PlaceCatEvent"
placeEvent.Parent = ReplicatedStorage
end
-- Папка с установленными котами
local placedFolder = workspace:FindFirstChild("PlacedCats")
if not placedFolder then
placedFolder = Instance.new("Folder")
placedFolder.Name = "PlacedCats"
placedFolder.Parent = workspace
end
-- Деньги игрока. Пока без сохранения.
local function setupPlayer(player)
local leaderstats = player:FindFirstChild("leaderstats")
if not leaderstats then
leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
end
local coins = leaderstats:FindFirstChild("Coins")
if not coins then
coins = Instance.new("NumberValue")
coins.Name = "Coins"
coins.Value = 0
coins.Parent = leaderstats
end
end
Players.PlayerAdded:Connect(setupPlayer)
for _, player in ipairs(Players:GetPlayers()) do
setupPlayer(player)
end
local function getOwnedBase(player)
local baseName = player:GetAttribute("BaseName")
if not baseName then
return nil
end
local base = workspace:FindFirstChild(baseName)
if not base or not base:IsA("Model") then
return nil
end
if base:GetAttribute("OwnerUserId") ~= player.UserId then
return nil
end
return base
end
local function countCats(player)
local count = 0
for _, cat in ipairs(placedFolder:GetChildren()) do
if cat:GetAttribute("OwnerUserId") == player.UserId then
count += 1
end
end
return count
end
local function getEquippedCat(player)
local character = player.Character
if not character then
return nil
end
for _, item in ipairs(character:GetChildren()) do
if item:IsA("Tool")
and catTools:FindFirstChild(item.Name)
and item:GetAttribute("Income") ~= nil
and item:GetAttribute("Rarity") ~= nil then
return item
end
end
return nil
end
-- Создаем физическую модель установленного кота
local function createPlacedCat(tool, player, floor, clickPosition)
local catModel = Instance.new("Model")
catModel.Name = tool.Name
-- Копируем содержимое Tool, но не его скрипты
for _, child in ipairs(tool:GetChildren()) do
if not child:IsA("Script")
and not child:IsA("LocalScript")
and not child:IsA("ModuleScript") then
local clone = child:Clone()
clone.Parent = catModel
end
end
local handle = catModel:FindFirstChild("Handle", true)
if not handle or not handle:IsA("BasePart") then
catModel:Destroy()
warn("У кота отсутствует Handle:", tool.Name)
return false
end
catModel.PrimaryPart = handle
-- Закрепляем части, чтобы кот не падал и не разлетался
for _, descendant in ipairs(catModel:GetDescendants()) do
if descendant:IsA("BasePart") then
descendant.Anchored = true
descendant.CanCollide = false
end
end
-- Позиция на верхней поверхности пола
local localPosition = floor.CFrame:PointToObjectSpace(clickPosition)
local surfacePosition = floor.CFrame:PointToWorldSpace(
Vector3.new(
localPosition.X,
floor.Size.Y / 2,
localPosition.Z
)
)
catModel:PivotTo(CFrame.new(surfacePosition + Vector3.new(0, 3, 0)))
-- Подгоняем высоту по реальному размеру модели
local boxCFrame, boxSize = catModel:GetBoundingBox()
local desiredCenter = surfacePosition
+ Vector3.new(0, boxSize.Y / 2 + 0.05, 0)
catModel:PivotTo(
catModel:GetPivot() + (desiredCenter - boxCFrame.Position)
)
catModel:SetAttribute("OwnerUserId", player.UserId)
catModel:SetAttribute("CatToolName", tool.Name)
catModel:SetAttribute("Income", tool:GetAttribute("Income"))
catModel:SetAttribute("Rarity", tool:GetAttribute("Rarity"))
-- Взаимодействие удержанием E
local prompt = Instance.new("ProximityPrompt")
prompt.Name = "PickupPrompt"
prompt.ActionText = "Забрать кота"
prompt.ObjectText = tool.Name
prompt.KeyboardKeyCode = Enum.KeyCode.E
prompt.HoldDuration = PICKUP_HOLD_DURATION
prompt.MaxActivationDistance = 10
prompt.RequiresLineOfSight = false
prompt.Parent = handle
prompt.Triggered:Connect(function(picker)
if not catModel.Parent then
return
end
-- Чужих котов забирать нельзя
if catModel:GetAttribute("OwnerUserId") ~= picker.UserId then
return
end
local backpack = picker:FindFirstChildOfClass("Backpack")
local template = catTools:FindFirstChild(
catModel:GetAttribute("CatToolName")
)
if not backpack or not template or not template:IsA("Tool") then
return
end
-- Сначала выдаем Tool, потом убираем модель
local returnedTool = template:Clone()
returnedTool.Parent = backpack
catModel:Destroy()
end)
catModel.Parent = placedFolder
return true
end
placeEvent.OnServerEvent:Connect(function(player, target, clickPosition)
if typeof(target) ~= "Instance"
or not target:IsA("BasePart")
or typeof(clickPosition) ~= "Vector3" then
return
end
local base = getOwnedBase(player)
if not base then
return
end
local floor = base:FindFirstChild("Floor")
if target ~= floor then
return
end
local character = player.Character
local root = character and character:FindFirstChild("HumanoidRootPart")
if not root or (root.Position - clickPosition).Magnitude > PLACEMENT_DISTANCE then
return
end
-- Проверяем, что позиция действительно находится на полу
local localPosition = floor.CFrame:PointToObjectSpace(clickPosition)
if math.abs(localPosition.X) > floor.Size.X / 2
or math.abs(localPosition.Z) > floor.Size.Z / 2
or math.abs(localPosition.Y - floor.Size.Y / 2) > 5 then
return
end
local tool = getEquippedCat(player)
if not tool then
return
end
if countCats(player) >= MAX_CATS then
warn(player.Name .. ": достигнут лимит в 16 котов")
return
end
-- Проверяем, что характеристики заданы корректно
local income = tool:GetAttribute("Income")
local rarity = tool:GetAttribute("Rarity")
if typeof(income) ~= "number"
or income < 0
or typeof(rarity) ~= "string" then
return
end
if createPlacedCat(tool, player, floor, clickPosition) then
tool:Destroy()
end
end)
-- Начисляем доход раз в секунду
task.spawn(function()
while true do
task.wait(1)
for _, cat in ipairs(placedFolder:GetChildren()) do
if cat:IsA("Model") then
local ownerId = cat:GetAttribute("OwnerUserId")
local income = cat:GetAttribute("Income")
local owner = ownerId and Players:GetPlayerByUserId(ownerId)
if owner and typeof(income) == "number" and income > 0 then
local leaderstats = owner:FindFirstChild("leaderstats")
local coins = leaderstats and leaderstats:FindFirstChild("Coins")
if coins then
coins.Value += income
end
end
end
end
end
end)
print("CatPlacementServer запущен")