init.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. default = default or {}
  2. utility = utility or {}
  3. utility.modpath = minetest.get_modpath("utility")
  4. -- Dummy function.
  5. fireambiance = {}
  6. function fireambiance.on_flame_addremove(pos)
  7. end
  8. function utility.trim_remove_special_chars(msg)
  9. local sub = string.gsub
  10. msg = sub(msg, "%z", "") -- Zero byte.
  11. msg = sub(msg, "%c", "") -- Control bytes.
  12. -- Trim whitespace.
  13. msg = sub(msg, "^%s+", "")
  14. msg = sub(msg, "%s+$", "")
  15. return msg
  16. end
  17. -- `level = 0/1, snappy = 3` enables quick digging via shears.
  18. -- Otherwise item cannot be dug by shears at all.
  19. --
  20. -- The 'hand' only digs items `level = 0` or `level = 1`, with some additional
  21. -- restrictions. See tool-data file for details.
  22. --
  23. -- Important/hard-to-craft nodes should be level 0 (like machines) otherwise
  24. -- player will lose the item if dug with a tool without a high enough level.
  25. --
  26. -- Shears only dig nodes with `level = 0/1, snappy = 3`.
  27. --
  28. -- `oddly_breakable_by_hand` only works if `level = 0/1`. HOWEVER, node drops
  29. -- can ONLY be obtained if the node's level is 0! Level 1 nodes may be dug if
  30. -- they're `oddly_breakable_by_hand`, but the player won't get the drops.
  31. --
  32. -- Base hardness for regular stone is `level = 2, cracky = 2`. Cobble is at
  33. -- `level = 1, cracky = 3`. These are both carefully tuned to allow new players
  34. -- to advance: wooden pick digs cobble to make stone pick, and a stone pick is
  35. -- able to dig regular stone. All other rocks/stones in the game should have
  36. -- their hardness calculated around regular stone/cobble.
  37. --
  38. -- The base hardness for tree trunks is `level = 2, choppy = 2`. Wood is
  39. -- calculated at `level = 2, choppy = 3`. All other wooden nodes should be
  40. -- calculated around these two.
  41. local dig_groups = {}
  42. -- Special undiggable group.
  43. dig_groups["ignore"] = {}
  44. -- Cracky stuff (stones/rocks/minerals).
  45. dig_groups["stone"] = {level = 2, cracky = 2} -- Carefully tuned dig-params! Do not modify.
  46. dig_groups["softstone"] = {level = 2, cracky = 3} -- Like sandstone.
  47. dig_groups["cobble"] = {level = 1, cracky = 3} -- Must be `cracky=3` otherwise cannot be dug by wooden pick.
  48. dig_groups["softcobble"] = {level = 1, cracky = 3, crumbly = 1} -- Can be dug by wodden pick.
  49. dig_groups["clay"] = {level = 0, cracky = 2, crumbly = 2}
  50. dig_groups["hardore"] = {level = 2, cracky = 1}
  51. dig_groups["hardclay"] = {level = 1, cracky = 2}
  52. dig_groups["ice"] = {level = 0, cracky = 2}
  53. dig_groups["hardice"] = {level = 1, cracky = 1}
  54. dig_groups["glass"] = {level = 1, cracky = 3}
  55. dig_groups["netherack"] = {level = 1, cracky = 3, oddly_breakable_by_hand = 1} -- Easiest thing to dig, practically!
  56. dig_groups["mineral"] = {level = 2, cracky = 3}
  57. dig_groups["hardmineral"] = {level = 2, cracky = 1}
  58. dig_groups["obsidian"] = {level = 3, cracky = 1} -- Obsidian, etc. Hardest possible.
  59. dig_groups["hardstone"] = {level = 3, cracky = 2} -- Granites, marbles.
  60. dig_groups["crystal"] = {level = 2, cracky = 3}
  61. -- Cracky stuff (building blocks/walls/bricks/etc).
  62. dig_groups["wall"] = {level = 1, cracky = 2}
  63. dig_groups["brick"] = {level = 1, cracky = 1}
  64. dig_groups["block"] = {level = 1, cracky = 1} -- Stone blocks, metal blocks, etc.
  65. -- Crumbly stuff (loose earth material).
  66. dig_groups["gravel"] = {level = 2, crumbly = 2} -- Cannot be dug by hand (level 1).
  67. dig_groups["dirt"] = {level = 2, crumbly = 3}
  68. dig_groups["sand"] = {level = 1, crumbly = 2}
  69. dig_groups["snow"] = {level = 0, crumbly = 3, oddly_breakable_by_hand = 3}
  70. dig_groups["mud"] = {level = 0, crumbly = 3, oddly_breakable_by_hand = 1}
  71. dig_groups["racksand"] = {level = 2, crumbly = 3}
  72. -- Choppy stuff (trees/wood).
  73. dig_groups["tree"] = {level = 2, choppy = 2} -- Carefully tuned dig-params! Do not change.
  74. dig_groups["deadtree"] = {level = 0, choppy = 2, oddly_breakable_by_hand = 1}
  75. dig_groups["wood"] = {level = 2, choppy = 3} -- Also wooden 'blocklike'. Planks & stuff.
  76. dig_groups["nyan"] = {level = 3, choppy = 1}
  77. -- Choppy stuff (crafted building materials).
  78. dig_groups["hardwood"] = {level = 1, choppy = 1}
  79. dig_groups["softwood"] = {level = 1, choppy = 3} -- Cactus, etc.
  80. -- Snappy stuff (plants/crops/leaves).
  81. -- Plants/crops can be dug by hand, but leaves cannot without proper tool.
  82. -- Addendum: player can dig leaves by hand but won't get drops.
  83. dig_groups["leaves"] = {level = 1, snappy = 3, choppy = 2, oddly_breakable_by_hand = 1} -- Must be `snappy=3` otherwise shears won't work.
  84. dig_groups["seeds"] = {level = 1, snappy = 2, oddly_breakable_by_hand = 3}
  85. dig_groups["plant"] = {level = 0, snappy = 3, choppy = 2} -- Must be `snappy=3` otherwise shears won't work.
  86. dig_groups["crop"] = {level = 0, snappy = 3, choppy = 2} -- Ditto ^^^. Also diggable by hand.
  87. dig_groups["straw"] = {level = 1, snappy = 2, choppy = 1, oddly_breakable_by_hand = 1}
  88. dig_groups["shroom"] = {level = 1, snappy = 2, choppy = 3, oddly_breakable_by_hand = 1}
  89. -- Misc items (items/machines/furniture/etc).
  90. dig_groups["wool"] = {level = 1, snappy = 3, choppy = 3}
  91. dig_groups["pane_wood"] = {level = 1, choppy = 3}
  92. dig_groups["pane_metal"] = {level = 1, cracky = 2}
  93. dig_groups["pane_glass"] = {level = 1, cracky = 3}
  94. dig_groups["fence_metal"] = {level = 1, cracky = 2}
  95. dig_groups["fence_wood"] = {level = 1, choppy = 2}
  96. dig_groups["furniture"] = {level = 0, snappy = 1, choppy = 3, oddly_breakable_by_hand = 3}
  97. dig_groups["item"] = {level = 0, dig_immediate = 3}
  98. dig_groups["bigitem"] = {level = 0, dig_immediate = 2}
  99. dig_groups["door_metal"] = {level = 1, cracky = 1}
  100. dig_groups["door_glass"] = {level = 1, cracky = 2}
  101. dig_groups["door_wood"] = {level = 1, choppy = 2}
  102. dig_groups["door_woodglass"]= {level = 1, choppy = 1}
  103. dig_groups["door_stone"] = {level = 1, cracky = 1}
  104. dig_groups["scaffolding"] = {level = 0, dig_immediate = 2}
  105. dig_groups["chest"] = {level = 0, choppy = 3, oddly_breakable_by_hand = 3}
  106. dig_groups["metalchest"] = {level = 0, cracky = 3, oddly_breakable_by_hand = 3}
  107. dig_groups["machine"] = {level = 0, cracky = 3} -- Must be level 0, or player may lose machine when dug!
  108. -- Get dig groups for a node based on its broad category.
  109. -- When choosing a name for a node, choose the name closest to the node's main material.
  110. function utility.dig_groups(name, ex)
  111. local groups = {}
  112. if not dig_groups[name] then
  113. minetest.log("error", "Could not find data for digging group '" .. name .. "'!")
  114. end
  115. local dig = dig_groups[name] or {level = 1, oddly_breakable_by_hand = 3}
  116. for k, v in pairs(dig) do
  117. groups[k] = v
  118. end
  119. -- Let custom groups override, include other stuff from groups.
  120. if ex then
  121. for k, v in pairs(ex) do
  122. groups[k] = v
  123. end
  124. end
  125. return groups
  126. end
  127. -- Copy standard/builtin groups only.
  128. -- Used mainly to ensure that stairs/microblock nodes don't include strange groups
  129. -- that should ONLY apply to their parent fullblock nodes.
  130. --
  131. -- Shall not return any groups used in crafting recipes!
  132. -- Shall return any/all groups required by tools!
  133. function utility.copy_builtin_groups(old_groups)
  134. local groups = {}
  135. groups.level = old_groups.level or 1
  136. if old_groups.crumbly then
  137. groups.crumbly = old_groups.crumbly
  138. end
  139. if old_groups.cracky then
  140. groups.cracky = old_groups.cracky
  141. end
  142. if old_groups.snappy then
  143. groups.snappy = old_groups.snappy
  144. end
  145. if old_groups.choppy then
  146. groups.choppy = old_groups.choppy
  147. end
  148. if old_groups.oddly_breakable_by_hand then
  149. groups.oddly_breakable_by_hand = old_groups.oddly_breakable_by_hand
  150. end
  151. if old_groups.flammable then
  152. groups.flammable = old_groups.flammable
  153. end
  154. if old_groups.dig_immediate then
  155. groups.dig_immediate = old_groups.dig_immediate
  156. end
  157. return groups
  158. end
  159. function utility.inventory_count_items(inv, listname, itemname)
  160. local list = inv:get_list(listname)
  161. local count = 0
  162. for i = 1, #list, 1 do
  163. if list[i]:get_name() == itemname then
  164. count = count + list[i]:get_count()
  165. end
  166. end
  167. return count
  168. end
  169. function utility.get_short_desc(str)
  170. if string.find(str, "[\n%(]") then
  171. str = string.sub(str, 1, string.find(str, "[\n%(]")-1)
  172. end
  173. str = string.gsub(str, "^%s+", "")
  174. str = string.gsub(str, "%s+$", "")
  175. return str
  176. end
  177. dofile(utility.modpath .. "/particle_override.lua")
  178. dofile(utility.modpath .. "/mapsave.lua")
  179. dofile(utility.modpath .. "/functions.lua")
  180. -- Get a player's foot position, given the player's position.
  181. -- Should help compatibility going into 0.5.0 and beyond.
  182. function utility.get_foot_pos(pos)
  183. return vector.add(pos, {x=0, y=0, z=0})
  184. end
  185. function utility.get_middle_pos(pos)
  186. return vector.add(pos, {x=0, y=1, z=0})
  187. end
  188. function utility.get_head_pos(pos)
  189. return vector.add(pos, {x=0, y=1.75, z=0})
  190. end
  191. -- Get rounded position of node player is standing on.
  192. function utility.node_under_pos(pos)
  193. return vector.round(vector.add(pos, {x=0, y=-0.05, z=0}))
  194. end
  195. -- Global multipliers for ABMs. Performance setting.
  196. default.ABM_TIMER_MULTIPLIER = 1
  197. default.ABM_CHANCE_MULTIPLIER = 2
  198. -- Global player-movement multiplier values.
  199. default.ROAD_SPEED = 1.3
  200. default.ROAD_SPEED_NETHER = 1.1
  201. default.ROAD_SPEED_CAVERN = 1.15
  202. default.SLOW_SPEED = 0.7
  203. default.SLOW_SPEED_NETHER = 0.85
  204. default.SLOW_SPEED_ICE = 0.85
  205. default.SLOW_SPEED_GRASS = 0.85
  206. default.SLOW_SPEED_PLANTS = 0.55
  207. default.NORM_SPEED = 1.0
  208. default.ROPE_SPEED = 1.1
  209. default.FAST_JUMP = 1.0
  210. default.SLOW_JUMP = 1.0
  211. default.NORM_JUMP = 1.0
  212. function utility.transform_nodebox(nodebox)
  213. for k, v in ipairs(nodebox) do
  214. for m, n in ipairs(v) do
  215. local p = nodebox[k][m]
  216. p = p / 16
  217. p = p - 0.5
  218. nodebox[k][m] = p
  219. end
  220. end
  221. return nodebox
  222. end
  223. -- Public API function. Sort two positions such that the first is always less than the second.
  224. utility.sort_positions = function(p1, p2)
  225. local pos1 = {x=p1.x, y=p1.y, z=p1.z}
  226. local pos2 = {x=p2.x, y=p2.y, z=p2.z}
  227. if pos1.x > pos2.x then pos2.x, pos1.x = pos1.x, pos2.x end
  228. if pos1.y > pos2.y then pos2.y, pos1.y = pos1.y, pos2.y end
  229. if pos1.z > pos2.z then pos2.z, pos1.z = pos1.z, pos2.z end
  230. return pos1, pos2
  231. end
  232. --
  233. -- optimized helper to put all items in an inventory into a drops list
  234. --
  235. function default.get_inventory_drops(pos, inventory, drops)
  236. local inv = minetest.get_meta(pos):get_inventory()
  237. local n = #drops
  238. for i = 1, inv:get_size(inventory) do
  239. local stack = inv:get_stack(inventory, i)
  240. if stack:get_count() > 0 then
  241. drops[n+1] = stack:to_table()
  242. n = n + 1
  243. end
  244. end
  245. end
  246. --
  247. -- dig upwards
  248. --
  249. function default.dig_up(pos, node, digger)
  250. if digger == nil then return end
  251. local np = {x = pos.x, y = pos.y + 1, z = pos.z}
  252. local nn = minetest.get_node(np)
  253. if nn.name == node.name then
  254. minetest.node_dig(np, nn, digger)
  255. end
  256. end
  257. --
  258. -- Checks if specified volume intersects a protected volume
  259. --
  260. function default.intersects_protection(minp, maxp, player_name, interval)
  261. -- 'interval' is the largest allowed interval for the 3D lattice of checks
  262. -- Compute the optimal float step 'd' for each axis so that all corners and
  263. -- borders are checked. 'd' will be smaller or equal to 'interval'.
  264. -- Subtracting 1e-4 ensures that the max co-ordinate will be reached by the
  265. -- for loop (which might otherwise not be the case due to rounding errors).
  266. local d = {}
  267. for _, c in pairs({"x", "y", "z"}) do
  268. if maxp[c] > minp[c] then
  269. d[c] = (maxp[c] - minp[c]) / math.ceil((maxp[c] - minp[c]) / interval) - 1e-4
  270. elseif maxp[c] == minp[c] then
  271. d[c] = 1 -- Any value larger than 0 to avoid division by zero
  272. else -- maxp[c] < minp[c], print error and treat as protection intersected
  273. minetest.log("error", "maxp < minp in 'default.intersects_protection()'")
  274. return true
  275. end
  276. end
  277. for zf = minp.z, maxp.z, d.z do
  278. local z = math.floor(zf + 0.5)
  279. for yf = minp.y, maxp.y, d.y do
  280. local y = math.floor(yf + 0.5)
  281. for xf = minp.x, maxp.x, d.x do
  282. local x = math.floor(xf + 0.5)
  283. if minetest.test_protection({x = x, y = y, z = z}, player_name) then
  284. return true
  285. end
  286. end
  287. end
  288. end
  289. return false
  290. end
  291. default.get_raillike_selection_box = function()
  292. return {
  293. type = "fixed",
  294. -- but how to specify the dimensions for curved and sideways rails?
  295. fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
  296. }
  297. end
  298. default.get_raillike_collision_box = function()
  299. return {
  300. type = "fixed",
  301. fixed = {
  302. {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
  303. },
  304. }
  305. end
  306. --
  307. -- Sapling 'on place' function to check protection of node and resulting tree volume
  308. --
  309. function default.sapling_on_place(itemstack, placer, pointed_thing,
  310. sapling_name, minp_relative, maxp_relative, interval)
  311. -- Position of sapling
  312. local pos = pointed_thing.under
  313. local node = minetest.get_node_or_nil(pos)
  314. local pdef = node and minetest.reg_ns_nodes[node.name]
  315. if pdef and pdef.on_rightclick and not placer:get_player_control().sneak then
  316. return pdef.on_rightclick(pos, node, placer, itemstack, pointed_thing)
  317. end
  318. if not pdef or not pdef.buildable_to then
  319. pos = pointed_thing.above
  320. node = minetest.get_node_or_nil(pos)
  321. pdef = node and minetest.reg_ns_nodes[node.name]
  322. if not pdef or not pdef.buildable_to then
  323. return itemstack
  324. end
  325. end
  326. local player_name = placer:get_player_name()
  327. -- Check sapling position for protection
  328. if minetest.is_protected(pos, player_name) then
  329. minetest.record_protection_violation(pos, player_name)
  330. return itemstack
  331. end
  332. -- Check tree volume for protection
  333. if default.intersects_protection(
  334. vector.add(pos, vector.add(minp_relative, {x=-1, y=-1, z=-1})),
  335. vector.add(pos, vector.add(maxp_relative, {x=1, y=1, z=1})),
  336. player_name,
  337. interval) then
  338. minetest.record_protection_violation(pos, player_name)
  339. -- Print extra information to explain
  340. minetest.chat_send_player(player_name, "# Server: Tree will intersect protection!")
  341. return itemstack
  342. end
  343. minetest.log("action", player_name .. " places node "
  344. .. sapling_name .. " at " .. minetest.pos_to_string(pos))
  345. local take_item = not minetest.setting_getbool("creative_mode")
  346. local newnode = {name = sapling_name}
  347. local ndef = minetest.reg_ns_nodes[sapling_name]
  348. minetest.set_node(pos, newnode)
  349. -- Run callback
  350. if ndef and ndef.after_place_node then
  351. -- Deepcopy place_to and pointed_thing because callback can modify it
  352. if ndef.after_place_node(table.copy(pos), placer,
  353. itemstack, table.copy(pointed_thing)) then
  354. take_item = false
  355. end
  356. end
  357. -- Run script hook
  358. for _, callback in ipairs(minetest.registered_on_placenodes) do
  359. -- Deepcopy pos, node and pointed_thing because callback can modify them
  360. if callback(table.copy(pos), table.copy(newnode),
  361. placer, table.copy(node or {}),
  362. itemstack, table.copy(pointed_thing)) then
  363. take_item = false
  364. end
  365. end
  366. -- Notify other hooks.
  367. dirtspread.on_environment(pos)
  368. droplift.notify(pos)
  369. if take_item then
  370. itemstack:take_item()
  371. end
  372. return itemstack
  373. end
  374. --
  375. -- NOTICE: This method is not an official part of the API yet!
  376. -- This method may change in future.
  377. --
  378. function utility.can_interact_with_node(player, pos)
  379. if player then
  380. if minetest.check_player_privs(player, "protection_bypass") then
  381. return true
  382. end
  383. else
  384. return false
  385. end
  386. local meta = minetest.get_meta(pos)
  387. local owner = meta:get_string("owner") or ""
  388. if owner == "" or owner == player:get_player_name() then
  389. -- Owner can access the node to any time
  390. return true
  391. end
  392. -- is player wielding the right key?
  393. local item = player:get_wielded_item()
  394. if item:get_name() == "key:key" or item:get_name() == "key:chain" then
  395. local key_meta = item:get_meta()
  396. if key_meta:get_string("secret") == "" then
  397. local key_oldmeta = item:get_metadata()
  398. if key_oldmeta == "" or not minetest.parse_json(key_oldmeta) then
  399. return false
  400. end
  401. key_meta:set_string("secret", minetest.parse_json(key_oldmeta).secret)
  402. item:set_metadata("")
  403. end
  404. return meta:get_string("key_lock_secret") == key_meta:get_string("secret")
  405. end
  406. return false
  407. end
  408. -- Called from bones mod to ensure the map is loaded before placing bones.
  409. -- Dunno if this has any real effect on the problem of bones disappearing.
  410. function utility.ensure_map_loaded(minp, maxp)
  411. local vm = minetest.get_voxel_manip()
  412. vm:read_from_map(minp, maxp)
  413. return vm:get_emerged_area() -- Return area actually loaded.
  414. end
  415. function table.shuffle(t, from, to, random)
  416. from = from or 1
  417. to = to or #t
  418. random = random or math.random
  419. local n = to - from + 1
  420. while n > 1 do
  421. local r = from + n-1
  422. local l = from + random(0, n-1)
  423. t[l], t[r] = t[r], t[l]
  424. n = n-1
  425. end
  426. end