1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
--[[
Some functions that are needed multiple places in the code, to deal with player inventories.
]]
local invfuncs = {}
--Forcibly put an item in a backpack, you should check to make sure there's room first
invfuncs.PutItemInBackpack = function(backpack,x,y,item)
backpack[1][x][y] = item
for k = 1,#item.Shape do
for i = 1,#(item.Shape[k]) do
if k == 1 and i == 1 then continue end
backpack[1][x + k - 1][y + i - 1] = item.Shape[k][i]
end
end
end
--Writes a backpack to the net stream
invfuncs.SerializeBackpack = function(backpack)
net.WriteString(backpack[3]) --Name
net.WriteUInt(backpack[2][1],16) --width
net.WriteUInt(backpack[2][2],16) --height
for k,v in pairs(backpack[1]) do
for i,j in pairs(v) do
if type(j) ~= "table" then continue end
net.WriteString(j.Name)
net.WriteUInt(k,16)
net.WriteUInt(i,16)
local data = j:Serialize()
net.WriteUInt(#data,32)
net.WriteData(data,#data)
end
end
net.WriteString("END_ITEMS")
end
--Loads a backpack from the net stream
invfuncs.DeSerializeBackpack = function()
local backpackname = net.ReadString()
local width = net.ReadUInt(16)
local height = net.ReadUInt(16)
--Build the backpack
local tb = {}
tb[1] = {}
tb[2] = {width,height}
tb[3] = backpackname
for x = 1,width do
tb[1][x] = {}
for y = 1,height do
tb[1][x][y] = false
end
end
local nitemname = net.ReadString()
while nitemname ~= "END_ITEMS" do
local xpos = net.ReadUInt(16)
local ypos = net.ReadUInt(16)
local data = net.ReadData(net.ReadUInt(32))
local nitem = ART.GetItemByName(nitemname):DeSerialize(data)
invfuncs.PutItemInBackpack(tb,xpos,ypos,nitem)
nitemname = net.ReadString()
end
return tb
end
--Checks to see if an item can fit in the backpack at a certain position
invfuncs.CanFitInBackpack = function(backpack,x,y,item)
for k,v in pairs(item.Shape) do
for i,j in pairs(v) do
if not j then continue end
if backpack[1][x + k - 1] == nil then
return false
end
if backpack[1][x + k - 1][y + i - 1] or backpack[1][x + k - 1][y + i - 1] == nil then
return false
end
end
end
return true
end
--Creates a new backpack, this is NOT called when players join the server, even new ones.
invfuncs.CreateBackpack = function(name,width,height)
local backpack = {}
backpack[1] = {}
backpack[2] = {width,height}
backpack[3] = name
for i = 1,width do --the width of the backpack.
backpack[1][i] = {}
end
for k,v in pairs(backpack[1]) do
for i = 1,height do --the height of the backpack.
backpack[1][k][i] = false
end
end
return backpack
end
--Displays a dropdown of options under the players mouse, if the option is clicked, does the function
--Requires a table of strings to functions, or strings to tables of strings to functions.
--Be careful not to make this a recursive table.
local function createMenuFor(menu, tbl)
for k,v in pairs(tbl) do
if(isfunction(v)) then --This is a dead-end, add the menu
local thisoption = menu:AddOption(k,v)
else --Otherwise it should be a table, recursively call to create
local submenu = menu:AddSubMenu(k)
createMenuFor(submenu,v)
end
end
end
--Draws a backpack on the dpanel, client side only
invfuncs.DrawBackpackOnDPanel = function(dp, backpack, backpacknum, tent)
local width = ScrW()
local height = ScrH()
local slotsize = math.Round(width / 32)
local backgrid = vgui.Create( "DGrid", dp )
backgrid:SetPos( 10, 30 )
backgrid:SetCols( backpack[2][1] )
backgrid:SetColWide( backpack[2][2] )
backgrid:Dock(FILL)
for i = 1,#(backpack[1]) do
for j = 1,#(backpack[1][i]) do
local item = backpack[1][j][i]
if type(backpack[1][j][i]) == "table" then
local itemwidth = 0
for _,l in pairs(item.Shape) do
itemwidth = math.Max(itemwidth,#l)
end
local itemheight = #item.Shape
local invicon = vgui.Create( "DButton", dp )
invicon:SetSize(slotsize * itemwidth, slotsize * itemheight)
invicon:SetPos(slotsize * (i - 1), slotsize * (j - 1))
invicon:SetText(item.Name)
if item.Tooltip then
invicon:SetTooltip(item.Tooltip)
end
--invicon.Paint = function(self, w, h) draw.RoundedBox(4, 0,0,w,h,Color(0,100,0)) end
invicon.DoClick = function()
if not item.GetOptions then return end
local menu = vgui.Create("DMenu")
createMenuFor(menu,item:GetOptions())
menu:Open()
end
invicon.Item = item
invicon.invpos = {j,i}
invicon.ent = tent
invicon.backpacknum = backpacknum
invicon:Droppable("Inventory")
elseif not backpack[1][j][i] then
local emptyslot = vgui.Create("DPanel", dp)
emptyslot:SetSize(slotsize,slotsize)
emptyslot:SetPos(slotsize * (i - 1), slotsize * (j - 1))
--emptyslot.Paint = function(self, w, h) draw.RoundedBox(4, 0,0,w,h,Color(0,0,100)) end
emptyslot:Receiver( "Inventory", function( receiver, tableOfDroppedPanels, isDropped, menuIndex, mouseX, mouseY )
if not isDropped then return end
local icon = tableOfDroppedPanels[1]
local item = icon.Item
local curpos = icon.invpos
--Set the shape it was at to false
if not icon.wasequiped and icon.ent == tent then
assert(curpos ~= nil, "print curpos was nil when not equiped")
for k = 1,#item.Shape do
for l = 1,#(item.Shape[k]) do
if k == 1 and l == 1 then continue end
backpack[1][curpos[1] + k - 1][curpos[2] + l - 1] = false
end
end
backpack[1][curpos[1]][curpos[2]] = false
end
if invfuncs.CanFitInBackpack(backpack,j,i,item) then
local fromtbl = icon.invpos
local wasequiped = icon.wasequiped
if wasequiped then
net.Start("unequipitem")
net.WriteString(wasequiped)
net.WriteUInt(backpacknum,16)
net.WriteUInt(i,16)
net.WriteUInt(j,16)
net.SendToServer()
else
net.Start("moveitem")
net.WriteEntity(icon.ent) -- from ent
net.WriteEntity(tent) -- to ent
net.WriteUInt(icon.backpacknum,16) -- from backpack number
net.WriteUInt(backpacknum,16) -- to backpack number
net.WriteUInt(fromtbl[1],16) -- From position
net.WriteUInt(fromtbl[2],16)
net.WriteUInt(j,16) -- To position
net.WriteUInt(i,16)
net.SendToServer()
if item.onEquip ~= nil then
item:onEquip(LocalPlayer())
end
end
end
end, {} )
end
end
end
end
return invfuncs
|