init.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. if not minetest.global_exists("engraver") then engraver = {} end
  2. engraver.modpath = minetest.get_modpath("engraver")
  3. local MAX_SIGN_LENGTH = 256
  4. -- API function to allow caller to check if an item has a custom description.
  5. function engraver.item_has_custom_description(item)
  6. if item:get_count() ~= 1 then
  7. return false
  8. end
  9. local meta = item:get_meta()
  10. local en_desc = meta:get_string("en_desc") or ""
  11. local ar_desc = meta:get_string("ar_desc") or ""
  12. return en_desc ~= "" or ar_desc ~= ""
  13. end
  14. local function player_wields_tools(user)
  15. local chisel_index = user:get_wield_index()
  16. local hammer_index = chisel_index + 1
  17. local inv = user:get_inventory()
  18. local chisel_stack = inv:get_stack("main", chisel_index)
  19. local chisel_name = chisel_stack:get_name()
  20. local hammer_stack = inv:get_stack("main", hammer_index)
  21. local hammer_name = hammer_stack:get_name()
  22. if chisel_name ~= "engraver:chisel" then
  23. return false
  24. end
  25. if hammer_name ~= "xdecor:hammer" and hammer_name ~= "anvil:hammer" then
  26. return false
  27. end
  28. return true
  29. end
  30. local function node_can_be_chiseled(pos)
  31. local node = minetest.get_node(pos)
  32. local ndef = minetest.registered_nodes[node.name]
  33. if not ndef then
  34. return false
  35. end
  36. -- Check node drawtype (must be full node).
  37. local dt = ndef.drawtype
  38. if dt ~= "normal" and dt ~= "glasslike" and dt ~= "glasslike_framed" and dt ~= "glasslike_framed_optional" and dt ~= "allfaces" and dt ~= "allfaces_optional" then
  39. return false
  40. end
  41. -- Check node groups (must be stone, brick or block).
  42. local groups = ndef.groups or {}
  43. if (groups.stone and groups.stone > 0) or (groups.brick and groups.brick > 0) or (groups.block and groups.block > 0) then
  44. -- Do nothing.
  45. else
  46. return false
  47. end
  48. -- Check meta (cannot have infotext or formspec, or must have been previously chiseled).
  49. local meta = minetest.get_meta(pos)
  50. local data = meta:to_table() or {fields={}, inventory={}}
  51. -- Any inventory fields means this node can't be engraved.
  52. for k, v in pairs(data.inventory) do
  53. return false
  54. end
  55. local was_engraved = false
  56. local was_polished = false
  57. local has_other_fields = false
  58. local has_infotext = false
  59. for k, v in pairs(data.fields) do
  60. if k == "engraver_chiseled" then
  61. was_engraved = true
  62. elseif k == "infotext" then
  63. has_infotext = true
  64. elseif k == "chiseled_text" or k == "chiseled_date" then
  65. -- Nothing to be done. Ignore these fields.
  66. elseif k == "chiseled_polished" then
  67. was_polished = true
  68. else
  69. has_other_fields = true
  70. end
  71. end
  72. if has_infotext and not was_engraved then
  73. return false
  74. end
  75. if has_other_fields or was_polished then
  76. return false
  77. end
  78. return true
  79. end
  80. local function show_chisel_formspec(pos, user)
  81. local pname = user:get_player_name()
  82. local node = minetest.get_node(pos)
  83. local text = minetest.get_meta(pos):get_string("chiseled_text")
  84. local formspec = "size[5,2.3]" ..
  85. default.gui_bg ..
  86. default.gui_bg_img ..
  87. default.gui_slots ..
  88. "item_image[1,1;1,1;" .. minetest.formspec_escape(node.name) .. "]" ..
  89. "field[0.3,0.3;5,1;text;;" .. minetest.formspec_escape(text) .. "]" ..
  90. "button_exit[2,1;2,1;proceed;Chisel Text]" ..
  91. "label[0,2;`%n' inserts a new line.]"
  92. local formname = "engraver:chisel_" .. minetest.pos_to_string(pos)
  93. minetest.show_formspec(pname, formname, formspec)
  94. end
  95. -- Must be a tool for the wear bar to work.
  96. minetest.register_tool("engraver:chisel", {
  97. description = "Chisel",
  98. groups = {not_repaired_by_anvil = 1},
  99. inventory_image = "engraver_chisel.png",
  100. wield_image = "engraver_chisel.png",
  101. on_use = function(itemstack, user, pt)
  102. if not user or not user:is_player() then
  103. return
  104. end
  105. if pt.type ~= "node" then
  106. return
  107. end
  108. if not player_wields_tools(user) then
  109. return
  110. end
  111. if not node_can_be_chiseled(pt.under) then
  112. return
  113. end
  114. ambiance.sound_play("anvil_clang", pt.under, 1.0, 30)
  115. show_chisel_formspec(pt.under, user)
  116. end,
  117. })
  118. local function handle_engraver_use(player, formname, fields)
  119. if not string.find(formname, "^engraver:chisel_") then
  120. return
  121. end
  122. if not player or not player:is_player() then
  123. return true
  124. end
  125. local pname = player:get_player_name()
  126. local pos = minetest.string_to_pos(string.sub(formname, string.len("engraver:chisel_") + 1))
  127. if not pos then
  128. return true
  129. end
  130. if not player_wields_tools(player) then
  131. return true
  132. end
  133. if not node_can_be_chiseled(pos) then
  134. return true
  135. end
  136. if not fields.text or type(fields.text) ~= "string" then
  137. return true
  138. end
  139. -- Max sign length.
  140. local the_text = fields.text:sub(1, MAX_SIGN_LENGTH)
  141. local message = utility.trim_remove_special_chars(the_text)
  142. if anticurse.check(pname, message, "foul") then
  143. anticurse.log(pname, message)
  144. minetest.chat_send_player(pname, "# Server: Don't use a chisel for naughty talk!")
  145. return true
  146. elseif anticurse.check(pname, message, "curse") then
  147. anticurse.log(pname, message)
  148. minetest.chat_send_player(pname, "# Server: Please do not curse with a chisel.")
  149. return true
  150. end
  151. -- Add wear to the chisel.
  152. local got_chisel = false
  153. local inv = player:get_inventory()
  154. local index = player:get_wield_index()
  155. local chisel = inv:get_stack("main", index)
  156. if chisel:get_name() == "engraver:chisel" then
  157. chisel:add_wear(300)
  158. inv:set_stack("main", index, chisel)
  159. if chisel:is_empty() == 0 then
  160. ambiance.sound_play("default_tool_breaks", pos, 1.0, 10)
  161. end
  162. got_chisel = true
  163. end
  164. if got_chisel then
  165. local meta = minetest.get_meta(pos)
  166. meta:set_string("chiseled_text", message)
  167. meta:set_string("chiseled_date", os.time())
  168. meta:set_int("engraver_chiseled", 1)
  169. meta:mark_as_private({"chiseled_text", "chiseled_date", "engraver_chiseled"})
  170. -- Translate escape sequences.
  171. message = string.gsub(message, "%%[nN]", "\n")
  172. if message ~= "" then
  173. meta:set_string("infotext", message)
  174. else
  175. meta:set_string("infotext", "")
  176. meta:set_int("engraver_chiseled", 0)
  177. end
  178. minetest.chat_send_player(pname, "# Server: Text chiseled successfully.")
  179. ambiance.sound_play("anvil_clang", pos, 1.0, 30)
  180. end
  181. return true
  182. end
  183. minetest.register_on_player_receive_fields(handle_engraver_use)
  184. minetest.register_craft({
  185. output = "engraver:chisel",
  186. recipe = {
  187. {"carbon_steel:ingot"},
  188. {"darkage:iron_stick"},
  189. },
  190. })
  191. -- Code by 'octacian'
  192. --
  193. -- Formspec
  194. --
  195. local function get_workbench_formspec(pos, error)
  196. local msg = "Rename Item"
  197. local text = minetest.get_meta(pos):get_string("text")
  198. if error then
  199. msg = minetest.colorize("red", error)
  200. end
  201. return
  202. "size[8,7]" ..
  203. default.gui_bg ..
  204. default.gui_bg_img ..
  205. default.gui_slots ..
  206. "field[0.5,0.5;6.2,1;text;"..msg..";"..minetest.formspec_escape(text).."]" ..
  207. "button[6.5,0.2;1.5,1;rename;Rename]" ..
  208. "list[context;input;1.5,1.4;1,1;]" ..
  209. "image[2.5,1.4;1,1;gui_workbench_plus.png]" ..
  210. "image[3.5,1.4;1,1;default_nametag_slot.png]" ..
  211. "list[context;nametag;3.5,1.4;1,1;]" ..
  212. "image[4.5,1.4;1,1;gui_furnace_arrow_bg.png^[transformR270]" ..
  213. "list[context;output;5.5,1.4;1,1]" ..
  214. "list[current_player;main;0,2.85;8,1;]" ..
  215. "list[current_player;main;0,4.08;8,3;8]" ..
  216. "field_close_on_enter[text;false]" ..
  217. default.get_hotbar_bg(0,2.85)
  218. end
  219. local function get_item_desc(stack)
  220. if not stack:is_known() then
  221. return
  222. end
  223. local desc = stack:get_meta():get_string("description")
  224. if desc == "" then
  225. desc = minetest.registered_items[stack:get_name()].description or ""
  226. end
  227. desc = utility.get_short_desc(desc)
  228. return desc
  229. end
  230. local function workbench_update_text(pos, stack)
  231. local meta = minetest.get_meta(pos)
  232. meta:set_string("text", get_item_desc(stack))
  233. meta:set_string("formspec", get_workbench_formspec(pos))
  234. end
  235. local function workbench_update_help(pos, type, string)
  236. local meta = minetest.get_meta(pos)
  237. meta:set_string("formspec", get_workbench_formspec(pos, string))
  238. meta:set_string("error", type)
  239. end
  240. --
  241. -- Node definition
  242. --
  243. minetest.register_node(":engraver:bench", {
  244. description = "Engraving Bench",
  245. tiles = {"default_workbench_top.png", "default_wood.png", "default_workbench_sides.png",
  246. "default_workbench_sides.png", "default_workbench_sides.png", "default_workbench_sides.png"},
  247. groups = utility.dig_groups("furniture", {flammable = 3}),
  248. sounds = default.node_sound_wood_defaults(),
  249. drawtype = "nodebox",
  250. paramtype = "light",
  251. node_box = {
  252. type = "fixed",
  253. fixed = {
  254. {-0.5, 3/16, -0.5, 0.5, 0.5, 0.5},
  255. {-7/16, -0.5, 1/4, -1/4, 0.5, 7/16},
  256. {-7/16, -0.5, -7/16, -1/4, 0.5, -1/4},
  257. {1/4, -0.5, 1/4, 7/16, 0.5, 7/16},
  258. {1/4, -0.5, -7/16, 7/16, 0.5, -1/4},
  259. }
  260. },
  261. on_construct = function(pos)
  262. local meta = minetest.get_meta(pos)
  263. meta:set_string("formspec", get_workbench_formspec(pos))
  264. local inv = meta:get_inventory()
  265. inv:set_size("input", 1)
  266. inv:set_size("nametag", 1)
  267. inv:set_size("output", 1)
  268. end,
  269. can_dig = function(pos, player)
  270. local inv = minetest.get_meta(pos):get_inventory()
  271. if inv:is_empty("input") and inv:is_empty("nametag") and
  272. inv:is_empty("output") then
  273. return true
  274. else
  275. return false
  276. end
  277. end,
  278. on_blast = function(pos)
  279. local inv = minetest.get_meta(pos):get_inventory()
  280. local drops = {
  281. inv:get_list("input")[1],
  282. inv:get_list("nametag")[1],
  283. inv:get_list("output")[1],
  284. "engraver:bench",
  285. }
  286. minetest.remove_node(pos)
  287. return drops
  288. end,
  289. allow_metadata_inventory_put = function(pos, listname, index, stack, player)
  290. local pname = player:get_player_name()
  291. if minetest.test_protection(pos, pname) then
  292. return 0
  293. end
  294. if not stack:is_known() then
  295. return 0
  296. end
  297. if listname == "nametag" then
  298. if stack:get_name() ~= "engraver:plate" then
  299. return 0
  300. else
  301. return stack:get_count()
  302. end
  303. elseif listname == "output" then
  304. return 0
  305. elseif listname == "input" then
  306. if minetest.get_item_group(stack:get_name(), "not_renamable") > 0 then
  307. return 0
  308. end
  309. if stack:get_stack_max() > 1 then
  310. return 0
  311. end
  312. return stack:get_count()
  313. end
  314. return 0
  315. end,
  316. allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
  317. return 0
  318. end,
  319. allow_metadata_inventory_take = function(pos, listname, index, stack, player)
  320. local pname = player:get_player_name()
  321. if minetest.test_protection(pos, pname) then
  322. return 0
  323. end
  324. return stack:get_count()
  325. end,
  326. on_metadata_inventory_put = function(pos, listname, index, stack)
  327. local meta = minetest.get_meta(pos)
  328. local inv = meta:get_inventory()
  329. local error = meta:get_string("error")
  330. if error == "input" and not inv:is_empty("input") then
  331. meta:set_string("formspec", get_workbench_formspec(pos))
  332. elseif error == "nametag" and not inv:is_empty("nametag") then
  333. meta:set_string("formspec", get_workbench_formspec(pos))
  334. end
  335. if listname == "input" then
  336. workbench_update_text(pos, stack)
  337. end
  338. end,
  339. on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index)
  340. -- Moving is not allowed.
  341. end,
  342. on_metadata_inventory_take = function(pos, listname)
  343. local meta = minetest.get_meta(pos)
  344. local inv = meta:get_inventory()
  345. local error = meta:get_string("error")
  346. if error == "output" and inv:is_empty("output") then
  347. meta:set_string("formspec", get_workbench_formspec(pos))
  348. end
  349. if listname == "input" then
  350. meta:set_string("text", "")
  351. meta:set_string("formspec", get_workbench_formspec(pos))
  352. end
  353. end,
  354. on_receive_fields = function(pos, formname, fields, sender)
  355. local meta = minetest.get_meta(pos)
  356. local inv = meta:get_inventory()
  357. local pname = sender:get_player_name()
  358. if fields.rename or fields.key_enter_field == "text" then
  359. meta:set_string("text", fields.text)
  360. if inv:is_empty("input") then
  361. workbench_update_help(pos, "input", "Missing input item!")
  362. elseif inv:is_empty("nametag") then
  363. workbench_update_help(pos, "nametag", "Missing nameplate!")
  364. elseif not inv:is_empty("output") then
  365. workbench_update_help(pos, "output", "No room in output!")
  366. else
  367. local new_stack = inv:get_stack("input", 1)
  368. if not new_stack:is_known() then
  369. workbench_update_help(pos, nil, "Cannot rename unknown item!")
  370. return
  371. end
  372. local item = minetest.registered_items[new_stack:get_name()]
  373. local renameable = item.groups.renameable ~= 0
  374. if not renameable then
  375. workbench_update_help(pos, nil, "Item cannot be renamed!")
  376. return
  377. elseif new_stack:get_stack_max() > 1 then
  378. workbench_update_help(pos, nil, "Item cannot be renamed!")
  379. return
  380. elseif fields.text == "" then
  381. workbench_update_help(pos, nil, "Description cannot be blank!")
  382. return
  383. elseif anticurse.check(pname, fields.text, "foul") then
  384. workbench_update_help(pos, nil, "No foul language!")
  385. return
  386. elseif anticurse.check(pname, fields.text, "curse") then
  387. workbench_update_help(pos, nil, "No cursing!")
  388. return
  389. elseif fields.text:len() > 256 then
  390. workbench_update_help(pos, nil, "Description too long (max 256 characters)!")
  391. return
  392. elseif fields.text == get_item_desc(inv:get_stack("input", 1)) then
  393. workbench_update_help(pos, nil, "Description not changed!")
  394. end
  395. local itemmeta = new_stack:get_meta()
  396. itemmeta:set_string("en_desc", fields.text)
  397. toolranks.apply_description(itemmeta, new_stack:get_definition())
  398. minetest.log("action", pname .. " renames "
  399. ..inv:get_stack("input", 1):get_name().." to "..fields.text)
  400. inv:remove_item("input", inv:get_stack("input", 1))
  401. inv:remove_item("nametag", inv:get_stack("nametag", 1):take_item(1))
  402. inv:set_stack("output", 1, new_stack)
  403. meta:set_string("text", "")
  404. workbench_update_help(pos)
  405. end
  406. end
  407. end,
  408. })
  409. minetest.register_craft({
  410. output = "engraver:bench",
  411. recipe = {
  412. {'default:bronze_ingot', 'default:bronze_ingot', 'default:bronze_ingot'},
  413. {'basictrees:tree_wood', 'default:stone', 'basictrees:tree_wood'},
  414. {'basictrees:tree_wood', '', 'basictrees:tree_wood'},
  415. }
  416. })
  417. minetest.register_craftitem(":engraver:plate", {
  418. description = "Nameplate",
  419. inventory_image = "default_nametag.png",
  420. groups = {not_renamable = 1}
  421. })
  422. minetest.register_craft({
  423. type = "compressing",
  424. output = "engraver:plate 4",
  425. recipe = "default:bronze_ingot",
  426. time = 10,
  427. })
  428. minetest.register_craft({
  429. type = "anvil",
  430. output = "engraver:plate",
  431. recipe = "default:bronze_ingot",
  432. })