shaper.lua 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. -- Facade Shaper
  2. -- This machine serves the same purpose as the circular saw from moreblocks or the milling
  3. -- maching from mymillwork. Namely, it provides a tool for creating shaped blocks that does
  4. -- not rely on using recipes.
  5. -- Balancing output per 1 input block with respect to apparent volume of output shape.
  6. -- All current shapes are added, but shapes not present in this table will still be produced
  7. -- one at a time — if that is the desired quantity, adding them is not required.
  8. local output_ratios = {
  9. bannerstone = 1,
  10. bannerstone_corner = 1,
  11. centerstone = 1,
  12. column = 1,
  13. column_corner = 1,
  14. corbel = 1,
  15. corbel_corner = 1,
  16. corbel_corner_inner = 1,
  17. carved_stone_a = 1,
  18. carved_stone_a_corner = 1,
  19. rgspro = 2,
  20. rgspro_inner_corner = 1,
  21. rgspro_outer_corner = 1,
  22. corner_bricks = 2,
  23. columnia_mid = 4,
  24. columnia_bottom = 1,
  25. columnia_top = 1,
  26. columnia_crosslink = 1,
  27. columnia_link = 4,
  28. columnia_linkdown = 4,
  29. }
  30. -- The material to be used for buttons when no material is actually loaded.
  31. -- It should be a generic material for which all the facade shapes are defined.
  32. local demo_material = "default:stone"
  33. -- Whether the facade should obey area protection for the inventories (as machines in technic mod)
  34. -- or allow anybody to use them, but disallow the removal of machine itself (like circular saw in moreblocks)
  35. local protect_inventories = false
  36. local function prepare_formspec (material_name)
  37. local output = string.gsub(material_name, "^.*:", "facade:")
  38. local shaper_formspec =
  39. "size[8,11;]"..
  40. "label[0,0;" .. "Choose shape to produce:" .. "]"..
  41. -- row 1, blocky shapes
  42. "item_image_button[0,0.5;1,1;" .. output .. "_bannerstone" .. ";bannerstone; ]"..
  43. "item_image_button[1,0.5;1,1;" .. output .. "_bannerstone_corner" .. ";bannerstone_corner; ]"..
  44. "item_image_button[2,0.5;1,1;" .. output .. "_centerstone" .. ";centerstone; ]"..
  45. "item_image_button[3,0.5;1,1;" .. output .. "_carved_stone_a" .. ";carved_stone_a; ]"..
  46. "item_image_button[4,0.5;1,1;" .. output .. "_carved_stone_a_corner" .. ";carved_stone_a_corner; ]"..
  47. "item_image_button[5,0.5;1,1;" .. output .. "_column" .. ";column; ]"..
  48. "item_image_button[6,0.5;1,1;" .. output .. "_column_corner" .. ";column_corner; ]"..
  49. -- row 2, corbel
  50. "item_image_button[0,1.5;1,1;" .. output .. "_corbel" .. ";corbel; ]"..
  51. "item_image_button[1,1.5;1,1;" .. output .. "_corbel_corner_inner" .. ";corbel_corner_inner; ]"..
  52. "item_image_button[2,1.5;1,1;" .. output .. "_corbel_corner" .. ";corbel_corner; ]"..
  53. -- row 3, cornice
  54. "item_image_button[0,2.5;1,1;" .. output .. "_rgspro" .. ";rgspro; ]"..
  55. "item_image_button[1,2.5;1,1;" .. output .. "_rgspro_inner_corner" .. ";rgspro_inner_corner; ]"..
  56. "item_image_button[2,2.5;1,1;" .. output .. "_rgspro_outer_corner" .. ";rgspro_outer_corner; ]"
  57. -- row 4, columnia
  58. if not minetest.get_modpath("columnia") then
  59. shaper_formspec = shaper_formspec ..
  60. "item_image_button[0,3.5;1,1;" .. output .. "_columnia_mid" .. ";columnia_mid; ]"..
  61. "item_image_button[1,3.5;1,1;" .. output .. "_columnia_bottom" .. ";columnia_bottom; ]"..
  62. "item_image_button[2,3.5;1,1;" .. output .. "_columnia_crosslink" .. ";columnia_crosslink; ]"..
  63. "item_image_button[3,3.5;1,1;" .. output .. "_columnia_link" .. ";columnia_link; ]"..
  64. "item_image_button[4,3.5;1,1;" .. output .. "_columnia_linkdown" .. ";columnia_linkdown; ]"
  65. -- this code is a provision in case top column pieces enter service
  66. if minetest.registered_nodes[output .. "_columnia_top"] then
  67. shaper_formspec = shaper_formspec ..
  68. "item_image_button[5,3.5;1,1;" .. output .. "_columnia_top" .. ";columnia_top; ]"
  69. end
  70. end
  71. -- row 5 for shapes which are not available for all materials
  72. -- only one such shape exists so far, but more should be easy to add here
  73. if minetest.registered_nodes[output .. "_corner_bricks"] then
  74. shaper_formspec = shaper_formspec ..
  75. "item_image_button[0,4.5;1,1;" .. output .. "_corner_bricks" .. ";corner_bricks; ]"
  76. end
  77. -- inventory part
  78. shaper_formspec = shaper_formspec ..
  79. "label[0, 5.5;".."In:".."]"..
  80. "list[current_name;src;1,5.5;1,1;]"..
  81. "label[3, 5.5;".."Out:".."]"..
  82. "list[current_name;dst;4,5.5;4,1;]"..
  83. "list[current_player;main;0,7;8,4;]"..
  84. "listring[current_name;dst]"..
  85. "listring[current_player;main]"..
  86. "listring[current_name;src]"..
  87. "listring[current_player;main]"
  88. return(shaper_formspec)
  89. end
  90. -- a simple check for compatibile materials
  91. local function check_material_applicability (material)
  92. -- using centerstone node here, since it appears to be both one of the oldest
  93. -- and defined for all materials as well, making it suitable for a quick check
  94. if minetest.registered_nodes[string.gsub(material, "^.*:", "facade:") .. "_centerstone"] then
  95. return true
  96. else
  97. return false
  98. end
  99. end
  100. -- update the buttons to show shapes made from the actual material
  101. local function update_formspec_put (pos, listname, index, stack, player)
  102. if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
  103. return
  104. end
  105. if listname ~= "src" then
  106. return
  107. end
  108. local meta = minetest.get_meta(pos)
  109. local material_name = stack:get_name()
  110. if check_material_applicability(material_name) then
  111. meta:set_string("formspec", prepare_formspec(material_name))
  112. else
  113. return
  114. end
  115. end
  116. -- update the buttons to show shapes made from demo material if all material is removed
  117. local function update_formspec_take (pos, listname, index, stack, player)
  118. if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
  119. return
  120. end
  121. if listname ~= "src" then
  122. return
  123. end
  124. local meta = minetest.get_meta(pos)
  125. local inv = meta:get_inventory()
  126. if inv:is_empty("src") then
  127. meta:set_string("formspec", prepare_formspec(demo_material))
  128. end
  129. return
  130. end
  131. -- disallow putting in materials which are not supported
  132. local function check_inventory_put (pos, listname, index, stack, player)
  133. if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
  134. return 0
  135. end
  136. if listname ~= "src" then
  137. return 0
  138. end
  139. local material_name = stack:get_name()
  140. if check_material_applicability(material_name) then
  141. return(stack:get_count())
  142. else
  143. return 0
  144. end
  145. end
  146. local function check_inventory_take (pos, listname, index, stack, player)
  147. if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
  148. return 0
  149. end
  150. if listname ~= "src" and listname ~= "dst" then
  151. return 0
  152. end
  153. return(stack:get_count())
  154. end
  155. local function check_inventory_move (pos, from_list, from_index, to_list, to_index, count, player)
  156. if protect_inventories and minetest.is_protected(pos, player:get_player_name()) then
  157. return 0
  158. end
  159. return(stack:get_count())
  160. end
  161. -- process the form fields and convert source material to desired shapes
  162. local function form_handler(pos, formname, fields, sender)
  163. if protect_inventories and minetest.is_protected(pos, sender:get_player_name()) then
  164. return
  165. end
  166. if fields.quit then
  167. return
  168. end
  169. local meta = minetest.get_meta(pos)
  170. local inv = meta:get_inventory()
  171. if inv:is_empty("src") then
  172. return
  173. end
  174. local inputstack = inv:get_stack("src", 1)
  175. local inputname = inputstack:get_name()
  176. for shape,_ in pairs(fields) do
  177. local result = string.gsub(inputname, "^.*:", "facade:") .. "_" .. shape
  178. -- one can never be overly paranoid, unlike the quick check before, this one is precise
  179. if not minetest.registered_nodes[result] then
  180. return
  181. end
  182. -- output quantities are adjusted to preserve roughly same mass of resulting products
  183. if output_ratios[shape] then
  184. result = result .. " " .. output_ratios[shape]
  185. end
  186. if not inv:room_for_item("dst", result) then
  187. return
  188. end
  189. inputstack:take_item(1)
  190. inv:set_stack("src", 1, inputstack)
  191. inv:add_item("dst", result)
  192. end
  193. return
  194. end
  195. local function check_removability (pos, player)
  196. local meta = minetest.get_meta(pos)
  197. local owner = meta:set_string("owner")
  198. local pname = player:get_player_name()
  199. local inv = meta:get_inventory()
  200. -- owner may always remove the device
  201. if owner and owner ~= "" and pname and pname ~= "" and owner == pname then
  202. if inv:is_empty("src") and inv:is_empty("dst") then
  203. return true
  204. else
  205. return false
  206. end
  207. end
  208. if minetest.is_protected(pos, player:get_player_name()) then
  209. return false
  210. end
  211. if inv:is_empty("src") and inv:is_empty("dst") then
  212. return true
  213. end
  214. return false
  215. end
  216. minetest.register_node("facade:shaper", {
  217. description = "Shaper Machine",
  218. drawtype = "nodebox",
  219. node_box = {
  220. type = "fixed",
  221. fixed = {
  222. -- base
  223. {-1/2, -1/2, -1/2, 1/2, -14/32, 1/2},
  224. -- back
  225. {-8/32, -1/2, 12/32, 8/32, 1/2, 16/32},
  226. -- table
  227. {-8/32, -4/32, -16/32, 8/32, 4/32, 16/32},
  228. -- rear table sliding support
  229. {-16/32, -4/32, 12/32, 16/32, 4/32, 16/32},
  230. -- front table sliding support
  231. {-8/32, -14/32, -12/32, 8/32, -4/32, -16/32},
  232. -- top tool beam
  233. {-4/32, 16/32, -8/32, 4/32, 12/32, 12/32},
  234. -- cutter holder
  235. {-2/32, 7/32, -2/32, 2/32, 14/32, 2/32},
  236. -- cutter
  237. {-1/128, 6/32, -1/32, 1/128, 7/32, 1/32},
  238. },
  239. },
  240. selection_box = {
  241. type = "fixed",
  242. fixed = {
  243. {-1/2, -1/2, -1/2, 1/2, 1/2, 1/2},
  244. },
  245. },
  246. tiles = { "facade_shaper_top.png",
  247. "facade_shaper_bottom.png",
  248. "facade_shaper_right.png",
  249. "facade_shaper_left.png",
  250. "facade_shaper_back.png",
  251. "facade_shaper_front.png"},
  252. groups = { oddly_breakable_by_hand=2, cracky=3, dig_immediate=1 },
  253. paramtype = "light",
  254. paramtype2 = "facedir",
  255. legacy_facedir_simple = true,
  256. on_construct = function(pos)
  257. local meta = minetest.get_meta(pos)
  258. meta:set_string("formspec", prepare_formspec(demo_material))
  259. local inv = meta:get_inventory()
  260. inv:set_size("src", 1)
  261. inv:set_size("dst", 4)
  262. end,
  263. after_place_node = function(pos, placer)
  264. local meta = minetest.get_meta(pos)
  265. local owner = placer and placer:get_player_name() or ""
  266. meta:set_string("owner", owner)
  267. if owner then
  268. meta:set_string("infotext", ("Facade Shaper (owned by %s)"):format(owner))
  269. else
  270. meta:set_string("infotext", "Facade Shaper")
  271. end
  272. end,
  273. can_dig = check_removability,
  274. allow_metadata_inventory_put = check_inventory_put,
  275. allow_metadata_inventory_take = check_inventory_take,
  276. allow_metadata_inventory_move = check_inventory_move,
  277. on_metadata_inventory_put = update_formspec_put,
  278. on_metadata_inventory_take = update_formspec_take,
  279. on_receive_fields = form_handler,
  280. })
  281. minetest.register_craft({
  282. output = 'facade:shaper',
  283. recipe = {
  284. {'', 'default:diamond', '' },
  285. {'default:steel_ingot', 'default:steelblock', 'default:steel_ingot' },
  286. {'', 'default:steelblock' , '' },
  287. },
  288. })