11 part
3: Treasure spawning
mod handling
12 part
4: Internal functions
16 part
1: Initialization
19 -- This creates the main table; all functions of this mod are stored in this table
22 -- Table which stores all the treasures
23 treasurer
.treasures
= {}
25 -- This table stores the treasures again, but this time sorted by groups
28 -- Groups defined by the Treasurer API
29 treasurer
.groups
.treasurer
= {}
30 treasurer
.groups
.treasurer
.default
= {}
32 -- Groups defined by the Minetest API
33 treasurer
.groups
.minetest
= {}
36 format of treasure table:
38 name, -- treasure name, e.g. mymod:item
39 rarity, -- relative rarity on a scale from 0 to 1 (inclusive).
40 -- a rare treasure must not neccessarily be a precious treasure
41 count, -- count (see below)
42 preciousness, -- preciousness or “worth” of the treasure.
43 -- ranges from 0 (“scorched stuff”) to 10 (“diamond block”)
44 wear, -- wear (see below)
45 metadata, -- unused at the moment
48 treasures can be nodes or items
51 count = number -- it’s always number times
52 count = {min, max} -- it’s pseudorandomly between min and max times, math.random() will be used to chose the value
53 count = {min, max, prob_func} -- it’s between min and max times, and the value is given by prob_func (which is not neccessarily random [in the strictly mathematical sense])
56 completely analogous to count type
58 format of prob_func function:
59 prob_func = function()
60 --> returns a random or pseudorandom number between 0 (inclusive) and 1 (exclusive)
61 prob_func is entirely optional, if it’s not used, treasurer will default to math.random.
62 You can use prob_func to define your own random function, in case you don’t like an even
65 format of treasurer_groups:
66 This is just a table of strings, each string stands for a group name.
75 treasurer.register_treasure - registers a new treasure
76 (this means the treasure will be ready to be spawned by treasure spawning mods.
78 name: name of resulting ItemStack, e.g. “mymod:item”
79 rarity: rarity of treasure on a scale from 0 to 1 (inclusive). lower = rarer
80 preciousness: preciousness of treasure on a scale from 0 (“scorched stuff”) to 10 (“diamond block”).
81 count: optional value which specifies the multiplicity of the item. Default is 1. See count syntax help in this file.
82 wear: optional value which specifies the wear of the item. Default is 0, which disables the wear. See wear syntax help in this file.
83 treasurer_groups: (optional) a table of group names to assign this treasure to. If omitted, the treasure is added to the default group.
84 This function does some basic parameter checking to catch the most obvious mistakes. If invalid parameters have been passed, the input is rejected and the function returns false. However, it does not cover every possible mistake, so some invalid treasures may slip through.
86 returns: true on success, false on failure
88 function treasurer
.register_treasure(name
, rarity
, preciousness
, count
, wear
, treasurer_groups
)
89 --[[ We don’t trust our input, so we first check if the parameters
90 have the correct types and refuse to add the treasure if a
91 parameter is malformed.
92 What follows is a bunch of parameter checks.
95 -- check wheather name is a string
96 if type(name
) ~= "string" then
97 minetest
.log("error","[treasure] I rejected a treasure because the name was of type \""..type(name
).."\" instead of \"string\".")
100 -- first check if rarity is even a number
101 if type(rarity
) == "number" then
102 -- then check wheather the rarity lies in the allowed range
103 if rarity
< 0 or rarity
> 1 then
104 minetest
.log("error", "[treasurer] I rejected the treasure \""..tostring(name
).."\" because it’s rarity value is out of bounds. (it was "..tostring(rarity
)..".)")
108 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had an illegal type of rarity. Given type was \""..type(rarity
).."\".")
112 -- check if preciousness is even a number
113 if type(preciousness
) == "number" then
114 -- then check wheather the preciousness lies in the allowed range
115 if preciousness
< 0 or preciousness
> 10 then
116 minetest
.log("error", "[treasurer] I rejected the treasure \""..tostring(name
).."\" because it’s preciousness value is out of bounds. (it was "..tostring(preciousness
)..".)")
120 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had an illegal type of preciousness. Given type was \""..type(preciousness
).."\".")
125 -- first check if count is of a correct type
126 if type(count
) ~= "number" and type(count
) ~= "nil" and type(count
) ~= "table" then
127 minetest
.log("error", "[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had an illegal type of “count”. Given type was \""..type(count
).."\".")
130 -- if count’s a table, check if it’s format is correct
131 if type(count
) == "table" then
132 if(not (type(count
[1]) == "number" and type(count
[2]) == "number" and (type(count
[3]) == "function" or type(count
[3]) == "nil"))) then
133 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had a malformed table for the count parameter.")
138 -- now do the same for wear:
139 -- first check if wear is of a correct type
140 if type(wear
) ~= "number" and type(wear
) ~= "nil" and type(wear
) ~= "table" then
141 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had an illegal type of “wear”. Given type was \""..type(wear
).."\".")
144 -- if wear’s a table, check if it’s format is correct
145 if type(wear
) == "table" then
146 if(not (type(wear
[1]) == "number" and type(wear
[2]) == "number" and (type(wear
[3]) == "function" or type(wear
[3]) == "nil"))) then
147 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because it had a malformed table for the wear parameter.")
152 -- check type of treasurer_group
153 if type(treasurer_groups
) ~= "table" and type(treasurer_groups
) ~= "nil" and type(treasurer_groups
) ~= "string" then
154 minetest
.log("error","[treasurer] I rejected the treasure \""..tostring(name
).."\" because the treasure_group parameter is of type "..tostring(type(treasurer_groups
)).." (expected: nil, string or table).")
161 --[[ End of checks. If we reached this point of the code, all checks have been passed
162 and we finally register the treasure.]]
164 -- default count is 1
165 if count
== nil then count
= 1 end
167 if wear
== nil then wear
= 0 end
173 preciousness
= preciousness
,
176 table.insert(treasurer
.treasures
, treasure
)
178 --[[ Assign treasure to Treasurer group(s) or default if not provided ]]
179 -- default Treasurer group is default
180 if treasurer_groups
== nil then treasurer_groups
= "default" end
182 if(type(treasurer_groups
) == "string") then
183 if(treasurer
.groups
.treasurer
[treasurer_groups
] == nil) then
184 treasurer
.groups
.treasurer
[treasurer_groups
] = {}
186 table.insert(treasurer
.groups
.treasurer
[treasurer_groups
], treasure
)
187 elseif(type(treasurer_groups
) == "table") then
188 for i
=1,#treasurer_groups
do
189 -- assign to Treasurer group (create table if it does not exist yet)
190 if(treasurer
.groups
.treasurer
[treasurer_groups
[i]]
== nil) then
191 treasurer
.groups
.treasurer
[treasurer_groups
[i]]
= {}
193 table.insert(treasurer
.groups
.treasurer
[treasurer_groups
[i]]
, treasure
)
198 minetest
.log("info","[treasurer] Treasure successfully registered: "..name
)
204 part
3: Treasure spawning
mod (TSM
) handling
208 treasurer.select_random_treasures - request some treasures from treasurer
210 count: (optional) amount of items in the treasure. If this value is nil, treasurer assumes a default of 1.
211 min_preciousness: (optional) don’t consider treasures with a lower preciousness. nil = no lower limit
212 max_preciousness: (optional) don’t consider treasures with a higher preciousness. nil = no lower limit
213 treasurer_groups: (optional): Only consider treasures which are members of at least one of the members of the provided Treasurer group table. nil = consider all groups
215 a table of ItemStacks (the requested treasures) - may be empty
216 on error, it returns false
218 function treasurer
.select_random_treasures(count
, min_preciousness
, max_preciousness
, treasurer_groups
)
219 if #treasurer
.treasures
== 0 and count
>= 1 then
220 minetest
.log("info","[treasurer] I was asked to return "..count
.." treasure(s) but I can’t return any because no treasure was registered to me.")
223 if count
== nil then count
= 1 end
228 -- copy treasures into helper table
229 local p_treasures
= {}
230 if(treasurer_groups
== nil) then
231 -- if the group filter is not used (defaul behaviour), copy all treasures
232 for i
=1,#treasurer
.treasures
do
233 table.insert(p_treasures
, treasurer
.treasures
[i
])
236 -- if the group filter IS used, copy only the treasures from the said groups
237 elseif(type(treasurer_groups
) == "string") then
238 if(treasurer
.groups
.treasurer
[treasurer_groups
] ~= nil) then
239 for i
=1,#treasurer
.groups
.treasurer
[treasurer_groups
] do
240 table.insert(p_treasures
, treasurer
.groups
.treasurer
[treasurer_groups
][i
])
243 minetest
.log("info","[treasurer] I was asked to return "..count
.." treasure(s) but I can’t return any because no treasure which fits to the given Treasurer group “"..treasurer_groups
.."”.")
246 elseif(type(treasurer_groups
) == "table") then
247 for t
=1,#treasurer_groups
do
248 if(treasurer
.groups
.treasurer
[treasurer_groups
[t]]
~= nil) then
249 for i
=1,#treasurer
.groups
.treasurer
[treasurer_groups
[t]]
do
250 table.insert(p_treasures
, treasurer
.groups
.treasurer
[treasurer_groups
[t]]
[i
])
255 minetest
.log("error","[treasurer] treasurer.select_random_treasures was called with a malformed treasurer_groups parameter!")
259 if(min_preciousness
~= nil) then
260 -- filter out too unprecious treasures
261 for t
=#p_treasures
,1,-1 do
262 if((p_treasures
[t
].preciousness
) < min_preciousness
) then
263 table.remove(p_treasures
,t
)
268 if(max_preciousness
~= nil) then
269 -- filter out too precious treasures
270 for t
=#p_treasures
,1,-1 do
271 if(p_treasures
[t
].preciousness
> max_preciousness
) then
272 table.remove(p_treasures
,t
)
277 for t
=1,#p_treasures
do
278 sum
= sum
+ p_treasures
[t
].rarity
282 randoms
[c
] = math
.random() * sum
287 for t
=1,#p_treasures
do
288 if randoms
[c
] < cumulate
[t
] then
289 table.insert(treasures
, p_treasures
[t
])
295 local itemstacks
= {}
296 for i
=1,#treasures
do
297 itemstacks
[i
] = treasurer
.treasure_to_itemstack(treasures
[i
])
299 if #itemstacks
< count
then
300 minetest
.log("info","[treasurer] I was asked to return "..count
.." treasure(s) but I could only return "..(#itemstacks
)..".")
306 Part
4: internal functions
309 --[[ treasurer.treasure_to_itemstack - converts a treasure table to an
312 treasure: a treasure (see format in the head of this file)
316 function treasurer
.treasure_to_itemstack(treasure
)
318 itemstack
.name
= treasure
.name
319 itemstack
.count
= treasurer
.determine_count(treasure
)
320 itemstack
.wear
= treasurer
.determine_wear(treasure
)
321 itemstack
.metadata
= treasure
.metadata
323 return ItemStack(itemstack
)
327 This determines the count of a treasure by taking the various different
328 possible types of the count value into account
329 This function assumes that the treasure table is valid.
332 function treasurer
.determine_count(treasure
)
333 if(type(treasure
.count
)=="number") then
334 return treasure
.count
336 local min,max,prob
= treasure
.count
[1], treasure
.count
[2], treasure
.count
[3]
338 return(math
.floor(min + math
.random() * (max-min)))
340 return(math
.floor(min + prob() * (max-min)))
346 This determines the wear of a treasure by taking the various different
347 possible types of the wear value into account.
348 This function assumes that the treasure table is valid.
351 function treasurer
.determine_wear(treasure
)
352 if(type(treasure
.wear
)=="number") then
355 local min,max,prob
= treasure
.wear
[1], treasure
.wear
[2], treasure
.wear
[3]
357 return(math
.floor(min + math
.random() * (max-min)))
359 return(math
.floor(min + prob() * (max-min)))