init.lua 16 KB

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