--[[ Various functions to work with inventories ]] --- Various functions to deal with inventories. -- @module Player local pmeta = FindMetaTable("Player") local emeta = FindMetaTable("Entity") local invfuncs = include("inventory_common.lua") --A 2d array of the inventory. pmeta.Inventory = pmeta.Inventory or {} --each backpack has 1:a tbl containing items or false, 2: a tbl {width,height} and 3:name pmeta.Inventory.Backpacks = pmeta.Inventory.Backpacks or {} --Eqiped stuff at base, player has 1=Head, 2=Body, 3=Legs, 4=Boots, 5=Gloves, 6=Left Hand, 7=Right Hand pmeta.Inventory.Equiped = pmeta.Inventory.Equiped or {} local equipedslots = { "Head","Body","Legs","Boots","Gloves","Left","Right" } for _,v in pairs(equipedslots) do pmeta.Inventory.Equiped[v] = pmeta.Inventory.Equiped[v] or false end --- Puts an item in the inventory. -- Puts an item in an inventory, overwriteing all other items it might be overlapping, you should check to make sure you're not over writeing something first. -- @param backpack the backpack number this item should be placed in -- @param x the column in the backpack this item should be placed in -- @param y the row in the backpack this item should be placed in -- @param item the item to place in the backpack. -- @see Player.FindSpotForItem function pmeta:PutInvItem(backpack,x,y,item) invfuncs.PutItemInBackpack(self.Inventory.Backpacks[backpack],x,y,item) end --- Finds a spot for an item. -- Finds a backpack, row, and column for an item in a player's inventory. -- @param item The item to try and fit into the backpack. -- @return row The row where a spot was found -- @return col The column where a spot was found -- @return n The backpack number where a spot was found function pmeta:FindSpotForItem(item) for n,v in pairs(self.Inventory.Backpacks) do for row = 1,v[2][2] do for col = 1,v[2][1] do if self:CanFitInBackpack(v,row,col,item) then return row,col,n end end end end end --- Checks if the player has an item by name -- function pmeta:HasItem(itemname) for n,v in pairs(self.Inventory.Backpacks) do for row = 1,v[2][2] do for col = 1,v[2][1] do local itemin = v[1][row][col] if itemin ~= false and itemin.Name == itemname then return row,col,n end end end end end function pmeta:RemoveItemAt(backpack,row,col) local item = self.Inventory.Backpacks[backpack][1][row][col] for k = 1,#item.Shape do for i = 1,#(item.Shape[k]) do self.Inventory.Backpacks[backpack][1][row + k - 1][col + i - 1] = false end end self:SynchronizeInventory() end function pmeta:GiveItem(item) local x,y,b = self:FindSpotForItem(item) self:PutInvItem(b,x,y,item) self:SynchronizeInventory() end function pmeta:CanFitInBackpack(backpack,x,y,item) return invfuncs.CanFitInBackpack(backpack,x,y,item) end if SERVER then util.AddNetworkString("synchinventory") util.AddNetworkString("moveitem") util.AddNetworkString("equipitem") util.AddNetworkString("unequipitem") end net.Receive("unequipitem",function(len,ply) local itemslot = net.ReadString() local tobackpack = net.ReadUInt(16) local topos = {} topos[1] = net.ReadUInt(16) topos[2] = net.ReadUInt(16) local item = ply.Inventory.Equiped[itemslot] if ply:CanFitInBackpack( ply.Inventory.Backpacks[tobackpack], topos[1], topos[2], item ) then ply.Inventory.Equiped[itemslot] = false ply:PutInvItem(tobackpack,topos[1],topos[2],item) if item.onUnEquip ~= nil then item:onUnEquip(ply) end ply:SynchronizeInventory() end end) net.Receive("equipitem",function(len,ply) local backpacknum = net.ReadUInt(16) local frompos = {} frompos[1] = net.ReadUInt(16) frompos[2] = net.ReadUInt(16) local equippos = net.ReadString() local item = ply.Inventory.Backpacks[backpacknum][1][frompos[1]][frompos[2]] if item.Equipable ~= nil and item.Equipable == equippos then --Remove from the backpack for k = 1,#item.Shape do for i = 1,#(item.Shape[k]) do if k == 1 and i == 1 then continue end ply.Inventory.Backpacks[backpacknum][1][frompos[1] + k - 1][frompos[2] + i - 1] = false end end ply.Inventory.Backpacks[backpacknum][1][frompos[1]][frompos[2]] = false ply.Inventory.Equiped[equippos] = item if item.onEquip ~= nil then item:onEquip(ply) end ply:SynchronizeInventory() end end) net.Receive("moveitem",function(len,ply) local froment = net.ReadEntity() local toent = net.ReadEntity() local frombackpack = net.ReadUInt(16) local tobackpack = net.ReadUInt(16) local frompos = {net.ReadUInt(16),net.ReadUInt(16)} local topos = {net.ReadUInt(16),net.ReadUInt(16)} if froment:IsPlayer() and toent:IsPlayer() and (froment ~= toent) then--Just don't allow stealing between players, anything else is fine ply:PrintMessage( HUD_PRINTCENTER, "You can't steal from this person!" ) return end local item = froment.Inventory.Backpacks[frombackpack][1][frompos[1]][frompos[2]] --Set the shape it was at to false for k = 1,#item.Shape do for i = 1,#(item.Shape[k]) do if k == 1 and i == 1 then continue end froment.Inventory.Backpacks[frombackpack][1][frompos[1] + k - 1][frompos[2] + i - 1] = false end end froment.Inventory.Backpacks[frombackpack][1][frompos[1]][frompos[2]] = false --now check if it can fit in the backpack if invfuncs.CanFitInBackpack(toent.Inventory.Backpacks[tobackpack],topos[1],topos[2],item) then invfuncs.PutItemInBackpack(toent.Inventory.Backpacks[tobackpack],topos[1],topos[2],item) else invfuncs.PutItemInBackpack(froment.Inventory.Backpacks[frombackpack],frompos[1],frompos[2],item) end froment:SynchronizeInventory() toent:SynchronizeInventory() end) function pmeta:LoadInventory(json) local reinv = util.JSONToTable(json) for k,v in pairs(reinv) do self.Inventory[k] = v end self:SynchronizeInventory() end function pmeta:SynchronizeInventory() net.Start("synchinventory") net.WriteEntity(self) net.WriteFloat(#self.Inventory.Backpacks) for k,v in pairs(self.Inventory.Backpacks) do invfuncs.SerializeBackpack(v) end for k,v in pairs(equipedslots) do if self.Inventory.Equiped and self.Inventory.Equiped[v] ~= false then net.WriteString(v) local data = self.Inventory.Equiped[v]:Serialize() net.WriteString(self.Inventory.Equiped[v].Name) net.WriteUInt(#data,32) net.WriteData(data,#data) end end net.WriteString("END_EQUIPED") net.Send(self) end if CLIENT then net.Receive("synchinventory",function(len,ply) if LocalPlayer().invdisplays == nil then LocalPlayer().invdisplays = {} end local what = net.ReadEntity() what.Inventory.Backpacks = {} local numbackpacks = net.ReadFloat() for k = 1,numbackpacks do local tbackpack = invfuncs.DeSerializeBackpack() table.insert(what.Inventory.Backpacks,tbackpack) end local neq = net.ReadString() local updated_slots = {} while neq ~= "END_EQUIPED" do local itemslot = neq local itemname = net.ReadString() local itemdata = net.ReadData(net.ReadUInt(32)) local item = ART.GetItemByName(itemname):DeSerialize(itemdata) what.Inventory.Equiped[itemslot] = item updated_slots[itemslot] = true neq = net.ReadString() end if what.Inventory.Equiped ~= nil then for k,v in pairs(equipedslots) do if updated_slots[v] then continue end what.Inventory.Equiped[v] = false end end local discopy = LocalPlayer().invdisplays LocalPlayer().invdisplays = {} for k,ptbl in pairs(discopy) do if not ptbl.panel:IsValid() then continue end if ptbl.panel.Close ~= nil then ptbl.panel:Close() else print(ptbl.panel) error("panel has no close method") ptbl.panel:Remove() end ptbl.redraw() end end) end concommand.Add("artery_showinventory",function(ply,cmd,args) PrintTable(ply.Inventory) PrintTable(ply.ClientInventory) end) hook.Add( "PlayerSpawn", "artery_disable_sprint", function(ply) ply:SetRunSpeed(ply:GetWalkSpeed()) end )