api.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. --[[
  2. Minetest Mod Storage Drawers - A Mod adding storage drawers
  3. Copyright (C) 2017-2019 Linus Jahn <lnj@kaidan.im>
  4. Copyright (C) 2016 Mango Tango <mtango688@gmail.com>
  5. MIT License
  6. Permission is hereby granted, free of charge, to any person obtaining a copy
  7. of this software and associated documentation files (the "Software"), to deal
  8. in the Software without restriction, including without limitation the rights
  9. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10. copies of the Software, and to permit persons to whom the Software is
  11. furnished to do so, subject to the following conditions:
  12. The above copyright notice and this permission notice shall be included in all
  13. copies or substantial portions of the Software.
  14. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. SOFTWARE.
  21. ]]
  22. -- Load support for intllib.
  23. local MP = core.get_modpath(core.get_current_modname())
  24. local S, NS = dofile(MP.."/intllib.lua")
  25. drawers.node_box_simple = {
  26. {-0.5, -0.5, -0.4375, 0.5, 0.5, 0.5},
  27. {-0.5, -0.5, -0.5, -0.4375, 0.5, -0.4375},
  28. {0.4375, -0.5, -0.5, 0.5, 0.5, -0.4375},
  29. {-0.4375, 0.4375, -0.5, 0.4375, 0.5, -0.4375},
  30. {-0.4375, -0.5, -0.5, 0.4375, -0.4375, -0.4375},
  31. }
  32. drawers.drawer_formspec = "size[9,7]" ..
  33. "list[context;upgrades;2,0.5;5,1;]" ..
  34. "list[current_player;main;0,3;9,4;]" ..
  35. drawers.gui_bg ..
  36. drawers.gui_bg_img ..
  37. drawers.gui_slots ..
  38. drawers.get_upgrade_slots_bg(2, 0.5)
  39. -- construct drawer
  40. function drawers.drawer_on_construct(pos)
  41. local node = core.get_node(pos)
  42. local ndef = core.registered_nodes[node.name]
  43. local drawerType = ndef.groups.drawer
  44. local base_stack_max = core.nodedef_default.stack_max or 99
  45. local stack_max_factor = ndef.drawer_stack_max_factor or 24 -- 3x8
  46. stack_max_factor = math.floor(stack_max_factor / drawerType) -- drawerType => number of drawers in node
  47. -- meta
  48. local meta = core.get_meta(pos)
  49. local i = 1
  50. while i <= drawerType do
  51. local vid = i
  52. -- 1x1 drawers don't have numbers in the meta fields
  53. if drawerType == 1 then vid = "" end
  54. meta:set_string("name"..vid, "")
  55. meta:set_int("count"..vid, 0)
  56. meta:set_int("max_count"..vid, base_stack_max * stack_max_factor)
  57. meta:set_int("base_stack_max"..vid, base_stack_max)
  58. meta:set_string("entity_infotext"..vid, drawers.gen_info_text(S("Empty"), 0,
  59. stack_max_factor, base_stack_max))
  60. meta:set_int("stack_max_factor"..vid, stack_max_factor)
  61. i = i + 1
  62. end
  63. -- spawn all visuals
  64. drawers.spawn_visuals(pos)
  65. -- create drawer upgrade inventory
  66. meta:get_inventory():set_size("upgrades", 5)
  67. -- set the formspec
  68. meta:set_string("formspec", drawers.drawer_formspec)
  69. end
  70. -- destruct drawer
  71. function drawers.drawer_on_destruct(pos)
  72. drawers.remove_visuals(pos)
  73. -- clean up visual cache
  74. if drawers.drawer_visuals[core.serialize(pos)] then
  75. drawers.drawer_visuals[core.serialize(pos)] = nil
  76. end
  77. end
  78. -- drop all items
  79. function drawers.drawer_on_dig(pos, node, player)
  80. local drawerType = 1
  81. if core.registered_nodes[node.name] then
  82. drawerType = core.registered_nodes[node.name].groups.drawer
  83. end
  84. if core.is_protected(pos,player:get_player_name()) then
  85. core.record_protection_violation(pos,player:get_player_name())
  86. return 0
  87. end
  88. local meta = core.get_meta(pos)
  89. local k = 1
  90. while k <= drawerType do
  91. -- don't add a number in meta fields for 1x1 drawers
  92. local vid = tostring(k)
  93. if drawerType == 1 then vid = "" end
  94. local count = meta:get_int("count"..vid)
  95. local name = meta:get_string("name"..vid)
  96. -- drop the items
  97. local stack_max = ItemStack(name):get_stack_max()
  98. local j = math.floor(count / stack_max) + 1
  99. local i = 1
  100. while i <= j do
  101. local rndpos = drawers.randomize_pos(pos)
  102. if not (i == j) then
  103. core.add_item(rndpos, name .. " " .. stack_max)
  104. else
  105. core.add_item(rndpos, name .. " " .. count % stack_max)
  106. end
  107. i = i + 1
  108. end
  109. k = k + 1
  110. end
  111. -- drop all drawer upgrades
  112. local upgrades = meta:get_inventory():get_list("upgrades")
  113. if upgrades then
  114. for _,itemStack in pairs(upgrades) do
  115. if itemStack:get_count() > 0 then
  116. local rndpos = drawers.randomize_pos(pos)
  117. core.add_item(rndpos, itemStack:get_name())
  118. end
  119. end
  120. end
  121. -- remove node
  122. core.node_dig(pos, node, player)
  123. end
  124. function drawers.drawer_allow_metadata_inventory_put(pos, listname, index, stack, player)
  125. if core.is_protected(pos,player:get_player_name()) then
  126. core.record_protection_violation(pos,player:get_player_name())
  127. return 0
  128. end
  129. if listname ~= "upgrades" then
  130. return 0
  131. end
  132. if stack:get_count() > 1 then
  133. return 0
  134. end
  135. if core.get_item_group(stack:get_name(), "drawer_upgrade") < 1 then
  136. return 0
  137. end
  138. return 1
  139. end
  140. function drawers.add_drawer_upgrade(pos, listname, index, stack, player)
  141. -- only do anything if adding to upgrades
  142. if listname ~= "upgrades" then return end
  143. drawers.update_drawer_upgrades(pos)
  144. end
  145. function drawers.remove_drawer_upgrade(pos, listname, index, stack, player)
  146. -- only do anything if adding to upgrades
  147. if listname ~= "upgrades" then return end
  148. drawers.update_drawer_upgrades(pos)
  149. end
  150. function drawers.drawer_insert_object(pos, node, stack, direction)
  151. local drawer_visuals = drawers.drawer_visuals[core.serialize(pos)]
  152. if not drawer_visuals then return stack end
  153. -- first try to insert in the correct slot (if there are already items)
  154. local leftover = stack
  155. for _, visual in pairs(drawer_visuals) do
  156. if visual.itemName == stack:get_name() then
  157. leftover = visual:try_insert_stack(leftover, true)
  158. end
  159. end
  160. -- if there's still something left, also use other slots
  161. if leftover:get_count() > 0 then
  162. for _, visual in pairs(drawer_visuals) do
  163. leftover = visual:try_insert_stack(leftover, true)
  164. end
  165. end
  166. return leftover
  167. end
  168. function drawers.drawer_can_insert_object(pos, node, stack, direction)
  169. local drawer_visuals = drawers.drawer_visuals[core.serialize(pos)]
  170. if not drawer_visuals then return false end
  171. for _, visual in pairs(drawer_visuals) do
  172. if visual.itemName == "" or (visual.itemName == stack:get_name() and visual.count ~= visual.maxCount) then
  173. return true
  174. end
  175. end
  176. return false
  177. end
  178. function drawers.register_drawer(name, def)
  179. def.description = def.description or S("Wooden")
  180. def.drawtype = "nodebox"
  181. def.node_box = {type = "fixed", fixed = drawers.node_box_simple}
  182. def.collision_box = {type = "regular"}
  183. def.selection_box = {type = "fixed", fixed = drawers.node_box_simple}
  184. def.paramtype = "light"
  185. def.paramtype2 = "facedir"
  186. def.legacy_facedir_simple = true
  187. def.groups = def.groups or {}
  188. def.drawer_stack_max_factor = def.drawer_stack_max_factor or 24
  189. -- events
  190. def.on_construct = drawers.drawer_on_construct
  191. def.on_destruct = drawers.drawer_on_destruct
  192. def.on_dig = drawers.drawer_on_dig
  193. def.allow_metadata_inventory_put = drawers.drawer_allow_metadata_inventory_put
  194. def.allow_metadata_inventory_take = drawers.drawer_allow_metadata_inventory_put
  195. def.on_metadata_inventory_put = drawers.add_drawer_upgrade
  196. def.on_metadata_inventory_take = drawers.remove_drawer_upgrade
  197. if minetest.get_modpath("screwdriver") and screwdriver then
  198. def.on_rotate = def.on_rotate or screwdriver.disallow
  199. end
  200. if minetest.get_modpath("pipeworks") and pipeworks then
  201. def.groups.tubedevice = 1
  202. def.groups.tubedevice_receiver = 1
  203. def.tube = def.tube or {}
  204. def.tube.insert_object = def.tube.insert_object or
  205. drawers.drawer_insert_object
  206. def.tube.can_insert = def.tube.can_insert or
  207. drawers.drawer_can_insert_object
  208. def.tube.connect_sides = {left = 1, right = 1, back = 1, top = 1,
  209. bottom = 1}
  210. def.after_place_node = pipeworks.after_place
  211. def.after_dig_node = pipeworks.after_dig
  212. end
  213. if drawers.enable_1x1 then
  214. -- normal drawer 1x1 = 1
  215. local def1 = table.copy(def)
  216. def1.description = S("@1 Drawer", def.description)
  217. def1.tiles = def.tiles or def.tiles1
  218. def1.tiles1 = nil
  219. def1.tiles2 = nil
  220. def1.tiles4 = nil
  221. def1.groups.drawer = 1
  222. core.register_node(name .. "1", def1)
  223. core.register_alias(name, name .. "1") -- 1x1 drawer is the default one
  224. end
  225. if drawers.enable_1x2 then
  226. -- 1x2 = 2
  227. local def2 = table.copy(def)
  228. def2.description = S("@1 Drawers (1x2)", def.description)
  229. def2.tiles = def.tiles2
  230. def2.tiles1 = nil
  231. def2.tiles2 = nil
  232. def2.tiles4 = nil
  233. def2.groups.drawer = 2
  234. core.register_node(name .. "2", def2)
  235. end
  236. if drawers.enable_2x2 then
  237. -- 2x2 = 4
  238. local def4 = table.copy(def)
  239. def4.description = S("@1 Drawers (2x2)", def.description)
  240. def4.tiles = def.tiles4
  241. def4.tiles1 = nil
  242. def4.tiles2 = nil
  243. def4.tiles4 = nil
  244. def4.groups.drawer = 4
  245. core.register_node(name .. "4", def4)
  246. end
  247. if (not def.no_craft) and def.material then
  248. if drawers.enable_1x1 then
  249. core.register_craft({
  250. output = name .. "1",
  251. recipe = {
  252. {def.material, def.material, def.material},
  253. { "", drawers.CHEST_ITEMSTRING, "" },
  254. {def.material, def.material, def.material}
  255. }
  256. })
  257. end
  258. if drawers.enable_1x2 then
  259. core.register_craft({
  260. output = name .. "2 2",
  261. recipe = {
  262. {def.material, drawers.CHEST_ITEMSTRING, def.material},
  263. {def.material, def.material, def.material},
  264. {def.material, drawers.CHEST_ITEMSTRING, def.material}
  265. }
  266. })
  267. end
  268. if drawers.enable_2x2 then
  269. core.register_craft({
  270. output = name .. "4 4",
  271. recipe = {
  272. {drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING},
  273. { def.material, def.material, def.material },
  274. {drawers.CHEST_ITEMSTRING, def.material, drawers.CHEST_ITEMSTRING}
  275. }
  276. })
  277. end
  278. end
  279. end
  280. function drawers.register_drawer_upgrade(name, def)
  281. def.groups = def.groups or {}
  282. def.groups.drawer_upgrade = def.groups.drawer_upgrade or 100
  283. def.inventory_image = def.inventory_image or "drawers_upgrade_template.png"
  284. def.stack_max = 1
  285. local recipe_item = def.recipe_item or "air"
  286. def.recipe_item = nil
  287. core.register_craftitem(name, def)
  288. if not def.no_craft then
  289. core.register_craft({
  290. output = name,
  291. recipe = {
  292. {recipe_item, "group:stick", recipe_item},
  293. {"group:stick", "drawers:upgrade_template", "group:stick"},
  294. {recipe_item, "group:stick", recipe_item}
  295. }
  296. })
  297. end
  298. end