Server code:
local RS = game:GetService("ReplicatedStorage")
local SS = game:GetService("ServerStorage")
local ServerScriptService = game:GetService("ServerScriptService")
local Items = SS:WaitForChild("AllItems")
local InventoryRemotes = RS:WaitForChild("InventoryRemotes")
local StoreItemEvent = InventoryRemotes:WaitForChild("StoreItem")
local TakeItemEvent = InventoryRemotes:WaitForChild("TakeItem")
local UnstoreItemEvent = InventoryRemotes:WaitForChild("UnstoreItem")
local EatItemEvent = InventoryRemotes:WaitForChild("EatItemEvent")
local CraftingRS = RS:WaitForChild("CraftingReplicatedStorage")
local ItemValues =require(CraftingRS:WaitForChild("ItemValues"))
local UtilityModule = require(SS:WaitForChild("UtilityModule"))
local ToolModels = SS:WaitForChild("ToolModels")
StoreItemEvent.OnServerEvent:Connect(function(player, item)
local PlayerItemsFolder = player:FindFirstChild("StoredItemsFolder")
local NumberOfCurrentItemsStored = player:FindFirstChild("ItemsStoredValue")
local MaxStorage = player:FindFirstChild("MaxStorageCap")
if not item or not item:HasTag("Storable") then return end
if PlayerItemsFolder and NumberOfCurrentItemsStored.Value < MaxStorage.Value then
NumberOfCurrentItemsStored.Value += 1
item.Parent = PlayerItemsFolder
item:SetAttribute("StoreOrder", NumberOfCurrentItemsStored.Value)
end
if item:IsA("Model") and item.PrimaryPart then
for _, part in item:GetDescendants() do
if part:IsA("BasePart") then
part.CollisionGroup = "ChestSpawnCollisionGroup"
part.Anchored = false
end
end
elseif item:IsA("BasePart") then
item.CollisionGroup = "ChestSpawnCollisionGroup"
item.Anchored = false
end
end)
UnstoreItemEvent.OnServerEvent:Connect(function(player)
local PlayerItemsFolder = player:FindFirstChild("StoredItemsFolder")
local NumberOfCurrentItemsStored = player:FindFirstChild("ItemsStoredValue")
if PlayerItemsFolder and NumberOfCurrentItemsStored.Value > 0 then
-- Find the item with the highest StoreOrder (last stored)
local maxOrder = -1
local lastItem = nil
for _, item in pairs(PlayerItemsFolder:GetChildren()) do
local order = item:GetAttribute("StoreOrder") or -1
if order > maxOrder then
maxOrder = order
lastItem = item
end
end
if lastItem then
-- Drop the item in front of the player
local character = player.Character
if character then
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
local dropPosition = humanoidRootPart.Position + humanoidRootPart.CFrame.LookVector * 2 -- 2 studs in front
if lastItem:IsA("Model") and lastItem.PrimaryPart then
lastItem:PivotTo(CFrame.new(dropPosition))
elseif lastItem:IsA("BasePart") then
lastItem.Position = dropPosition
end
lastItem.Parent = workspace
lastItem:SetAttribute("DroppedUserId", player.UserId)
task.delay(1, function()
lastItem:SetAttribute("DroppedUserId", nil)
end)
NumberOfCurrentItemsStored.Value -= 1
end
end
else
NumberOfCurrentItemsStored.Value -= 1
end
end
end)
-- Create RemoteEvents
local dropEvent = InventoryRemotes:WaitForChild("DropToolEvent")
-- Drop tools from backpack
local TrapToolModel = ToolModels:WaitForChild("Trap")
dropEvent.OnServerEvent:Connect(function(player, tool)
if tool:IsA("Tool") and tool:HasTag("Droppable") then
local ToolModel = ToolModels:FindFirstChild(tool.Name)
if ToolModel then
for _, part in ToolModel:GetChildren() do
if part:IsA("BasePart") then
part.Anchored = false
part.CanCollide = true
end
end
ToolModel = ToolModel:Clone()
local character = player.Character
if character then
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
ToolModel:SetAttribute("DroppedUserId", player.UserId)
task.delay(1, function()
ToolModel:SetAttribute("DroppedUserId", nil)
end)
ToolModel:PivotTo(CFrame.new(humanoidRootPart.Position + humanoidRootPart.CFrame.LookVector * 2))
ToolModel.Parent = workspace
end
end
else
ToolModel = TrapToolModel:Clone()
ToolModel.Name = tool.Name
for _, part in ToolModel:GetChildren() do
if part:IsA("BasePart") then
part.Anchored = false
part.CanCollide = true
end
end
local character = player.Character
if character then
local humanoidRootPart = character:FindFirstChild("HumanoidRootPart")
if humanoidRootPart then
ToolModel:SetAttribute("DroppedUserId", player.UserId)
task.delay(1, function()
ToolModel:SetAttribute("DroppedUserId", nil)
end)
ToolModel:PivotTo(CFrame.new(humanoidRootPart.Position + humanoidRootPart.CFrame.LookVector * 2))
ToolModel.Parent = workspace
end
end
end
tool:Destroy()
end
end)
local function GiveItem(item,tagToDestroy, player)
for _, tool in player.Backpack:GetChildren() do
if tool:HasTag(tagToDestroy) then
tool:Destroy()
end
end
for _, tool in player.Character:GetChildren() do
if tool:HasTag(tagToDestroy) then
tool:Destroy()
end
end
local NewItem = Items[item.Name]:Clone()
NewItem.Parent = player.Backpack
item:Destroy()
end
local function PlayerHasTaggedTool(player, tagName)
if not player or not player.Character then return false end
-- Check Backpack
for _, tool in ipairs(player:FindFirstChild("Backpack"):GetChildren()) do
if tool:IsA("Tool") and tool:HasTag(tagName) then
return true
end
end
-- Check Character (equipped tool)
if player.Character then
for _, tool in ipairs(player.Character:GetChildren()) do
if tool:IsA("Tool") and tool:HasTag(tagName) then
return true
end
end
end
return false
end
local BadgModule = require(RS:WaitForChild("BadgeModule"))
local AddCharmProgressBindabale = ServerScriptService:WaitForChild("AddCharmProgress")
TakeItemEvent.OnServerEvent:Connect(function(player, item)
if item and item:HasTag("Takeable") then
if item:HasTag("TakenByPlayer") then return end
if item:HasTag("CHARM") then
local CharmsAmountAlreadyCollected = player:GetAttribute("CharmsCollected")
player:SetAttribute("CharmsCollected", (CharmsAmountAlreadyCollected or 0) + 1)
player.InGameCharmsAmount.Value += 1
if CharmsAmountAlreadyCollected then
if CharmsAmountAlreadyCollected + 1 == 5 then
BadgModule.awardBadge(player, 834542126887886)
elseif CharmsAmountAlreadyCollected +1 == 20 then
BadgModule.awardBadge(player, 1278058595215487)
end
end
item:AddTag("TakenByPlayer")
local Name = item.Name
item:Destroy()
AddCharmProgressBindabale:Fire(player, Name, 1)
return
end
item:AddTag("TakenByPlayer")
if item.Name == "Revolver Ammo" then
local RevolverAmmo = player:FindFirstChild("RevolverAmmo")
RevolverAmmo.Value += 6
item:Destroy()
return
elseif item.Name == "Rifle Ammo" then
local RifleAmmo = player:FindFirstChild("RifleAmmo")
RifleAmmo.Value += 6
item:Destroy()
return
elseif item.Name == "Ice Ammo" then
local IceAmmo = player:FindFirstChild("IceGunAmmo")
IceAmmo.Value += 6
item:Destroy()
return
elseif item:HasTag("Armor") then
local ArmorLevel = player.ArmorLevel
if item.Name == "Iron Chestplate" then
if ArmorLevel.Value < 1 then
ArmorLevel.Value = 1
UtilityModule.GiveArmor(item.Name,player)
item:Destroy()
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Gold Chestplate" then
if ArmorLevel.Value < 2 then
ArmorLevel.Value = 2
UtilityModule.GiveArmor(item.Name,player)
item:Destroy()
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Diamond Chestplate" then
if ArmorLevel.Value < 3 then
ArmorLevel.Value = 3
UtilityModule.GiveArmor(item.Name,player)
item:Destroy()
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Dragon Armor" then
if ArmorLevel.Value < 4 then
ArmorLevel.Value = 4
UtilityModule.GiveArmor("Knight Armor",player)
item:Destroy()
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
end
return
elseif item:HasTag("SACK") then
local SackLevel = player.SackLevel
local CurrentMaxStorageCap = player.MaxStorageCap
if item.Name == "Good Sack" then
if SackLevel.Value < 2 or not PlayerHasTaggedTool(player, "SACK") then
SackLevel.Value = 2
CurrentMaxStorageCap.Value = item:GetAttribute("StorageCap")
GiveItem(item, "SACK", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Huge Sack" then
if SackLevel.Value < 3 or not PlayerHasTaggedTool(player, "SACK") then
CurrentMaxStorageCap.Value = item:GetAttribute("StorageCap")
SackLevel.Value = 3
GiveItem(item, "SACK", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
end
return
elseif item:HasTag("MeleeWeapon") then
local MeleeWeaponLevel = player.MeleeWeaponLevel
if item.Name == "Wooden Bat" then
if MeleeWeaponLevel.Value < 1 then
MeleeWeaponLevel.Value = 1
GiveItem(item, "MeleeWeapon", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Metal Bat" then
if MeleeWeaponLevel.Value < 2 then
MeleeWeaponLevel.Value = 2
GiveItem(item, "MeleeWeapon", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Sword" then
if MeleeWeaponLevel.Value <3 then
MeleeWeaponLevel.Value = 3
GiveItem(item, "MeleeWeapon", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
end
return
elseif item:HasTag("AXE") then
local AxeLevel = player.AxeLevel
if item.Name == "Good Axe" then
if AxeLevel.Value < 2 or not PlayerHasTaggedTool(player, "AXE") then
GiveItem(item, "AXE", player)
AxeLevel.Value = 2
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
elseif item.Name == "Military Axe" then
if AxeLevel.Value < 3 or not PlayerHasTaggedTool(player, "AXE") then
AxeLevel.Value = 3
GiveItem(item, "AXE", player)
else
if item:HasTag("TakenByPlayer") then
item:RemoveTag("TakenByPlayer")
end
end
end
return
elseif item:HasTag("CashItem") then
local CashValue = ItemValues[item.Name].Money
local PlayerCashAmount = player.Money
PlayerCashAmount.Value += CashValue
item:Destroy()
return
elseif item:HasTag("Diamond") then
item:Destroy()
local PlayerDiamondsAmount = player.DiamondsAmount
PlayerDiamondsAmount.Value += 1
return
end
local ItemToGive = Items[item.Name]:Clone()
item:Destroy()
local Backpack = player:FindFirstChild("Backpack")
if Backpack then
ItemToGive.Parent = player:FindFirstChild("Backpack")
end
end
end)
local EatSound = script:WaitForChild("eat")
EatItemEvent.OnServerEvent:Connect(function(player, item)
if not item or not item:HasTag("Eatable") then return end
task.defer(function()
if player.Character then
local Torso = player.Character:FindFirstChild("Torso")
if Torso then
local ClonedSound = EatSound:Clone()
ClonedSound.Parent = Torso
ClonedSound:Play()
task.wait(0.5)
ClonedSound:Destroy()
end
end
end)
local itemInfo = ItemValues[item.Name]
if itemInfo then
local ItemSanityRestoreAmount = itemInfo.Sanity
local Abilityfunciton = itemInfo.Ability
if Abilityfunciton then
task.defer(Abilityfunciton, player)
end
UtilityModule.AddOrSubtractSanity(player,ItemSanityRestoreAmount)
end
if item then
item:Destroy()
end
end)
local UsedToolEvent = RS:WaitForChild("UsedTool")
local HealVFX = SS:WaitForChild("VFX"):WaitForChild("HealEffect")
UsedToolEvent.OnServerEvent:Connect(function(Player, tool)
if not tool:HasTag("USABLE") then return end
local HealValue = tool:FindFirstChild("HealAmount")
local char
if HealValue then
char = Player.Character
if char then
local Humanoid = char:FindFirstChildOfClass("Humanoid")
if Humanoid then
Humanoid.Health += HealValue.Value
end
end
end
local SanityHealAmount = tool:FindFirstChild("SanityHealAmount")
if SanityHealAmount then
UtilityModule.AddOrSubtractSanity(Player, SanityHealAmount.Value)
end
local Uses = tool:FindFirstChild("Uses")
if Uses and Uses.Value <=1 then
tool:Destroy()
else
if Uses then
Uses.Value -= 1
else
tool:Destroy()
end
end
if char then
local hroot = char:FindFirstChild("HumanoidRootPart")
if hroot then
local healClone = HealVFX:Clone()
local HealWeld = Instance.new("WeldConstraint")
healClone.CFrame = hroot.CFrame *CFrame.new(0,-3,0)
HealWeld.Parent = healClone
HealWeld.Part0 = hroot
HealWeld.Part1 = healClone
healClone.Parent = hroot
healClone.Used:Play()
game.Debris:AddItem(healClone,2.8)
end
end
end)
local FurnitureStoreStuff = workspace:WaitForChild("Furniture")
for _, furniture in FurnitureStoreStuff:GetChildren() do
local Prompt = Instance.new("ProximityPrompt")
Prompt.Name = "Furniture"
Prompt.RequiresLineOfSight = false
Prompt.Parent = furniture.CollisionBox
Prompt.ActionText = "Buy " .. furniture.Name .. ": $5"
Prompt.HoldDuration = 1
end
Client Code:
local player = game.Players.LocalPlayer
local backpack = player:WaitForChild("Backpack")
local character = player.Character or player.CharacterAdded:Wait()
local HotBar = script.Parent:WaitForChild("Hotbar")
local ToolSlots = HotBar:WaitForChild("Buttons"):WaitForChild("ToolSlots")
local ToolButtonTemplate = script:WaitForChild("ToolButton")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local InventoryReplicatedStorage = ReplicatedStorage:WaitForChild("InventoryRemotes")
local dropEvent = InventoryReplicatedStorage:WaitForChild("DropToolEvent")
local UserInputService = game:GetService("UserInputService")
local OnMobile = UserInputService.TouchEnabled
-- Disable default backpack GUI
game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
local toolOrder = {}
-- **Dragging state variables**
local isDragging = false
local draggedIndex = nil
local draggedButton = nil
local dragIndicator = nil
local dragThreshold = 10
local initialPos = nil
local dragInput = nil
dragType = nil
local screenGui = HotBar:FindFirstAncestorOfClass("ScreenGui")
-- **Function to start dragging**
local function startDragging(button, input, index)
isDragging = false
draggedButton = button
draggedIndex = index
initialPos = UserInputService:GetMouseLocation()
dragType = input.UserInputType == Enum.UserInputType.MouseButton1 and "mouse" or "touch"
if dragType == "touch" then
dragInput = input
end
end
-- **Updates the toolOrder table to reflect current tools**
local lastSyncTime = 0
local SYNC_INTERVAL = 5 -- seconds
local function updateToolOrder()
local currentTools = {}
for _, tool in ipairs(backpack:GetChildren()) do
if tool:IsA("Tool") then
table.insert(currentTools, tool)
end
end
for _, tool in ipairs(character:GetChildren()) do
if tool:IsA("Tool") then
table.insert(currentTools, tool)
end
end
-- Preserve order of existing tools, append new ones
local newOrder = {}
for _, tool in ipairs(toolOrder) do
if table.find(currentTools, tool) then
table.insert(newOrder, tool)
end
end
for _, tool in ipairs(currentTools) do
if not table.find(toolOrder, tool) then
table.insert(newOrder, tool)
end
end
toolOrder = newOrder
end
-- **Updates the hotbar UI**
local function EquipTool(tool)
if tool:IsA("Tool") then
local character = player.Character
if character then
local humanoid = character:FindFirstChildOfClass("Humanoid")
if humanoid then
if tool.Parent == player.Backpack then
-- Equip the tool: first unequip all tools, then equip this one
humanoid:EquipTool(tool)
elseif tool.Parent == character then
-- Unequip the tool
humanoid:UnequipTools()
end
end
end
end
end
local function updateHotbar()
updateToolOrder()
for _, child in ipairs(ToolSlots:GetChildren()) do
if child:IsA("GuiButton") then
child:Destroy()
end
end
for i, tool in ipairs(toolOrder) do
local button = ToolButtonTemplate:Clone()
button.ButtonText.Text = tool.Name
button.ToolNumber.Text = tostring(i)
button.Name = "ToolButton_" .. i
button.Parent = ToolSlots
button.UIStroke.Enabled = (tool.Parent == character)
-- Equip/Unequip on left-click
button.MouseButton1Click:Connect(function()
EquipTool(tool)
end)
-- **Start dragging on input began**
button.InputBegan:Connect(function(input)
if (input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch) and dragInput == nil then
startDragging(button, input, i)
end
end)
end
end
-- **Function to get the slot index at a given position**
local function getSlotAtPosition(pos)
for i = 1, #toolOrder do
local button = ToolSlots:FindFirstChild("ToolButton_" .. i)
if button then
local absPos = button.AbsolutePosition
local absSize = button.AbsoluteSize
if pos.X >= absPos.X and pos.X <= absPos.X + absSize.X and
pos.Y >= absPos.Y and pos.Y <= absPos.Y + absSize.Y then
return i
end
end
end
return nil
end
-- **Handle input changed for dragging**
UserInputService.InputChanged:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseMovement and draggedIndex ~= nil or
dragType == "touch" and input == dragInput and input.UserInputType == Enum.UserInputType.Touch
then
local currentPos = UserInputService:GetMouseLocation()
if not isDragging then
local distance = (currentPos - initialPos).Magnitude
if distance > dragThreshold then
isDragging = true
dragIndicator = draggedButton:Clone()
dragIndicator.Parent = screenGui
dragIndicator.Position = UDim2.fromOffset(currentPos.X, currentPos.Y)
dragIndicator.AnchorPoint = Vector2.new(0.5, 0.5)
dragIndicator.ZIndex = 10
dragIndicator.Active = false
end
else
dragIndicator.Position = UDim2.fromOffset(currentPos.X, currentPos.Y)
end
end
end)
-- **Handle input ended for dropping**
UserInputService.InputEnded:Connect(function(input)
if (input.UserInputType == Enum.UserInputType.MouseButton1 and draggedIndex ~= nil) or
(dragType == "touch" and input == dragInput)
then
if isDragging and dragIndicator then
dragIndicator:Destroy()
dragIndicator = nil
local endPos = Vector2.new(input.Position.X, input.Position.Y)
local targetIndex = getSlotAtPosition(endPos)
if targetIndex and targetIndex ~= draggedIndex then
-- Swap toolOrder[draggedIndex] and toolOrder[targetIndex]
local temp = toolOrder[draggedIndex]
toolOrder[draggedIndex] = toolOrder[targetIndex]
toolOrder[targetIndex] = temp
-- Update hotbar UI
updateHotbar()
end
end
isDragging = false
dragInput = nil
draggedIndex = nil
draggedButton = nil
end
end)
-- **Refresh hotbar on tool changes**
local function onToolChanged()
updateHotbar()
end
-- **Connect backpack events**
backpack.ChildAdded:Connect(onToolChanged)
backpack.ChildRemoved:Connect(onToolChanged)
-- **Connect character events, reconnect on respawn**
local function connectCharacterEvents()
character.ChildAdded:Connect(onToolChanged)
character.ChildRemoved:Connect(onToolChanged)
end
connectCharacterEvents()
player.CharacterAdded:Connect(function(newCharacter)
character = newCharacter
connectCharacterEvents()
updateHotbar()
end)
-- **Handle key presses for equipping tools**
UserInputService.InputBegan:Connect(function(input, gameProcessed)
if not gameProcessed then
if input.UserInputType == Enum.UserInputType.Keyboard then
local key = input.KeyCode
if key.Value >= Enum.KeyCode.One.Value and key.Value <= Enum.KeyCode.Nine.Value then
local slot = key.Value - Enum.KeyCode.Zero.Value
if slot >= 1 and slot <= #toolOrder then
local tool = toolOrder[slot]
EquipTool(tool)
end
end
end
end
end)
local ContextActionService = require(ReplicatedStorage:WaitForChild("ContextActionUtility"))
local telekenesisGui = player.PlayerGui:WaitForChild("TelekenesisiGui"):WaitForChild("Frame")
local DropLabel = telekenesisGui:WaitForChild("Drop")
local CurrentTool
local DropButton
ContextActionService:BindAction("DropTool", function(actionName, inputState, inputObject)
if inputState == Enum.UserInputState.Begin then
if CurrentTool then
ContextActionService:UnbindAction("UseItem")
dropEvent:FireServer(CurrentTool)
end
end
end, true,Enum.KeyCode.Backspace)
if OnMobile then
DropButton = ContextActionService:GetButton("DropTool")
ContextActionService:SetTitle("DropTool","Drop")
DropButton.Size = UDim2.new(0.6,0,0.6,0)
DropButton.Visible = false
end
character.ChildAdded:Connect(function(child)
if child:IsA("Tool") then
if child:HasTag("Droppable") then
local Connection = child.Unequipped:Connect(function()
if OnMobile then
DropButton.Visible = false
else
DropLabel.Visible = false
end
CurrentTool = nil
end)
if OnMobile then
DropButton.Visible = true
else
DropLabel.Visible = true
end
CurrentTool = child
end
if not child:HasTag("USABLE") then
ContextActionService:UnbindAction("UseItem")
end
end
end)
-- **Initial hotbar setup**
updateHotbar()