--[[ An inventory that accepts materials and can store 100's of them. ]] --[[ Public functions: RegisterInventory(tbl_inventory) ::nil Registers a new inventory prototype, see below CreateInventory(string_name) ::table_inventory Creates a new inventory be sure to set the .owner and .id fields! CreateInventoryFromData(string_name,string_data)::table_inventory) Just deserializes an inventory. You still need to set .owner and .id! DeriveInventory(string_name) ::table_inventory Creates a new inventory from an old, allows for heiarchy. Inventories have the following structure field returns inv.Name ::string The name! inv:FindPlaceFor(item) ::table_position or nil Finds a place for the item inv:CanFitIn(table_position,item) ::boolean Check if the item can fit in the position inv:Put(table_position,item) ::nil Put an item in at the position inv:Has(string_or_compare_func) ::table_position or nil find an item in the inventory inv:Remove(position) ::table_item Remove an item from the position inv:Get(position) ::table_item Get the item at a position inv:Serialize() ::string Serialize the item to store it in a db inv:DeSerialize(str) ::table_inventory recreate the item from data in serialize The above fields must be defined for new inventories. ----------------------------------------------------- The below are automatically made if they do not exist. inv:AddObserver(tbl_other) ::number_id Whenever put or remove is called on this inventory, tbl_other's put() and remove() is also called, for easy networking to whoever needs it inv:RemoveObserver(number_id) ::nil Removes an observer from the inventory ------------------------------------------------------ These fields should be defined when an inventory is created, before it can be used inv.Owner ::entity inv.id ::number ]] if not nrequire then return end local reg = nrequire("core/inventory/inventory.lua") local itm = nrequire("core/inventory/item.lua") local i = {} i.Name = "Crafting Inventory" i.materials = {} i.accepts = {} function i:FindPlaceFor(item) if not self.accepts[item.Name] then return nil end return {item.Name} end function i:CanFitIn(position,item) return self.accepts[item.Name] end function i:Put(pos,item) self.materials[item.Name] = (self.materials[item.Name] or 0) + 1 end function i:Has(str_or_cmp) if type(str_or_cmp) == "function" then error("Tried to check has of a workbench with function") end if (self.materials[str_or_cmp] or 0) > 0 then return {str_or_cmp} else return nil end end function i:Remove(tbl) local ret = itm.GetItemByName(tbl[1]) assert(self.materials[ tbl[1] ] > 0, "Tried to remove a resource when we didn't have any!") self.materials[ tbl[1] ] = self.materials[ tbl[1] ] - 1 return ret end function i:Get(tbl) return itm.GetItemByName(tbl[1]) end function i:Serialize() local s = { materials = self.materials, accepts = self.accepts } return util.TableToJSON(s) end function i:DeSerialize(data) local cpy = table.Copy(self) local d = util.JSONToTable(data) cpy.materials = d.materials cpy.accepts = d.accepts return cpy end if CLIENT then local svg = nrequire("cl_svg.lua") local com = nrequire("cl_common.lua") local col = nrequire("colortheme.lua") local c = col.ui.border local inputimg = svg.MaterialFromSVG("materials/svg/delapouite/gui/svg/000000/transparent/plain-arrow.svg", nil, ucol) function i.DrawOnDPanel(self,dpanel) local matpnls = {} local matscroll = vgui.Create("DScrollPanel",dpanel) matscroll:Dock(FILL) local inputpnl = vgui.Create("DModelPanel",dpanel) --inputpnl:Dock(TOP) inputpnl.PaintOver = function(tp,w,h) if inputimg.material then surface.SetDrawColor(c.r,c.g,c.b) surface.DrawOutlinedRect(0, 0, h, h) surface.SetDrawColor(255,255,255) surface.SetMaterial( inputimg.material ) surface.DrawTexturedRect( 0, 0, h, h ) end end inputpnl:Receiver("item",com.generatereceiver()) inputpnl:SetSize(50,50) inputpnl.info = { owner = self.Owner, id = self.id, pos = {"*"}, inv = self } inputpnl:Dock(TOP) local function create_panel(k,v) local pnlitem = {} pnlitem.panel = vgui.Create("DPanel",matscroll) pnlitem.panel:Dock(TOP) pnlitem.text = vgui.Create("DLabel",pnlitem.panel) pnlitem.text:SetText(string.format("%10s : %5d",k,v - 1)) pnlitem.text:Dock(FILL) pnlitem.text:SetDark(true) local ta = vgui.Create("DModelPanel",pnlitem.panel) ta:Dock(LEFT) ta:Droppable("item") ta.info = { owner = self.Owner, id = self.id, pos = {k}, inv = self } matpnls[k] = pnlitem end for k,v in pairs(self.materials) do if v > 0 then create_panel(k,v) end end local function refresh_ammt(name,p) local pnlitem = matpnls[ name ] local ammt = self.materials[name] if ammt == 0 or ammt == nil then pnlitem.panel:Remove() else pnlitem.text:SetText(string.format("%10s : %5d",name,ammt)) --Called before the actual inventorie's put, so +1 end end local observer = {} observer.Put = function(obs,position,item) if self.materials[ item.Name ] == nil or self.materials[ item.Name ] == 0 then --Create a panel for the item create_panel(item.Name,1) else refresh_ammt(item.Name,1) end --matslbls[ position[1] ]:SetText(self.materials[ position[1] ]) --drawitemat(self,position[1],position[2],item) end observer.Remove = function(obs,position) if self.materials[position[1]] == 1 then --Remove at 1 since this is called before inventory's remove() matpnls[position[1]].panel:Remove() end refresh_ammt(position[1],-1) --matslbls[ position[1] ]:SetText(self.materials[ position[1] ]) --undrawitemat(self,position[1],position[2]) end return observer end end reg.RegisterInventory(i)