init.lua 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579
  1. -- global callbacks
  2. footprints = {}
  3. local default_modpath = minetest.get_modpath("default")
  4. local S = minetest.get_translator(minetest.get_current_modname())
  5. -- Parameters
  6. local GLOBALSTEP_INTERVAL = 0.2 -- Function cycle in seconds.
  7. local HARDPACK_PROBABILITY = minetest.settings:get("footprints_hardpack_probability") or 0.9 -- Chance walked dirt/grass is worn and compacted to footprints:trail.
  8. local HARDPACK_COUNT = minetest.settings:get("footprints_hardpack_count") or 10 -- Number of times the above chance needs to be passed for soil to compact.
  9. local EROSION = minetest.settings:get_bool("footprints_erosion", true) -- Enable footprint erosion.
  10. local FOOTPRINTS_EROSION = minetest.settings:get_bool("footprints_trail_erosion", false) -- Allow hard-packed soil to erode back to dirt
  11. local EROSION_INTERVAL = minetest.settings:get("footprints_erosion_interval") or 128 -- Erosion interval.
  12. local EROSION_CHANCE = minetest.settings:get("footprints_erosion_chance") or 2 -- Erosion 1/x chance.
  13. -- Utility
  14. local function deep_copy(input)
  15. if type(input) ~= "table" then
  16. return input
  17. end
  18. local output = {}
  19. for index, value in pairs(input) do
  20. output[index] = deep_copy(value)
  21. end
  22. return output
  23. end
  24. -- Player positions
  25. local player_pos_previous_map = {}
  26. minetest.register_on_joinplayer(function(player)
  27. player_pos_previous_map[player:get_player_name()] = {x = 0, y = 0, z = 0}
  28. end)
  29. minetest.register_on_leaveplayer(function(player)
  30. player_pos_previous_map[player:get_player_name()] = nil
  31. end)
  32. local trampleable_nodes = {}
  33. local erosion = {}
  34. footprints.register_trample_node = function(trampleable_node_name, trample_def)
  35. trample_def = trample_def or {} -- Everything has defaults, so if no trample_def is passed in just use an empty table.
  36. if trampleable_nodes[trampleable_node_name] then
  37. minetest.log("error", "[footprints] Attempted to call footprints.register_trample_node to register trampleable node "
  38. .. trampleable_node_name ..", which has already been registered as trampleable.")
  39. return
  40. end
  41. local trampleable_node_def = minetest.registered_nodes[trampleable_node_name]
  42. if trampleable_node_def == nil then
  43. minetest.log("error", "[footprints] Attempted to call footprints.register_trample_node with the trampleable node "
  44. .. trampleable_node_name ..", which has not yet been registered as a node.")
  45. return
  46. end
  47. local trampled_node_name = trample_def.trampled_node_name or trampleable_node_name.."_trampled"
  48. if not minetest.registered_nodes[trampled_node_name] then
  49. local trampled_node_def = deep_copy(trampleable_node_def) -- start with a deep copy of the source node's definition
  50. if trample_def.trampled_node_def_override then -- override any values that need to be overridden explicitly
  51. for key, value in pairs(trample_def.trampled_node_def_override) do
  52. trampled_node_def[key] = value
  53. end
  54. end
  55. -- Set up the erosion ABM group
  56. if EROSION and trample_def.erodes ~= false then
  57. local groups = trampled_node_def.groups or {}
  58. groups.footprints_erodes = 1
  59. trampled_node_def.groups = groups
  60. erosion[trampled_node_name] = trampleable_node_name
  61. end
  62. -- If the source node doesn't have a special drop, then set drop to drop a source node rather than dropping a node with a footstep.
  63. if trampled_node_def.drop == nil then
  64. trampled_node_def.drop = trampleable_node_name
  65. end
  66. -- Modify the +Y tile with a footprint overlay
  67. if trample_def.add_footprint_overlay ~= false then
  68. local footprint_overlay = trample_def.footprint_overlay or "footprints_footprint.png"
  69. local footprint_opacity = trample_def.footprint_opacity or 64
  70. local overlay_texture = "^(" .. footprint_overlay .. "^[opacity:" .. tostring(footprint_opacity) .. ")"
  71. local tiles = trampled_node_def.tiles
  72. local first_tile = tiles[1]
  73. local second_tile = tiles[2]
  74. if second_tile == nil then
  75. -- The provided node def only has one tile for all sides. We need to only modify the +Y tile,
  76. -- so we need to copy the original first tile into the second tile slot
  77. tiles[2] = deep_copy(first_tile)
  78. end
  79. if type(first_tile) == "table" then
  80. first_tile.name = first_tile.name .. overlay_texture
  81. elseif type(first_tile) == "string" then
  82. first_tile = first_tile .. overlay_texture
  83. end
  84. trampled_node_def.tiles[1] = first_tile
  85. end
  86. minetest.register_node(":"..trampled_node_name, trampled_node_def)
  87. -- If hard pack has been defined for this footprints type, add it
  88. local hard_pack_node_name = trample_def.hard_pack_node_name
  89. if hard_pack_node_name then
  90. local hard_pack_probability = trample_def.hard_pack_probability or 0.1
  91. local hard_pack_count = trample_def.hard_pack_count or 1
  92. trampleable_nodes[trampled_node_name] = {name=hard_pack_node_name, probability=hard_pack_probability, count = hard_pack_count}
  93. end
  94. end
  95. local probability = trample_def.probability or 1
  96. local trample_count = trample_def.trample_count or 1
  97. trampleable_nodes[trampleable_node_name] = {name=trampled_node_name, probability=probability, randomize_trampled_param2 = trample_def.randomize_trampled_param2, count = trample_count}
  98. end
  99. footprints.register_erosion = function(source_node_name, destination_node_name)
  100. if not EROSION then
  101. return
  102. end
  103. if minetest.registered_nodes[source_node_name] == nil then
  104. minetest.log("error", "[footprints] attempted to call footprints.register_erosion with unregistered source node "
  105. .. source_node_name)
  106. return
  107. end
  108. if minetest.registered_nodes[destination_node_name] == nil then
  109. minetest.log("error", "[footprints] attempted to call footprints.register_erosion with unregistered destination node "
  110. .. destination_node_name)
  111. return
  112. end
  113. if minetest.get_item_group(source_node_name, "footprints_erodes") == 0 then
  114. minetest.log("error", "[footprints] attempted to call footprints.register_erosion with source node "
  115. .. destination_node_name .. " that wasn't in group footprints_erodes.")
  116. return
  117. end
  118. erosion[source_node_name] = destination_node_name
  119. end
  120. -- Nodes
  121. if default_modpath then
  122. -- hard-packed soil
  123. local footprints_trail_def = {
  124. tiles = {"footprints_trailtop.png", "default_dirt.png",
  125. "default_dirt.png^footprints_trailside.png"},
  126. groups = {crumbly = 2},
  127. drop = "default:dirt",
  128. sounds = default.node_sound_dirt_defaults(),
  129. }
  130. if FOOTPRINTS_EROSION then
  131. footprints_trail_def.groups.footprints_erodes = 1
  132. end
  133. minetest.register_node("footprints:trail", footprints_trail_def)
  134. if FOOTPRINTS_EROSION then
  135. footprints.register_erosion("footprints:trail", "default:dirt")
  136. end
  137. -- hard-packed dry soil
  138. local footprints_dry_trail_def = {
  139. tiles = {"footprints_trailtop.png", "default_dry_dirt.png",
  140. "default_dry_dirt.png^footprints_trailside.png"},
  141. groups = {crumbly = 2},
  142. drop = "default:dry_dirt",
  143. sounds = default.node_sound_dirt_defaults(),
  144. }
  145. if FOOTPRINTS_EROSION then
  146. footprints_dry_trail_def.groups.footprints_erodes = 1
  147. end
  148. minetest.register_node("footprints:dry_trail", footprints_dry_trail_def)
  149. if FOOTPRINTS_EROSION then
  150. footprints.register_erosion("footprints:dry_trail", "default:dry_dirt")
  151. end
  152. -- Default dirt
  153. footprints.register_trample_node("default:dirt", {
  154. trampled_node_name = "footprints:dirt",
  155. trampled_node_def_override = {description = S("Dirt with Footprint"),},
  156. hard_pack_node_name = "footprints:trail",
  157. footprint_opacity = 96,
  158. hard_pack_probability = HARDPACK_PROBABILITY,
  159. hard_pack_count = HARDPACK_COUNT,
  160. })
  161. footprints.register_trample_node("default:dirt_with_grass", {
  162. trampled_node_name = "footprints:dirt_with_grass",
  163. trampled_node_def_override = {description = S("Dirt with Grass and Footprint"),},
  164. hard_pack_node_name = "footprints:trail",
  165. hard_pack_probability = HARDPACK_PROBABILITY,
  166. hard_pack_count = HARDPACK_COUNT,
  167. })
  168. footprints.register_trample_node("default:dirt_with_dry_grass", {
  169. trampled_node_name = "footprints:dirt_with_dry_grass",
  170. trampled_node_def_override = {description = S("Dirt with Dry Grass and Footprint"),},
  171. hard_pack_node_name = "footprints:trail",
  172. hard_pack_probability = HARDPACK_PROBABILITY,
  173. hard_pack_count = HARDPACK_COUNT,
  174. })
  175. footprints.register_trample_node("default:dirt_with_snow", {
  176. trampled_node_name = "footprints:dirt_with_snow",
  177. trampled_node_def_override = {description = S("Dirt with Snow and Footprint"),},
  178. hard_pack_node_name = "footprints:trail",
  179. hard_pack_probability = HARDPACK_PROBABILITY,
  180. hard_pack_count = HARDPACK_COUNT,
  181. })
  182. footprints.register_trample_node("default:dirt_with_rainforest_litter", {
  183. trampled_node_name = "footprints:dirt_with_rainforest_litter",
  184. trampled_node_def_override = {description = S("Dirt with Rainforest Litter and Footprint"),},
  185. hard_pack_node_name = "footprints:trail",
  186. footprint_opacity = 96,
  187. hard_pack_probability = HARDPACK_PROBABILITY,
  188. hard_pack_count = HARDPACK_COUNT,
  189. })
  190. footprints.register_trample_node("default:dirt_with_coniferous_litter", {
  191. trampled_node_name = "footprints:dirt_with_coniferous_litter",
  192. trampled_node_def_override = {description = S("Dirt with Coniferous Litter and Footprint"),},
  193. hard_pack_node_name = "footprints:trail",
  194. footprint_opacity = 128,
  195. hard_pack_probability = HARDPACK_PROBABILITY,
  196. hard_pack_count = HARDPACK_COUNT,
  197. })
  198. footprints.register_trample_node("default:dry_dirt", {
  199. trampled_node_name = "footprints:dry_dirt",
  200. trampled_node_def_override = {description = S("Dry Dirt with Footprint"),},
  201. hard_pack_node_name = "footprints:dry_trail",
  202. footprint_opacity = 96,
  203. hard_pack_probability = HARDPACK_PROBABILITY,
  204. hard_pack_count = HARDPACK_COUNT,
  205. })
  206. footprints.register_trample_node("default:dry_dirt_with_dry_grass", {
  207. trampled_node_name = "footprints:dry_dirt_with_dry_grass",
  208. trampled_node_def_override = {description = S("Dry Dirt with Dry Grass and Footprint"),},
  209. hard_pack_node_name = "footprints:dry_trail",
  210. footprint_opacity = 96,
  211. hard_pack_probability = HARDPACK_PROBABILITY,
  212. hard_pack_count = HARDPACK_COUNT,
  213. })
  214. -- Default sand
  215. footprints.register_trample_node("default:sand", {
  216. trampled_node_name = "footprints:sand",
  217. trampled_node_def_override = {description = S("Sand with Footprint"),},
  218. })
  219. footprints.register_trample_node("default:desert_sand", {
  220. trampled_node_name = "footprints:desert_sand",
  221. trampled_node_def_override = {description = S("Desert Sand with Footprint"),},
  222. })
  223. footprints.register_trample_node("default:silver_sand", {
  224. trampled_node_name = "footprints:silver_sand",
  225. trampled_node_def_override = {description = S("Silver Sand with Footprint"),},
  226. })
  227. footprints.register_trample_node("default:gravel", {
  228. trampled_node_name = "footprints:gravel",
  229. trampled_node_def_override = {description = S("Gravel with Footprint"),},
  230. footprint_opacity = 128,
  231. })
  232. -- Default snow
  233. footprints.register_trample_node("default:snowblock", {
  234. trampled_node_name = "footprints:snowblock",
  235. trampled_node_def_override = {description = S("Snow Block with Footprint"),},
  236. hard_pack_node_name = "default:ice",
  237. hard_pack_probability = HARDPACK_PROBABILITY,
  238. hard_pack_count = HARDPACK_COUNT,
  239. })
  240. footprints.register_trample_node("default:snow", {
  241. trampled_node_name = "footprints:snow",
  242. trampled_node_def_override = {description = S("Snow with Footprint"),},
  243. })
  244. end
  245. if minetest.get_modpath("farming") then
  246. local hoe_converts_nodes = {}
  247. local sounds
  248. if default_modpath then
  249. sounds = default.node_sound_leaves_defaults()
  250. end
  251. -- Flattened wheat
  252. minetest.register_node("footprints:wheat", {
  253. description = S("Flattened Wheat"),
  254. tiles = {"footprints_flat_wheat.png"},
  255. inventory_image = "footprints_flat_wheat.png",
  256. drawtype = "nodebox",
  257. paramtype = "light",
  258. paramtype2 = "facedir",
  259. buildable_to = true,
  260. node_box = {
  261. type = "fixed",
  262. fixed = {
  263. {-0.5, -0.5, -0.5, 0.5, -3 / 8, 0.5}
  264. },
  265. },
  266. groups = {snappy = 3, flammable = 2, attached_node = 1},
  267. drop = "",
  268. sounds = sounds,
  269. })
  270. footprints.register_trample_node("farming:wheat_5", {
  271. trampled_node_name = "footprints:wheat",
  272. randomize_trampled_param2 = true,
  273. })
  274. footprints.register_trample_node("farming:wheat_6", {
  275. trampled_node_name = "footprints:wheat",
  276. randomize_trampled_param2 = true,
  277. })
  278. footprints.register_trample_node("farming:wheat_7", {
  279. trampled_node_name = "footprints:wheat",
  280. randomize_trampled_param2 = true,
  281. })
  282. footprints.register_trample_node("farming:wheat_8", {
  283. trampled_node_name = "footprints:wheat",
  284. randomize_trampled_param2 = true,
  285. })
  286. minetest.register_node("footprints:cotton", {
  287. description = S("Flattened Cotton"),
  288. tiles = {"footprints_flat_cotton.png"},
  289. inventory_image = "footprints_flat_cotton.png",
  290. drawtype = "nodebox",
  291. paramtype = "light",
  292. paramtype2 = "facedir",
  293. buildable_to = true,
  294. node_box = {
  295. type = "fixed",
  296. fixed = {
  297. {-0.5, -0.5, -0.5, 0.5, -3 / 8, 0.5}
  298. },
  299. },
  300. groups = {snappy = 3, flammable = 2, attached_node = 1},
  301. drop = "",
  302. sounds = sounds,
  303. })
  304. footprints.register_trample_node("farming:cotton_5", {
  305. trampled_node_name = "footprints:cotton",
  306. randomize_trampled_param2 = true,
  307. })
  308. footprints.register_trample_node("farming:cotton_6", {
  309. trampled_node_name = "footprints:cotton",
  310. randomize_trampled_param2 = true,
  311. })
  312. footprints.register_trample_node("farming:cotton_7", {
  313. trampled_node_name = "footprints:cotton",
  314. randomize_trampled_param2 = true,
  315. })
  316. footprints.register_trample_node("farming:cotton_8", {
  317. trampled_node_name = "footprints:cotton",
  318. randomize_trampled_param2 = true,
  319. })
  320. -- Allow hoes to turn hardpack back into bare dirt
  321. footprints.register_hoe_converts = function(target_node, converted_node)
  322. hoe_converts_nodes[target_node] = converted_node
  323. end
  324. local old_hoe_on_use = farming.hoe_on_use
  325. if not old_hoe_on_use then
  326. -- Something's wrong, don't override
  327. return
  328. end
  329. local new_hoe_on_use = function(itemstack, user, pointed_thing, uses)
  330. local pt = pointed_thing
  331. -- check if pointing at a node
  332. if not pt then
  333. return
  334. end
  335. if pt.type ~= "node" then
  336. return
  337. end
  338. local under_node = minetest.get_node(pt.under)
  339. local restore_node = hoe_converts_nodes[under_node.name]
  340. -- check if pointing at hardpack
  341. if restore_node then
  342. if minetest.is_protected(pt.under, user:get_player_name()) then
  343. minetest.record_protection_violation(pt.under, user:get_player_name())
  344. return
  345. end
  346. -- turn the node into soil and play sound
  347. minetest.set_node(pt.under, {name = restore_node})
  348. minetest.sound_play("default_dig_crumbly", {
  349. pos = pt.under,
  350. gain = 0.5,
  351. })
  352. if not (creative and creative.is_enabled_for
  353. and creative.is_enabled_for(user:get_player_name())) then
  354. -- wear tool
  355. local wdef = itemstack:get_definition()
  356. itemstack:add_wear(65535/(uses-1))
  357. -- tool break sound
  358. if itemstack:get_count() == 0 and wdef.sound and wdef.sound.breaks then
  359. minetest.sound_play(wdef.sound.breaks, {pos = pt.above, gain = 0.5})
  360. end
  361. end
  362. return itemstack
  363. end
  364. return old_hoe_on_use(itemstack, user, pointed_thing, uses)
  365. end
  366. farming.hoe_on_use = new_hoe_on_use
  367. else
  368. footprints.register_hoe_converts = function(target_node, converted_node)
  369. end
  370. end
  371. if default_modpath then
  372. footprints.register_hoe_converts("footprints:trail", "default:dirt")
  373. footprints.register_hoe_converts("footprints:dry_trail", "default:dry_dirt")
  374. end
  375. -- Globalstep function
  376. local timer = 0
  377. local get_param2 = function(footprints_def)
  378. if footprints_def.randomize_trampled_param2 then
  379. return math.random(0,3)
  380. end
  381. return 0
  382. end
  383. local test_trample_count = function(footprints_def, pos)
  384. local target_count = footprints_def.count
  385. if target_count <= 1 then
  386. return true
  387. end
  388. local meta = minetest.get_meta(pos)
  389. local trampled_count = meta:get_int("footprints_trample_count")
  390. trampled_count = trampled_count + 1
  391. if trampled_count >= target_count then
  392. return true
  393. end
  394. meta:set_int("footprints_trample_count", trampled_count)
  395. return false
  396. end
  397. local math_floor = math.floor
  398. minetest.register_globalstep(function(dtime)
  399. timer = timer + dtime
  400. if timer > GLOBALSTEP_INTERVAL then
  401. timer = 0
  402. for _, player in ipairs(minetest.get_connected_players()) do
  403. local pos = player:get_pos()
  404. local player_name = player:get_player_name()
  405. local pos_x_plus_half = math_floor(pos.x + 0.5)
  406. local pos_z_plus_half = math_floor(pos.z + 0.5)
  407. local pos_y = pos.y
  408. local current_player_pos = {
  409. x = pos_x_plus_half,
  410. y = math_floor(pos_y + 0.2),
  411. z = pos_z_plus_half
  412. }
  413. --if player_pos_previous_map[player_name] == nil then
  414. --break
  415. --end
  416. local player_pos_previous = player_pos_previous_map[player_name]
  417. if current_player_pos.x ~= player_pos_previous.x or
  418. current_player_pos.y < player_pos_previous.y or
  419. current_player_pos.z ~= player_pos_previous.z then
  420. local pos_ground_cover = {
  421. x = pos_x_plus_half,
  422. y = math_floor(pos_y + 1.2),
  423. z = pos_z_plus_half
  424. }
  425. local name_ground_cover = minetest.get_node(pos_ground_cover).name
  426. -- test ground cover first (snow, wheat)
  427. local footprints_def = trampleable_nodes[name_ground_cover]
  428. if footprints_def then
  429. if math.random() <= footprints_def.probability then
  430. local pos_ground_cover_plus = {
  431. x = pos_x_plus_half,
  432. y = math_floor(pos_y + 0.5),
  433. z = pos_z_plus_half
  434. }
  435. if test_trample_count(footprints_def, pos_ground_cover_plus) then
  436. minetest.set_node(pos_ground_cover_plus, {name = footprints_def.name, param2 = get_param2(footprints_def)})
  437. end
  438. end
  439. else
  440. local pos_ground = {
  441. x = pos_x_plus_half,
  442. y = math_floor(pos_y + 0.4),
  443. z = pos_z_plus_half
  444. }
  445. local name_ground = minetest.get_node(pos_ground).name
  446. footprints_def = trampleable_nodes[name_ground]
  447. if footprints_def and math.random() <= footprints_def.probability then
  448. local pos_groundpl = {
  449. x = pos_x_plus_half,
  450. y = math_floor(pos_y - 0.5),
  451. z =pos_z_plus_half
  452. }
  453. if test_trample_count(footprints_def, pos_groundpl) then
  454. minetest.set_node(pos_groundpl, {name = footprints_def.name, param2 = get_param2(footprints_def)})
  455. end
  456. end
  457. end
  458. end
  459. player_pos_previous_map[player_name] = current_player_pos
  460. end
  461. end
  462. end)
  463. -- ABM
  464. if EROSION then
  465. minetest.register_abm({
  466. nodenames = {"group:footprints_erodes"},
  467. interval = EROSION_INTERVAL,
  468. chance = EROSION_CHANCE,
  469. catch_up = true,
  470. action = function(pos, node, _, _)
  471. local nodename = node.name
  472. local erodes_to = erosion[nodename]
  473. if erodes_to then
  474. local meta = minetest.get_meta(pos)
  475. local trampled_count = meta:get_int("footprints_trample_count") - 1
  476. if trampled_count <= 0 then
  477. minetest.set_node(pos, {name = erodes_to})
  478. else
  479. meta:set_int("footprints_trample_count", trampled_count)
  480. end
  481. else
  482. minetest.log("error", "[footprints] The node " .. nodename .. " is in group footprints_erodes but "
  483. .. " didn't have an erosion target node defined.")
  484. end
  485. end
  486. })
  487. end
  488. minetest.register_alias("trail:cotton", "footprints:cotton")
  489. minetest.register_alias("trail:desert_sand", "footprints:desert_sand")
  490. minetest.register_alias("trail:dirt", "footprints:dirt")
  491. minetest.register_alias("trail:dirt_with_coniferous_litter","footprints:dirt_with_coniferous_litter")
  492. minetest.register_alias("trail:dirt_with_dry_grass", "footprints:dirt_with_dry_grass")
  493. minetest.register_alias("trail:dirt_with_grass", "footprints:dirt_with_grass")
  494. minetest.register_alias("trail:dirt_with_rainforest_litter","footprints:dirt_with_rainforest_litter")
  495. minetest.register_alias("trail:dirt_with_snow", "footprints:dirt_with_snow")
  496. minetest.register_alias("trail:dry_dirt", "footprints:dry_dirt")
  497. minetest.register_alias("trail:dry_dirt_with_dry_grass", "footprints:dry_dirt_with_dry_grass")
  498. minetest.register_alias("trail:dry_trail", "footprints:dry_trail")
  499. minetest.register_alias("trail:gravel", "footprints:gravel")
  500. minetest.register_alias("trail:sand", "footprints:sand")
  501. minetest.register_alias("trail:silver_sand", "footprints:silver_sand")
  502. minetest.register_alias("trail:snow", "footprints:snow")
  503. minetest.register_alias("trail:snowblock", "footprints:snowblock")
  504. minetest.register_alias("trail:trail", "footprints:trail")
  505. minetest.register_alias("trail:wheat", "footprints:wheat")