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
|
# Tut 0x030
## Inventories
Many gamemode bases try to build an inventory system into the gamemode, leaving the developer with few ways to actually use the system more than "put item in, take item out". Artery somewhat forces you to build your own inventories to use.
In this tutorial, we'll build a simple rougelike inventory, where we expect items to have a "weight", and we can carry as many items as we want, as long as we don't exceed our "max weight".
Inventories and items in Artery are just tables, as per usual in lua. They have a few required fields each. On the left, under "Classes", open invtbl and itemtbl in new tabs.
## A simple inventory
You can see all the fields needed for an inventory, so let's get started. Recall that
function tbl:func_name(one)
...
end
is the same as
function tbl.func_name(self,one)
...
end
lua will automatically create the variable "self" in the first example
garrysmod/addons/artery_rougelite/data/artery/global/rougeinv.lua
local inventory_registry = nrequire("inventory.lua")
local item_registry = nrequire("item.lua")
local inv = {}
inv.items = {} --A table of all the items we have
inv.maxweight = 100 --The maximum weight of all our items
inv.weight = 0 --The current weight of all our items.
--Technically we could calculate the weight based on the "items" table,
-- but that might start taking a long time if we have a lot of low-weight items.
--Returns a position for an item, or nil if we don't have room
function inv:FindPlaceFor(item)
--Make sure we won't be over weight when we add the item
if self.weight + item.weight > self.maxweight then
return nil
end
--[[
ALWAYS return a table position, even if you only need a number.
This is the same as
return {
[1] = #self.items + 1
}
]]
return {#self.items + 1}
end
function inv:CanFitIn(position,item)
--Check that we won't be over weight
if self.weight + item.weight > self.maxweight then
return false
end
--And make sure we don't already have an item in that position
if self.items[position[1]] ~= nil then
return false
end
--If we won't go over weight, and the position isn't already used, we can fit it!
return true
end
--Put something into our inventory
function inv:Put(position,item)
self.items[position[1]] = item
self.weight = self.weight + item.weight
end
--This one is a bit complicated
--ptr can be either a string, or a function that takes 1 argument,
-- and returns true when given an object we should return.
--this function returns a POSITION that can be given back to get, remove, ect.
-- the object.
function inv:Has(ptr)
--Look for an item with the given name
if type(ptr) == "string" then
for k,v in pairs(self.items) do
if v.Name == ptr then
return {k}
end
end
elseif type(ptr) == "function" then
for k,v in pairs(self.items) do
if ptr(v) then
return {k}
end
end
end
return nil
end
--Removes an item from our inventory, returns the item we removed
function inv:Remove(position)
local item = self.items[position[1]]
self.weight = self.weight - item.weight
self.items[position[1]] = nil
return item
end
--Gets the item in a given position
function inv:Get(position)
return self.items[position[1]]
end
--Creates a string that this inventory can be re-created with
function inv:Serialize()
local ser = {}
for k,v in pairs(self.items) do
ser[k] = {
v.Name,
v:Serialize()
}
end
return util.TableToJSON(ser)
end
--Re-creates this inventory from the data created by Serialize()
function inv:DeSerialize(data)
local self_copy = table.Copy(self)
local json = util.JSONToTable(data)
for k,v in pairs(json) do
local item_name = v[1]
local item_data = v[2]
local item = item_registry.GetItemFromData(item_name,item_data)
self_copy.items[k] = item
end
for k,v in pair(self_copy.items) do
self_copy.weight = self_copy.weight + v.weight
end
return self_copy
end
--Don't forget to register it with the gamemode!
inventory_registry.RegisterInventory(inv)
That was a bit long, but we're done! This is the absolute minimum needed to create an Artery inventory. Now you can go in-game and use the console command `artery_printinventories`, and in that list, you will see your newly made inventory!
|