init.lua 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. ---------------------------------------------------------------------------------------
  2. -- simple anvil that can be used to repair tools
  3. ---------------------------------------------------------------------------------------
  4. -- * can be used to repair tools
  5. -- * the hammer gets dammaged a bit at each repair step
  6. ---------------------------------------------------------------------------------------
  7. anvil = anvil or {}
  8. anvil.modpath = minetest.get_modpath("anvil")
  9. -- Localize for performance.
  10. local math_floor = math.floor
  11. local math_random = math.random
  12. anvil.tmp = anvil.tmp or {}
  13. -- Item entity's displacement above the anvil.
  14. local item_displacement = 7/16
  15. local remove_item = function(pos, node)
  16. local objs = minetest.env:get_objects_inside_radius({x = pos.x, y = pos.y + item_displacement, z = pos.z}, .5)
  17. if objs then
  18. for _, obj in ipairs(objs) do
  19. if obj and obj:get_luaentity() and obj:get_luaentity().name == "anvil:item" then
  20. obj:remove()
  21. end
  22. end
  23. end
  24. end
  25. local update_item = function(pos, node)
  26. local meta = minetest.env:get_meta(pos)
  27. local inv = meta:get_inventory()
  28. if not inv:is_empty("input") then
  29. pos.y = pos.y + item_displacement
  30. anvil.tmp.nodename = node.name
  31. anvil.tmp.texture = inv:get_stack("input", 1):get_name()
  32. local e = minetest.env:add_entity(pos,"anvil:item")
  33. local yaw = math.pi*2 - node.param2 * math.pi/2
  34. e:setyaw(yaw)
  35. end
  36. end
  37. local update_item_if_needed = function(pos, node)
  38. local test_pos = {x=pos.x, y=pos.y + item_displacement, z=pos.z}
  39. if #minetest.get_objects_inside_radius(test_pos, 0.5) > 0 then
  40. return
  41. end
  42. update_item(pos, node)
  43. end
  44. function anvil.on_activate(self, staticdata)
  45. if anvil.tmp.nodename ~= nil and anvil.tmp.texture ~= nil then
  46. self.nodename = anvil.tmp.nodename
  47. anvil.tmp.nodename = nil
  48. self.texture = anvil.tmp.texture
  49. anvil.tmp.texture = nil
  50. else
  51. if staticdata ~= nil and staticdata ~= "" then
  52. local data = staticdata:split(';')
  53. if data and data[1] and data[2] then
  54. self.nodename = data[1]
  55. self.texture = data[2]
  56. end
  57. end
  58. end
  59. if self.texture ~= nil then
  60. self.object:set_properties({textures={self.texture}})
  61. end
  62. end
  63. function anvil.get_staticdata(self)
  64. if self.nodename ~= nil and self.texture ~= nil then
  65. return self.nodename .. ';' .. self.texture
  66. end
  67. return ""
  68. end
  69. function anvil.on_construct(pos)
  70. local meta = minetest.get_meta(pos)
  71. local inv = meta:get_inventory()
  72. inv:set_size("input", 1)
  73. end
  74. function anvil.on_destruct(pos)
  75. local meta = minetest.get_meta(pos)
  76. local inv = meta:get_inventory()
  77. local item = inv:get_stack("input", 1)
  78. if item:get_count() == 1 then
  79. minetest.add_item(pos, item)
  80. inv:set_stack("input", 1, ItemStack(""))
  81. end
  82. remove_item(pos, minetest.get_node(pos))
  83. end
  84. function anvil.on_finish_collapse(pos, node)
  85. local meta = minetest.get_meta(pos)
  86. local inv = meta:get_inventory()
  87. inv:set_stack("input", 1, ItemStack(""))
  88. end
  89. function anvil.after_place_node(pos, placer)
  90. local meta = minetest.get_meta(pos)
  91. meta:set_string("owner", placer:get_player_name() or "")
  92. meta:set_string("infotext", "Blacksmithing Anvil")
  93. end
  94. function anvil.can_dig(pos, player)
  95. local meta = minetest.get_meta(pos)
  96. local inv = meta:get_inventory()
  97. if not inv:is_empty("input") then
  98. return false
  99. end
  100. return true
  101. end
  102. function anvil.allow_metadata_inventory_put(pos, listname, index, stack, player)
  103. if not player or not player:is_player() then
  104. return 0
  105. end
  106. if minetest.test_protection(pos, player:get_player_name()) then
  107. return 0
  108. end
  109. local meta = minetest.get_meta(pos)
  110. if listname~="input" then
  111. return 0
  112. end
  113. if (listname=='input'
  114. and (stack:get_wear() == 0
  115. or minetest.get_item_group(stack:get_name(), "not_repaired_by_anvil") ~= 0
  116. or stack:get_name() == "cans:water_can"
  117. or stack:get_name() == "cans:lava_can" )) then
  118. -- Report error if tool is not the wieldhand.
  119. if stack:get_name() ~= "" then
  120. local pname = player:get_player_name()
  121. minetest.chat_send_player(pname, '# Server: This anvil is for damaged tools only.')
  122. end
  123. return 0
  124. end
  125. if meta:get_inventory():room_for_item("input", stack) then
  126. return stack:get_count()
  127. end
  128. return 0
  129. end
  130. function anvil.allow_metadata_inventory_move()
  131. return 0
  132. end
  133. function anvil.allow_metadata_inventory_take(pos, listname, index, stack, player)
  134. if not player or not player:is_player() then
  135. return 0
  136. end
  137. if minetest.test_protection(pos, player:get_player_name()) then
  138. return 0
  139. end
  140. if listname~="input" then
  141. return 0
  142. end
  143. return stack:get_count()
  144. end
  145. function anvil.on_rightclick(pos, node, clicker, itemstack)
  146. if not clicker or not clicker:is_player() then
  147. return
  148. end
  149. if minetest.test_protection(pos, clicker:get_player_name()) then
  150. return itemstack
  151. end
  152. -- If player is wielding nothing.
  153. if itemstack:get_count() == 0 then
  154. local meta = minetest.env:get_meta(pos)
  155. local inv = meta:get_inventory()
  156. if not inv:is_empty("input") then
  157. local return_stack = inv:get_stack("input", 1)
  158. inv:set_stack("input", 1, nil)
  159. --clicker:get_inventory():add_item("main", return_stack)
  160. remove_item(pos, node)
  161. return return_stack
  162. --return itemstack
  163. end
  164. end
  165. local this_def = minetest.reg_ns_nodes[node.name]
  166. if this_def.allow_metadata_inventory_put(pos, "input", 1, itemstack:peek_item(), clicker) > 0 then
  167. local s = itemstack:take_item()
  168. local meta = minetest.env:get_meta(pos)
  169. local inv = meta:get_inventory()
  170. inv:add_item("input", s)
  171. update_item(pos,node)
  172. end
  173. return itemstack
  174. end
  175. function anvil.on_punch(pos, node, puncher)
  176. if( not( pos ) or not( node ) or not( puncher )) then
  177. return
  178. end
  179. if minetest.test_protection(pos, puncher:get_player_name()) then
  180. return
  181. end
  182. update_item_if_needed(pos, node)
  183. local wielded = puncher:get_wielded_item()
  184. local meta = minetest.get_meta(pos)
  185. local inv = meta:get_inventory()
  186. if wielded:get_count() == 0 then
  187. if not inv:is_empty("input") then
  188. local return_stack = inv:get_stack("input", 1)
  189. inv:set_stack("input", 1, nil)
  190. puncher:get_inventory():add_item("main", return_stack)
  191. remove_item(pos, node)
  192. end
  193. end
  194. -- Only punching with the hammer is supposed to work.
  195. local wieldname = wielded:get_name()
  196. if wieldname ~= 'anvil:hammer' and wieldname ~= "xdecor:hammer" then
  197. return
  198. end
  199. local hammerwear = 300
  200. -- The xdecor hammer wears out faster (it is cheaper to craft).
  201. if wieldname == "xdecor:hammer" then
  202. hammerwear = 1000
  203. end
  204. local input = inv:get_stack('input',1)
  205. -- Only tools can be repaired.
  206. if( not( input )
  207. or input:is_empty()
  208. or input:get_name() == "cans:water_can"
  209. or input:get_name() == "cans:lava_can" ) then
  210. return
  211. end
  212. -- 65535 is max damage.
  213. local damage_state = 40-math_floor(input:get_wear()/1638)
  214. local tool_name = input:get_name()
  215. local hud2 = nil
  216. local hud3 = nil
  217. if( input:get_wear()>0 ) then
  218. hud2 = puncher:hud_add({
  219. hud_elem_type = "statbar",
  220. text = "default_cloud.png^[colorize:#ff0000:256",
  221. number = 40,
  222. direction = 0, -- left to right
  223. position = {x=0.5, y=0.65},
  224. alignment = {x = 0, y = 0},
  225. offset = {x = -320, y = 0},
  226. size = {x=32, y=32},
  227. })
  228. hud3 = puncher:hud_add({
  229. hud_elem_type = "statbar",
  230. text = "default_cloud.png^[colorize:#00ff00:256",
  231. number = damage_state,
  232. direction = 0, -- left to right
  233. position = {x=0.5, y=0.65},
  234. alignment = {x = 0, y = 0},
  235. offset = {x = -320, y = 0},
  236. size = {x=32, y=32},
  237. })
  238. end
  239. minetest.after(2, function()
  240. if( puncher ) then
  241. puncher:hud_remove(hud2)
  242. puncher:hud_remove(hud3)
  243. end
  244. end)
  245. -- Tell the player when the job is done.
  246. if (input:get_wear() == 0) then
  247. local tool_desc
  248. if minetest.registered_items[tool_name] and minetest.registered_items[tool_name].description then
  249. tool_desc = utility.get_short_desc(minetest.registered_items[tool_name].description)
  250. else
  251. tool_desc = tool_name
  252. end
  253. local pname = puncher:get_player_name()
  254. minetest.chat_send_player(pname, '# Server: Your `' .. tool_desc .. '` has been repaired successfully.')
  255. return
  256. else
  257. pos.y = pos.y + item_displacement
  258. ambiance.sound_play("anvil_clang", pos, 1.0, 30)
  259. minetest.add_particlespawner({
  260. amount = math_random(3, 10),
  261. time = 0.1,
  262. minpos = pos,
  263. maxpos = pos,
  264. minvel = {x=2, y=3, z=2},
  265. maxvel = {x=-2, y=1, z=-2},
  266. minacc = {x=0, y= -10, z=0},
  267. maxacc = {x=0, y= -10, z=0},
  268. minexptime = 0.5,
  269. maxexptime = 1,
  270. minsize = 1,
  271. maxsize = 1,
  272. collisiondetection = true,
  273. vertical = false,
  274. texture = "anvil_spark.png",
  275. })
  276. end
  277. -- Do the actual repair.
  278. input:add_wear( -1500 )
  279. inv:set_stack("input", 1, input)
  280. -- Damage the hammer slightly.
  281. wielded:add_wear(hammerwear)
  282. if wielded:is_empty() then
  283. ambiance.sound_play("default_tool_breaks", pos, 1.0, 10)
  284. end
  285. puncher:set_wielded_item( wielded )
  286. end
  287. if not anvil.registered then
  288. minetest.register_alias("castle:anvil", "anvil:anvil")
  289. -- The hammer for the anvil.
  290. minetest.register_tool("anvil:hammer", {
  291. description = "Steel Blacksmithing Hammer",
  292. groups = {not_repaired_by_anvil = 1},
  293. sound = {breaks = "default_tool_breaks"},
  294. image = "anvil_tool_steelhammer.png",
  295. inventory_image = "anvil_tool_steelhammer.png",
  296. tool_capabilities = tooldata["hammer_hammer"],
  297. })
  298. -- The anvil itself.
  299. minetest.register_node("anvil:anvil", {
  300. drawtype = "nodebox",
  301. description = "Anvil",
  302. tiles = {"chains_iron.png", "default_stone.png"},
  303. paramtype = "light",
  304. paramtype2 = "facedir",
  305. groups = utility.dig_groups("machine", {falling_node=1}),
  306. sounds = default.node_sound_metal_defaults(),
  307. is_ground_content = false,
  308. -- The nodebox model comes from realtest.
  309. -- It has been modified to fit this game.
  310. node_box = {
  311. type = "fixed",
  312. fixed = {
  313. -- Base
  314. {-0.5,-0.5,-0.3,0.5,-0.4,0.3},
  315. -- Column
  316. {-0.35,-0.4,-0.25,0.35,-0.3,0.25},
  317. {-0.3,-0.3,-0.15,0.3,-0.1,0.15},
  318. -- Top
  319. {-0.5,-0.1,-0.2,0.5,0.1,0.2},
  320. },
  321. },
  322. selection_box = {
  323. type = "fixed",
  324. fixed = {
  325. -- Base
  326. {-0.5,-0.5,-0.3,0.5,-0.4,0.3},
  327. -- Column
  328. {-0.35,-0.4,-0.25,0.35,-0.3,0.25},
  329. {-0.3,-0.3,-0.15,0.3,-0.1,0.15},
  330. -- Top
  331. {-0.5,-0.1,-0.2,0.5,0.1,0.2},
  332. }
  333. },
  334. on_construct = function(...)
  335. return anvil.on_construct(...)
  336. end,
  337. on_destruct = function(...)
  338. return anvil.on_destruct(...)
  339. end,
  340. on_finish_collapse = function(...)
  341. return anvil.on_finish_collapse(...)
  342. end,
  343. after_place_node = function(...)
  344. return anvil.after_place_node(...)
  345. end,
  346. can_dig = function(...)
  347. return anvil.can_dig(...)
  348. end,
  349. allow_metadata_inventory_put = function(...)
  350. return anvil.allow_metadata_inventory_put(...)
  351. end,
  352. allow_metadata_inventory_take = function(...)
  353. return anvil.allow_metadata_inventory_take(...)
  354. end,
  355. allow_metadata_inventory_move = function(...)
  356. return anvil.allow_metadata_inventory_move(...)
  357. end,
  358. on_rightclick = function(...)
  359. return anvil.on_rightclick(...)
  360. end,
  361. on_punch = function(...)
  362. return anvil.on_punch(...)
  363. end,
  364. })
  365. minetest.register_entity("anvil:item", {
  366. hp_max = 1,
  367. visual="wielditem",
  368. visual_size={x=.33,y=.33},
  369. collisionbox = {0,0,0,0,0,0},
  370. physical=false,
  371. textures={"air"},
  372. on_activate = function(...)
  373. return anvil.on_activate(...)
  374. end,
  375. get_staticdata = function(...)
  376. return anvil.get_staticdata(...)
  377. end,
  378. })
  379. minetest.register_craft({
  380. output = "anvil:anvil",
  381. recipe = {
  382. {"carbon_steel:ingot","carbon_steel:ingot","carbon_steel:ingot"},
  383. {'', "cast_iron:ingot",'' },
  384. {"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
  385. },
  386. })
  387. minetest.register_craft({
  388. output = "anvil:hammer",
  389. recipe = {
  390. {"carbon_steel:ingot","group:stick","carbon_steel:ingot"},
  391. {"carbon_steel:ingot","group:stick","carbon_steel:ingot"},
  392. {'', "group:stick", '' },
  393. },
  394. })
  395. local c = "anvil:core"
  396. local f = anvil.modpath .. "/init.lua"
  397. reload.register_file(c, f, false)
  398. anvil.registered = true
  399. end