code:
local S = mobs.intllib

local get_velocity = function(self)

	local v = self.object:get_velocity()

	-- sanity check
	if not v then return 0 end

	return (v.x * v.x + v.z * v.z) ^ 0.5
end

-- Spider by AspireMint (CC-BY-SA 3.0 license)

mobs:register_mob("mobs_monster:spider", {
	--docile_by_day = true,
	group_attack = true,
	type = "monster",
	passive = false,
	attack_type = "dogfight",
	reach = 2,
	damage = 3,
	hp_min = 10,
	hp_max = 30,
	armor = 200,
	collisionbox = {-0.8, -0.5, -0.8, 0.8, 0, 0.8},
	visual_size = {x = 1, y = 1},
	visual = "mesh",
	mesh = "mobs_spider.b3d",
	textures = {
		{"mobs_spider_mese.png"},
		{"mobs_spider_orange.png"},
		{"mobs_spider_snowy.png"},
		{"mobs_spider_grey.png"},
		{"mobs_spider_crystal.png"},
	},
	makes_footstep_sound = false,
	sounds = {
		random = "mobs_spider",
		attack = "mobs_spider",
	},
	walk_velocity = 1,
	run_velocity = 3,
	jump = true,
	view_range = 15,
	floats = 0,
	drops = {
		{name = "farming:string", chance = 1, min = 0, max = 2},
	},
	water_damage = 5,
	lava_damage = 5,
	light_damage = 0,
	animation = {
		speed_normal = 15,
		speed_run = 20,--15,
		stand_start = 0,
		stand_end = 0,
		walk_start = 1,
		walk_end = 21,
		run_start = 1,
		run_end = 21,
		punch_start = 25,
		punch_end = 45,
	},
	-- what kind of spider are we spawning?
	on_spawn = function(self)

		local pos = self.object:get_pos() ; pos.y = pos.y - 1

		-- snowy spider
		if minetest.find_node_near(pos, 1,
				{"default:snow", "default:snowblock", "default:dirt_with_snow"}) then
			self.base_texture = {"mobs_spider_snowy.png"}
			self.object:set_properties({textures = self.base_texture})
			self.docile_by_day = true
		-- tarantula
		elseif minetest.find_node_near(pos, 1,
				{"default:dirt_with_rainforest_litter", "default:jungletree"}) then
			self.base_texture = {"mobs_spider_orange.png"}
			self.object:set_properties({textures = self.base_texture})
			self.docile_by_day = true
		-- grey spider
		elseif minetest.find_node_near(pos, 1,
				{"default:stone", "default:gravel"}) then
			self.base_texture = {"mobs_spider_grey.png"}
			self.object:set_properties({textures = self.base_texture})
		-- mese spider
		elseif minetest.find_node_near(pos, 1,
				{"default:mese", "default:stone_with_mese"}) then
			self.base_texture = {"mobs_spider_mese.png"}
			self.object:set_properties({textures = self.base_texture})
		elseif minetest.find_node_near(pos, 1,
				{"ethereal:crystal_dirt", "ethereal:crystal_spike"}) then
			self.base_texture = {"mobs_spider_crystal.png"}
			self.object:set_properties({textures = self.base_texture})
			self.docile_by_day = true
			self.drops = {
				{name = "farming:string", chance = 1, min = 0, max = 2},
				{name = "ethereal:crystal_spike", chance = 15, min = 1, max = 2},
			}
		end

		return true -- run only once, false/nil runs every activation
	end,

	-- custom function to make spiders climb vertical facings
	do_custom = function(self, dtime)

		-- quarter second timer
		self.spider_timer = (self.spider_timer or 0) + dtime
		if self.spider_timer < 0.25 then
			return
		end
		self.spider_timer = 0

		-- need to be stopped to go onwards
		if get_velocity(self) > 0.5 then
			self.disable_falling = nil
			return
		end

		local pos = self.object:get_pos()
		local yaw = self.object:get_yaw()

		-- sanity check
		if not yaw then return end

		pos.y = pos.y + self.collisionbox[2] - 0.2

		local dir_x = -math.sin(yaw) * (self.collisionbox[4] + 0.5)
		local dir_z = math.cos(yaw) * (self.collisionbox[4] + 0.5)
		local nod = minetest.get_node_or_nil({
			x = pos.x + dir_x,
			y = pos.y + 0.5,
			z = pos.z + dir_z
		})

		-- get current velocity
		local v = self.object:get_velocity()

		-- can only climb solid facings
		if not nod or not minetest.registered_nodes[nod.name]
		or not minetest.registered_nodes[nod.name].walkable then
			self.disable_falling = nil
			v.y = 0
			self.object:set_velocity(v)
			return
		end

--print ("----", nod.name, self.disable_falling, dtime)

		-- turn off falling if attached to facing
		self.disable_falling = true

		-- move up facing
		v.x = 0 ; v.y = 0
		v.y = self.jump_height
		mobs:set_animation(self, "jump")
		self.object:set_velocity(v)
	end,

	-- make spiders jump at you on attack
	custom_attack = function(self, pos)

		local vel = self.object:get_velocity()

		self.object:set_velocity({
			x = vel.x * self.run_velocity,
			y = self.jump_height * 1.5,
			z = vel.z * self.run_velocity
		})

		self.pausetimer = 0.5

		return true -- continue rest of attack function
	end
})

-- above ground spawn
mobs:spawn({
	name = "mobs_monster:spider",
	nodes = {
		"default:dirt_with_rainforest_litter", "default:snowblock",
		"default:snow", "ethereal:crystal_dirt", "ethereal:cold_dirt"
	},
	min_light = 0,
	max_light = 8,
	chance = 7000,
	active_object_count = 1,
	min_height = 25,
	max_height = 31000,
})

-- below ground spawn
mobs:spawn({
	name = "mobs_monster:spider",
	nodes = {"default:stone_with_mese", "default:mese", "default:stone"},
	min_light = 0,
	max_light = 7,
	chance = 7000,
	active_object_count = 1,
	min_height = -31000,
	max_height = -40,
})

mobs:register_egg("mobs_monster:spider", S("Spider"), "mobs_cobweb.png", 1)

mobs:alias_mob("mobs_monster:spider2", "mobs_monster:spider") -- compatibility
mobs:alias_mob("mobs:spider", "mobs_monster:spider")

-- cobweb
minetest.register_node(":mobs:cobweb", {
	description = S("Cobweb"),
	drawtype = "plantlike",
	visual_scale = 1.2,
	tiles = {"mobs_cobweb.png"},
	inventory_image = "mobs_cobweb.png",
	paramtype = "light",
	sunlight_propagates = true,
	liquid_viscosity = 11,
	liquidtype = "source",
	liquid_alternative_flowing = "mobs:cobweb",
	liquid_alternative_source = "mobs:cobweb",
	liquid_renewable = false,
	liquid_range = 0,
	walkable = false,
	groups = {snappy = 1, disable_jump = 1},
	drop = "farming:string",
	sounds = default.node_sound_leaves_defaults(),
})

minetest.register_craft({
	output = "mobs:cobweb",
	recipe = {
		{"farming:string", "", "farming:string"},
		{"", "farming:string", ""},
		{"farming:string", "", "farming:string"},
	}
})


code:
local S = mobs.intllib

-- Stone Monster by PilzAdam

mobs:register_mob("mobs_monster:stone_monster", {
	type = "monster",
	passive = false,
	attack_type = "dogfight",
	pathfinding = true,
	reach = 2,
	damage = 3,
	hp_min = 12,
	hp_max = 35,
	armor = 80,
	collisionbox = {-0.4, -1, -0.4, 0.4, 0.9, 0.4},
	visual = "mesh",
	mesh = "mobs_stone_monster.b3d",
	textures = {
		{"mobs_stone_monster.png"},
		{"mobs_stone_monster2.png"}, -- by AMMOnym
	},
	makes_footstep_sound = true,
	sounds = {
		random = "mobs_stonemonster",
	},
	walk_velocity = 1,
	run_velocity = 2,
	jump_height = 0,
	stepheight = 1.1,
	floats = 0,
	view_range = 10,
	drops = {
		{name = "default:cobble", chance = 1, min = 0, max = 2},
		{name = "default:coal_lump", chance = 3, min = 0, max = 2},
		{name = "default:iron_lump", chance = 5, min = 0, max = 2},
	},
	water_damage = 0,
	lava_damage = 1,
	light_damage = 0,
	animation = {
		speed_normal = 15,
		speed_run = 15,
		stand_start = 0,
		stand_end = 14,
		walk_start = 15,
		walk_end = 38,
		run_start = 40,
		run_end = 63,
		punch_start = 40,
		punch_end = 63,
	},
	immune_to = {
		{"default:pick_wood", 0}, -- wooden pick doesnt hurt stone monster
		{"default:pick_stone", 4}, -- picks deal more damage to stone monster
		{"default:pick_bronze", 5},
		{"default:pick_steel", 5},
		{"default:pick_mese", 6},
		{"default:pick_diamond", 7},
	},
})

mobs:spawn({
	name = "mobs_monster:stone_monster",
	nodes = {"default:stone", "default:desert_stone", "default:sandstone"},
	max_light = 7,
	chance = 7000,
	max_height = 0,
})

mobs:register_egg("mobs_monster:stone_monster", S("Stone Monster"), "default_stone.png", 1)

mobs:alias_mob("mobs:stone_monster", "mobs_monster:stone_monster") -- compatibility

repo_name: Desour/PlayMinetestServer

license: mit


code:
local S = mobs.intllib

-- Tree Monster (or Tree Gollum) by PilzAdam

mobs:register_mob("mobs_monster:tree_monster", {
	type = "monster",
	passive = false,
	attack_type = "dogfight",
	attack_animals = true,
	--specific_attack = {"player", "mobs_animal:chicken"},
	reach = 2,
	damage = 2,
	hp_min = 7,
	hp_max = 33,
	armor = 100,
	collisionbox = {-0.4, -1, -0.4, 0.4, 0.8, 0.4},
	visual = "mesh",
	mesh = "mobs_tree_monster.b3d",
	textures = {
		{"mobs_tree_monster.png"},
		{"mobs_tree_monster2.png"},
	},
	blood_texture = "default_wood.png",
	makes_footstep_sound = true,
	sounds = {
		random = "mobs_treemonster",
	},
	walk_velocity = 1,
	run_velocity = 3,
	jump = true,
	view_range = 15,
	drops = {
		{name = "default:stick", chance = 1, min = 0, max = 2},
		{name = "default:sapling", chance = 2, min = 0, max = 2},
		{name = "default:junglesapling", chance = 3, min = 0, max = 2},
		{name = "default:apple", chance = 4, min = 1, max = 2},
	},
	water_damage = 0,
	lava_damage = 0,
	light_damage = 2,
	fall_damage = 0,
	immune_to = {
		{"default:axe_wood", 0}, -- wooden axe doesnt hurt wooden monster
		{"default:axe_stone", 4}, -- axes deal more damage to tree monster
		{"default:axe_bronze", 5},
		{"default:axe_steel", 5},
		{"default:axe_mese", 7},
		{"default:axe_diamond", 9},
		{"default:sapling", -5}, -- default and jungle saplings heal
		{"default:junglesapling", -5},
--		{"all", 0}, -- only weapons on list deal damage
	},
	animation = {
		speed_normal = 15,
		speed_run = 15,
		stand_start = 0,
		stand_end = 24,
		walk_start = 25,
		walk_end = 47,
		run_start = 48,
		run_end = 62,
		punch_start = 48,
		punch_end = 62,
	},
})

mobs:spawn({
	name = "mobs_monster:tree_monster",
	nodes = {"default:leaves", "default:jungleleaves"},
	max_light = 7,
	chance = 7000,
	min_height = 0,
	day_toggle = false,
})

mobs:register_egg("mobs_monster:tree_monster", S("Tree Monster"), "default_tree_top.png", 1)

mobs:alias_mob("mobs:tree_monster", "mobs_monster:tree_monster") -- compatibility


code:
## Chat Log (*chatlog*) mod for [Minetest][]

---
### **Description:**

Forked from [JBR's chatlog mod][forum.jbr]. This mod creates a *chatlog.txt* file in the world directory with a record of player conversations.

Available configuration settings:
- ***chatlog.monthfirst***
  - If ***true***, puts month first in timestamp.

---
### **Licensing:**

[CC0][lic.cc0]

[Minetest]: http://www.minetest.net/

[forum]: https://forum.minetest.net/viewtopic.php?t=18287
[forum.jbr]: https://forum.minetest.net/viewtopic.php?t=6220

[lic.cc0]: LICENSE.txt


code: Creates a *chatlog.txt* file in the world directory.


code:
-- License: CC0

local filename = minetest.get_worldpath() .. "/chatlog.txt"
local date_format = "%d/%m/%y %X"

minetest.register_on_chat_message(function(name, msg)
	local f = io.open(filename, "a")
	f:write(string.format("(%s) [%s]: %s\n", os.date(date_format), name, msg))
	f:close()
end)


code:
name = chatlog
author = JBR, Jordan Irwin (AntumDeluge)
license = CC0
version = 1.0


code:
# Whether month is displayed before day in timestamp (E.g. 'dd/mm/yyyy' vs. 'mm/dd/yyyy').
chatlog.monthfirst (Timestamp shows month before day) bool false


code:
# morelights
Minetest mod adding additional lighting nodes.

![Screenshot](https://raw.githubusercontent.com/random-geek/morelights/master/screenshot.png "Screenshot")

The Morelights Modpack adds over 30 high-quality lighting nodes for your Minetest world.

## Craft Recipes

Recipes for dark-variant nodes are the same as those of the light variants, except with dark grey dye instead of white dye.

![Craft Recipes](https://raw.githubusercontent.com/random-geek/morelights/master/crafts.png "Craft Recipes")

## Licenses
Source code is licensed under the LGPL v3.0 license. All other media and assets are licensed under the CC BY-SA 4.0 license.


code:
name = mp_morelights
description = Morelights is a lightweight modpack providing flexible interior and exterior lighting options for different styles of builds.


code:
author = random_geek
description = Provides flexible interior and exterior lighting options for different styles of builds.
release = 831
title = Morelights
name = morelights


code:
default
dye
xpanes?


code:
morelights = {}

if minetest.get_modpath("xpanes") then
  morelights.glass = "xpanes:pane_flat"
else
  morelights.glass = "default:glass"
end

function morelights.register_variants(variants, fixedDef)
  for _,variant in ipairs(variants) do
    local name = variant.name
    local def = table.copy(fixedDef)

    for k,v in pairs(variant) do
      if k ~= "name" then
        def[k] = v
      end
    end

    minetest.register_node(name, def)
  end
end

function morelights.on_place_hanging(itemstack, placer, pointed_thing, replaceName)
  local ceiling = minetest.get_node(vector.add(pointed_thing.above,
    {x=0, y=1, z=0}))

  if ceiling and ceiling.name ~= "air"
    and minetest.get_item_group(ceiling.name, "mounted_ceiling") == 0
    and not (placer and placer:get_player_control().sneak) then

    local name = itemstack:get_name()
    local fakestack = itemstack
    fakestack:set_name(replaceName)

    minetest.item_place(fakestack, placer, pointed_thing, 0)
    itemstack:set_name(name)

    return itemstack
  end

  minetest.item_place(itemstack, placer, pointed_thing, 0)
  return itemstack
end

function morelights.rotate_and_place(itemstack, placer, pointed_thing, lookup)
  local dir = minetest.dir_to_wallmounted(vector.subtract(pointed_thing.under, pointed_thing.above))
  local fDirs = lookup or {[0] = 20, 0, 16, 12, 8, 4}
  minetest.item_place(itemstack, placer, pointed_thing, fDirs[dir] or 0)
  return itemstack
end

local path = minetest.get_modpath("morelights")

dofile(path .. "/nodes.lua")


code:
minetest.register_craftitem("morelights:bulb", {
  description = "Light Bulb",
  inventory_image = "morelights_bulb.png"
})

morelights.register_variants({
  {name = "morelights:pole_d", description = "Metal Pole (dark)",
    tiles = {"morelights_metal_dark_32.png"},
    on_place = function(itemstack, placer, pointed_thing)
      return morelights.on_place_hanging(itemstack, placer, pointed_thing,
        "morelights:pole_ceiling_d")
    end},
  {name = "morelights:pole_l", description = "Metal Pole (light)",
    tiles = {"morelights_metal_light_32.png"},
    on_place = function(itemstack, placer, pointed_thing)
      return morelights.on_place_hanging(itemstack, placer, pointed_thing,
        "morelights:pole_ceiling_l")
    end}
},
{
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/32, -1/2, -1/32, 1/32, 1/2, 1/32}
  },
  selection_box = {
    type = "wallmounted",
    wall_bottom = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16},
    wall_side = {-1/2, -1/16, -1/16, 1/2, 1/16, 1/16},
    wall_top = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16}
  },
  paramtype = "light",
  paramtype2 = "wallmounted",
  sunlight_propegates = true,
  groups = {cracky = 3, oddly_breakable_by_hand = 3, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),
})

morelights.register_variants({
  {name = "morelights:pole_ceiling_d",
    tiles = {"morelights_metal_dark_32.png"}, drop = "morelights:pole_d"},
  {name = "morelights:pole_ceiling_l",
    tiles = {"morelights_metal_light_32.png"}, drop = "morelights:pole_l"}
},
{
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {{-3/16, -7/16, -3/16, 3/16, -1/2, 3/16},
      {-1/32, 1/2, -1/32, 1/32, -7/16, 1/32}}
  },
  selection_box = {
    type = "wallmounted",
    wall_bottom = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16},
    wall_side = {-1/2, -1/16, -1/16, 1/2, 1/16, 1/16},
    wall_top = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16}
  },
  paramtype = "light",
  paramtype2 = "wallmounted",
  sunlight_propegates = true,
  groups = {cracky = 3, oddly_breakable_by_hand = 3,
    not_in_creative_inventory = 1, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),
})

morelights.register_variants({
  {name = "morelights:chain_d", description = "Metal Chain (dark)",
    tiles = {"morelights_metal_dark_32.png"},
    on_place = function(itemstack, placer, pointed_thing)
      return morelights.on_place_hanging(itemstack, placer, pointed_thing,
        "morelights:chain_ceiling_d")
    end},
  {name = "morelights:chain_l", description = "Metal Chain (light)",
    tiles = {"morelights_metal_light_32.png"},
    on_place = function(itemstack, placer, pointed_thing)
      return morelights.on_place_hanging(itemstack, placer, pointed_thing,
        "morelights:chain_ceiling_l")
    end}
},
{
  drawtype = "mesh",
  mesh = "morelights_chain.obj",
  collision_box = {
    type = "fixed",
    fixed = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/16, -1/2, -1/16, 1/16, 1/2, 1/16}
  },
  paramtype = "light",
  groups = {cracky = 3, oddly_breakable_by_hand = 3, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),
})

morelights.register_variants({
  {name = "morelights:chain_ceiling_d",
    tiles = {"morelights_metal_dark_32.png"}, drop = "morelights:chain_d"},
  {name = "morelights:chain_ceiling_l",
    tiles = {"morelights_metal_light_32.png"}, drop = "morelights:chain_l"}
},
{
  drawtype = "mesh",
  mesh = "morelights_chain_ceiling.obj",
  collision_box = {
    type = "fixed",
    fixed = {{-3/16, 7/16, -3/16, 3/16, 1/2, 3/16},
      {-1/16, -1/2, -1/16, 1/16, 7/16, 1/16}}
  },
  selection_box = {
    type = "fixed",
    fixed = {{-3/16, 7/16, -3/16, 3/16, 1/2, 3/16},
      {-1/16, -1/2, -1/16, 1/16, 7/16, 1/16}}
  },
  paramtype = "light",
  groups = {cracky = 3, oddly_breakable_by_hand = 3,
    not_in_creative_inventory = 1, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),
})

--
-- Craft recipes
--

minetest.register_craft({
  output = "morelights:bulb 4",
  recipe = {
    {"", "default:glass", ""},
    {"", "default:copper_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights:pole_d 2",
  recipe = {
    {"dye:dark_grey", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights:pole_l 2",
  recipe = {
    {"dye:white", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights:chain_d",
  recipe = {
    {"dye:dark_grey", "default:steel_ingot", ""},
    {"", "", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights:chain_l",
  recipe = {
    {"dye:white", "default:steel_ingot", ""},
    {"", "", ""},
    {"", "default:steel_ingot", ""}
  }
})


code:
default
morelights
stairs?


code:
minetest.register_node("morelights_extras:f_block", {
  description = "Futuristic Light Block",
  tiles = {"morelights_extras_f_block.png"},
  paramtype = "light",
  light_source = LIGHT_MAX,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_extras:dirt_with_grass", {
  description = "Grass Light",
  tiles = {"default_grass.png^morelights_extras_blocklight.png",
    "default_dirt.png", "default_dirt.png^default_grass_side.png"},
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults()
})

minetest.register_node("morelights_extras:stone_block", {
  description = "Stone Block Light",
  tiles = {"default_stone_block.png^morelights_extras_blocklight.png"},
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults()
})

minetest.register_node("morelights_extras:sandstone_block", {
  description = "Sandstone Block Light",
  tiles = {"default_sandstone_block.png^morelights_extras_blocklight.png"},
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults()
})

minetest.register_node("morelights_extras:stairlight", {
  description = "Stair Light (place on stairs)",
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/4, -13/16, -1/16, 1/4, -11/16, 0}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/4, -13/16, -1/16, 1/4, -11/16, 0}
  },
  walkable = false,
  tiles = {"morelights_metal_dark.png"},
  overlay_tiles = {"", "morelights_extras_stairlight.png",
    "", "", "morelights_extras_stairlight.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = 10,
  groups = {cracky = 2, oddly_breakable_by_hand = 3, attached_node = 1},
  node_placement_prediction = "",
  sounds = default.node_sound_glass_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
    local node = minetest.get_node(vector.subtract(pointed_thing.above,
      {x=0, y=1, z=0}))

    if node and node.name:match("^stairs:stair")
      and node.param2 < 4 then
      minetest.item_place(itemstack, placer, pointed_thing, node.param2)
    end

    return itemstack
  end,

  on_rotate = function(pos, node, user, mode, new_param2)
    return false
  end,
})

--
-- Craft recipes
--

minetest.register_craft({
  output = "morelights_extras:f_block",
  recipe = {
    {"default:mese_crystal_fragment", "default:steel_ingot", "default:mese_crystal_fragment"},
    {morelights.glass, "morelights:bulb", morelights.glass},
    {"default:mese_crystal_fragment", "default:steel_ingot", "default:mese_crystal_fragment"}
  }
})

minetest.register_craft({
  output = "morelights_extras:dirt_with_grass",
  recipe = {
    {"", morelights.glass, ""},
    {"", "morelights:bulb", ""},
    {"default:grass_1", "default:dirt", ""}
  }
})

minetest.register_craft({
  output = "morelights_extras:stone_block",
  recipe = {
    {"", morelights.glass, ""},
    {"", "morelights:bulb", ""},
    {"", "default:stone_block", ""}
  }
})

minetest.register_craft({
  output = "morelights_extras:sandstone_block",
  recipe = {
    {"", morelights.glass, ""},
    {"", "morelights:bulb", ""},
    {"", "default:sandstone_block", ""}
  }
})

minetest.register_craft({
  output = "morelights_extras:stairlight",
  recipe = {
    {"default:steel_ingot", "morelights:bulb", "default:steel_ingot"}
  }
})


code:
default
dye
morelights
wool


code:
minetest.register_node("morelights_modern:block", {
  description = "Modern Light Block",
  tiles = {"morelights_metal_dark.png^morelights_modern_block.png"},
  paramtype = "light",
  light_source = LIGHT_MAX,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_modern:smallblock", {
  description = "Modern Light Block (small)",
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/4, -1/2, -1/4, 1/4, 0, 1/4}
  },
  tiles = {"morelights_metal_dark.png^morelights_modern_smallblock.png",
    "morelights_metal_dark.png^morelights_modern_smallblock.png",
    "[combine:16x16:0,0=morelights_metal_dark.png:0,4=morelights_modern_smallblock.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = 12,
  groups = {cracky = 3, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
    return morelights.rotate_and_place(itemstack, placer, pointed_thing)
  end,
})

morelights.register_variants({
  {name = "morelights_modern:post_d", description = "Modern Post Light (dark)",
    tiles = {"morelights_metal_dark.png", "morelights_metal_dark.png",
    "morelights_metal_dark.png^morelights_modern_post.png"}},
  {name = "morelights_modern:post_l", description = "Modern Post Light (light)",
    tiles = {"morelights_metal_light.png", "morelights_metal_light.png",
    "morelights_metal_light.png^morelights_modern_post.png"}}
},
{
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {{-1/8, -1/2, -1/8, 1/8, 1/2, 1/8}}
  },
  paramtype = "light",
  light_source = LIGHT_MAX,
  groups = {cracky = 3, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_metal_defaults(),
})

morelights.register_variants({
  {name = "morelights_modern:streetpost_d",
    description = "Street Lamp Post (dark)--connects to bar lights",
    tiles = {"morelights_metal_dark.png"}},
  {name = "morelights_modern:streetpost_l",
    description = "Street Lamp Post (light)--connects to bar lights",
    tiles = {"morelights_metal_light.png"}}
},
{
  drawtype = "nodebox",
  node_box = {
    type = "connected",
    fixed = {-1/16, -1/2, -1/16, 1/16,  1/2, 1/16},
    connect_front = {-1/16,  3/8, -1/2, 1/16,  7/16, -1/16},
    connect_left = {-1/2, 3/8, -1/16, -1/16, 7/16, 1/16},
    connect_back = {-1/16, 3/8, 1/16, 1/16, 7/16, 1/2},
    connect_right = {1/16, 3/8, -1/16, 1/2, 7/16, 1/16},
  },
  connects_to = {"morelights_modern:barlight_c", "morelights_modern:barlight_s"},
  paramtype = "light",
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_metal_defaults(),
})

minetest.register_node("morelights_modern:barlight_c", {
  description = "Ceiling Bar Light (connecting)",
  drawtype = "nodebox",
  node_box = {
    type = "connected",
    fixed = {-1/8,  3/8, -1/8, 1/8,  1/2, 1/8},
    connect_front = {-1/8, 3/8, -1/2, 1/8,  1/2, -1/8},
    connect_left = {-1/2, 3/8, -1/8, -1/8, 1/2, 1/8},
    connect_back = {-1/8, 3/8, 1/8, 1/8, 1/2, 1/2},
    connect_right = {1/8, 3/8, -1/8, 1/2, 1/2, 1/8},
  },
  connects_to = {"morelights_modern:barlight_c", "morelights_modern:barlight_s",
    "morelights_modern:streetpost_d", "morelights_modern:streetpost_l"},
  tiles = {"morelights_metal_dark.png", "morelights_modern_barlight.png",
    "morelights_metal_dark.png"},
  paramtype = "light",
  light_source = LIGHT_MAX,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_modern:barlight_s", {
  description = "Ceiling Bar Light (straight)",
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/2, 3/8, -1/8, 1/2, 1/2, 1/8},
  },
  tiles = {"morelights_metal_dark.png", "morelights_modern_barlight.png",
    "morelights_metal_dark.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = LIGHT_MAX,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_modern:ceilinglight", {
  description = "Modern Ceiling Light",
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/4, 3/8, -1/4, 1/4, 1/2, 1/4}
  },
  tiles = {"morelights_metal_dark.png",
    "morelights_metal_dark.png^morelights_modern_block.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = LIGHT_MAX,
  groups = {cracky = 3, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
    return morelights.rotate_and_place(itemstack, placer, pointed_thing,
      {[0] = 0, 20, 12, 16, 4, 8})
  end,
})

morelights.register_variants({
  {name = "morelights_modern:canlight_d",
    description = "Modern Can Light (dark)",
    tiles = {"morelights_metal_dark.png^morelights_modern_canlight.png"}},
  {name = "morelights_modern:canlight_l",
    description = "Modern Can Light (light)",
    tiles = {"morelights_metal_light.png^morelights_modern_canlight.png"}},
},
{
  drawtype = "mesh",
  mesh = "morelights_modern_canlight.obj",
  collision_box = {
    type = "fixed",
    fixed = {-1/8, 0, -1/8, 1/8, 1/2, 1/8}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/8, 0, -1/8, 1/8, 1/2, 1/8}
  },
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_metal_defaults(),
})

minetest.register_node("morelights_modern:walllamp", {
  description = "Modern Wall Lamp",
  drawtype = "mesh",
  mesh = "morelights_modern_walllamp.obj",
  collision_box = {
    type = "fixed",
    fixed = {-1/8, -3/8, 1/8, 1/8, 1/4, 1/2}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/8, -3/8, 1/8, 1/8, 1/4, 1/2}
  },
  tiles = {"morelights_metal_dark_32.png^morelights_modern_walllamp.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
    return morelights.rotate_and_place(itemstack, placer, pointed_thing,
      {[0] = 6, 4, 1, 3, 0, 2})
  end,
})

morelights.register_variants({
  {name = "morelights_modern:tablelamp_d",
    description = "Modern Table Lamp (dark)",
    tiles = {"morelights_metal_light_32.png^morelights_modern_tablelamp_o.png",
    "morelights_modern_tablelamp_d.png"}},
  {name = "morelights_modern:tablelamp_l",
    description = "Modern Table Lamp (light)",
    tiles = {"morelights_metal_dark_32.png^morelights_modern_tablelamp_o.png",
    "morelights_modern_tablelamp_l.png"}},
},
{
  drawtype = "mesh",
  mesh = "morelights_modern_tablelamp.obj",
  collision_box = {
    type = "fixed",
    fixed = {-1/4, -1/2, -1/4, 1/4, 7/16, 1/4}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/4, -1/2, -1/4, 1/4, 7/16, 1/4}
  },
  paramtype = "light",
  light_source = 10,
  groups = {choppy = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_defaults(),
})

morelights.register_variants({
  {name = "morelights_modern:pathlight_d",
    description = "Modern Path Light (dark)",
    tiles = {"morelights_metal_dark_32.png^morelights_modern_pathlight.png"}},
  {name = "morelights_modern:pathlight_l",
    description = "Modern Path Light (light)",
    tiles = {"morelights_metal_light_32.png^morelights_modern_pathlight.png"}}
},
{
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {{-1/32, -8/16, -1/32, 1/32, 1/8, 1/32},
      {-1/16, 1/8, -1/16, 1/16, 5/16, 1/16},
      {-1/8, 5/16, -1/8, 1/8, 3/8, 1/8}}
  },
  selection_box = {
    type = "fixed",
    fixed = {{-1/8, -1/2, -1/8, 1/8, 3/8, 1/8}}
  },
  paramtype = "light",
  light_source = 8,
  groups = {cracky = 3, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_metal_defaults(),
})

--
-- Craft recipes
--

minetest.register_craft({
  output = "morelights_modern:block",
  recipe = {
    {"", "default:steel_ingot", ""},
    {morelights.glass, "morelights:bulb", morelights.glass},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:smallblock",
  recipe = {
    {"", morelights.glass, ""},
    {"default:steel_ingot", "morelights:bulb", "default:steel_ingot"}
  }
})

minetest.register_craft({
  output = "morelights_modern:post_d",
  recipe = {
    {"dye:dark_grey", "default:steel_ingot", ""},
    {"", "morelights:bulb", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:post_l",
  recipe = {
    {"dye:white", "default:steel_ingot", ""},
    {"", "morelights:bulb", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:streetpost_d 2",
  recipe = {
    {"dye:dark_grey", "default:steel_ingot", "default:steel_ingot"},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:streetpost_l 2",
  recipe = {
    {"dye:white", "default:steel_ingot", "default:steel_ingot"},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:barlight_c 4",
  recipe = {
    {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"},
    {"default:copper_ingot", "default:glass", "default:copper_ingot"}
  }
})

minetest.register_craft({
  output = "morelights_modern:barlight_c",
  type = "shapeless",
  recipe = {"morelights_modern:barlight_s"}
})

minetest.register_craft({
  output = "morelights_modern:barlight_s",
  type = "shapeless",
  recipe = {"morelights_modern:barlight_c"}
})

minetest.register_craft({
  output = "morelights_modern:ceilinglight",
  recipe = {
    {"default:steel_ingot", "morelights:bulb", "default:steel_ingot"},
    {"", morelights.glass, ""},
  }
})

minetest.register_craft({
  output = "morelights_modern:canlight_d",
  recipe = {
    {"dye:dark_grey", "default:steel_ingot", ""},
    {"default:steel_ingot", "morelights:bulb", "default:steel_ingot"},
  }
})

minetest.register_craft({
  output = "morelights_modern:canlight_l",
  recipe = {
    {"dye:white", "default:steel_ingot", ""},
    {"default:steel_ingot", "morelights:bulb", "default:steel_ingot"},
  }
})

minetest.register_craft({
  output = "morelights_modern:walllamp",
  recipe = {
    {"dye:white", morelights.glass, ""},
    {morelights.glass, "morelights:bulb", "default:steel_ingot"},
    {"", "dye:dark_grey", "default:steel_ingot"}
  }
})

minetest.register_craft({
  output = "morelights_modern:tablelamp_d",
  recipe = {
    {"wool:dark_grey", "morelights:bulb", "wool:dark_grey"},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:tablelamp_l",
  recipe = {
    {"wool:white", "morelights:bulb", "wool:white"},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:pathlight_d",
  recipe = {
    {"dye:dark_grey", "morelights:bulb", ""},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})

minetest.register_craft({
  output = "morelights_modern:pathlight_l",
  recipe = {
    {"dye:white", "morelights:bulb", ""},
    {"", "default:steel_ingot", ""},
    {"", "default:steel_ingot", ""}
  }
})


code:
basic_materials?
default
farming
morelights


code:
-- basic_materials compatibility

local brass_ingot_name

if minetest.get_modpath("basic_materials") then
  -- Use basic materials brass ingot
  brass_ingot_name = "basic_materials:brass_ingot"
else
  -- Register and use morelights brass ingot
  minetest.register_craftitem("morelights_vintage:brass_ingot", {
    description = "Brass Ingot",
    inventory_image = "default_steel_ingot.png^[multiply:#FFCE69"
  })

  minetest.register_craft({
    output = "morelights_vintage:brass_ingot 2",
    type = "shapeless",
    recipe = {
      "default:copper_ingot", "default:tin_ingot"
    }
  })

  brass_ingot_name = "morelights_vintage:brass_ingot"
end

minetest.register_node("morelights_vintage:chain_b", {
  description = "Brass Chain",
  drawtype = "mesh",
  mesh = "morelights_chain.obj",
  collision_box = {
    type = "fixed",
    fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/16, -8/16, -1/16, 1/16, 8/16, 1/16}
  },
  tiles = {"morelights_vintage_brass_32.png"},
  paramtype = "light",
  groups = {cracky = 3, oddly_breakable_by_hand = 3, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
    return morelights.on_place_hanging(itemstack, placer, pointed_thing,
      "morelights_vintage:chain_ceiling_b")
  end,
})

minetest.register_node("morelights_vintage:chain_ceiling_b", {
  drawtype = "mesh",
  mesh = "morelights_chain_ceiling.obj",
  collision_box = {
    type = "fixed",
    fixed = {{-3/16,  7/16, -3/16, 3/16,  8/16, 3/16},
      {-1/16, -8/16, -1/16, 1/16, 7/16, 1/16}}
  },
  selection_box = {
    type = "fixed",
    fixed = {{-3/16,  7/16, -3/16, 3/16,  8/16, 3/16},
      {-1/16, -8/16, -1/16, 1/16, 7/16, 1/16}}
  },
  tiles = {"morelights_vintage_brass_32.png"},
  drop = "morelights_vintage:chain_b",
  paramtype = "light",
  groups = {cracky = 3, oddly_breakable_by_hand = 3,
    not_in_creative_inventory = 1, mounted_ceiling = 1},
  sounds = default.node_sound_metal_defaults(),
})

minetest.register_node("morelights_vintage:block", {
  description = "Vintage Light Block",
  tiles = {"morelights_vintage_block.png"},
  paramtype = "light",
  light_source = LIGHT_MAX,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_vintage:smallblock", {
  description = "Vintage Light Block (small)",
  drawtype = "nodebox",
  node_box = {
    type = "fixed",
    fixed = {-1/4, -1/2, -1/4, 1/4, 0, 1/4}
  },
  tiles = {"morelights_vintage_block.png", "morelights_vintage_block.png",
    "[combine:16x16:0,4=morelights_vintage_block.png"},
  paramtype = "light",
  paramtype2 = "facedir",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
  on_place = function(itemstack, placer, pointed_thing)
    return morelights.rotate_and_place(itemstack, placer, pointed_thing)
  end,
})

minetest.register_node("morelights_vintage:lantern_f", {
  description = "Vintage Lantern (floor, wall, or ceiling)",
  drawtype = "mesh",
  mesh = "morelights_vintage_lantern_f.obj",
  tiles = {"morelights_vintage_lantern.png", "morelights_metal_dark_32.png"},
  collision_box = {
    type = "fixed",
    fixed = {-3/16, -1/2, -3/16, 3/16, 1/16, 3/16}
  },
  selection_box = {
    type = "fixed",
    fixed = {-3/16, -1/2, -3/16, 3/16, 1/16, 3/16}
  },
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),

  on_place = function(itemstack, placer, pointed_thing)
		local wdir = minetest.dir_to_wallmounted(
      vector.subtract(pointed_thing.under, pointed_thing.above))
		local fakestack = itemstack

		if wdir == 0 then
			fakestack:set_name("morelights_vintage:lantern_c")
		elseif wdir == 1 then
			fakestack:set_name("morelights_vintage:lantern_f")
		else
			fakestack:set_name("morelights_vintage:lantern_w")
		end

		itemstack = minetest.item_place(fakestack, placer, pointed_thing, wdir)
		itemstack:set_name("morelights_vintage:lantern_f")

		return itemstack
	end,
})

minetest.register_node("morelights_vintage:lantern_c", {
  drawtype = "mesh",
  mesh = "morelights_vintage_lantern_c.obj",
  tiles = {"morelights_vintage_lantern.png", "morelights_metal_dark_32.png"},
  collision_box = {
    type = "fixed",
    fixed = {-3/16, -1/16, -3/16, 3/16, 1/2, 3/16}
  },
  selection_box = {
    type = "fixed",
    fixed = {-3/16, 0, -3/16, 3/16, 1/2, 3/16}
  },
  paramtype = "light",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3,
    not_in_creative_inventory = 1},
  sounds = default.node_sound_glass_defaults(),
  drop = "morelights_vintage:lantern_f",
})

minetest.register_node("morelights_vintage:lantern_w", {
  drawtype = "mesh",
  mesh = "morelights_vintage_lantern_w.obj",
  tiles = {"morelights_vintage_lantern.png", "morelights_metal_dark_32.png"},
  collision_box = {
    type = "fixed",
    fixed = {-3/16, -1/4, -5/16, 3/16, 1/8, 3/16}
  },
  selection_box = {
    type = "wallmounted",
    wall_bottom = {-3/16, -1/4, -5/16, 3/16, 1/8, 3/16},
    wall_side = {-1/4, -5/16, -3/16, 1/8, 3/16, 3/16},
    wall_top = {-3/16, -1/8, -5/16, 3/16, 1/4, 3/16}
  },
  paramtype = "light",
  paramtype2 = "wallmounted",
  light_source = 12,
  groups = {cracky = 2, oddly_breakable_by_hand = 3,
    not_in_creative_inventory = 1},
  sounds = default.node_sound_glass_defaults(),
  drop = "morelights_vintage:lantern_f",
})

minetest.register_node("morelights_vintage:hangingbulb", {
  description = "Vintage Hanging Light Bulb",
  drawtype = "mesh",
  mesh = "morelights_vintage_hangingbulb.obj",
  tiles = {"morelights_vintage_hangingbulb.png^[lowpart:50:morelights_metal_dark_32.png"},
  use_texture_alpha = true,
  collision_box = {
    type = "fixed",
    fixed = {-1/8, -1/8, -1/8, 1/8, 1/2, 1/8}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/8, -1/8, -1/8, 1/8, 1/2, 1/8}
  },
  paramtype = "light",
  light_source = 10,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_vintage:oillamp", {
  description = "Vintage Oil Lamp",
  drawtype = "mesh",
  mesh = "morelights_vintage_oillamp.obj",
  tiles = {{name = "morelights_vintage_oil_flame.png",
    animation = {type = "sheet_2d", frames_w = 16, frames_h = 1, frame_length = 0.3}},
    "morelights_vintage_oillamp.png",
    "morelights_vintage_brass_32.png"},
  collision_box = {
    type = "fixed",
    fixed = {-1/8, -1/2, -1/8, 1/8, 1/4, 1/8}
  },
  selection_box = {
    type = "fixed",
    fixed = {-1/8, -1/2, -1/8, 1/8, 1/4, 1/8}
  },
  paramtype = "light",
  light_source = 8,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

minetest.register_node("morelights_vintage:chandelier", {
  description = "Vintage Chandelier",
  drawtype = "mesh",
  mesh = "morelights_vintage_chandelier.obj",
  tiles = {"morelights_vintage_chandelier.png",
    "morelights_vintage_brass_32.png^[multiply:#DFDFDF"},
  collision_box = {
    type = "fixed",
    fixed = {-3/8, -1/2, -3/8, 3/8, 1/2, 3/8}
  },
  selection_box = {
    type = "fixed",
    fixed = {-3/8, -1/2, -3/8, 3/8, 1/2, 3/8}
  },
  paramtype = "light",
  light_source = 10,
  groups = {cracky = 2, oddly_breakable_by_hand = 3},
  sounds = default.node_sound_glass_defaults(),
})

--
-- Craft recipes
--

minetest.register_craft({
  output = "morelights_vintage:chain_b",
  recipe = {
    {"", brass_ingot_name, ""},
    {"", "", ""},
    {"", brass_ingot_name, ""}
  }
})

minetest.register_craft({
  output = "morelights_vintage:block",
  recipe = {
    {"", "default:junglewood", ""},
    {morelights.glass, "morelights:bulb", morelights.glass},
    {"", "default:junglewood", ""}
  }
})

minetest.register_craft({
  output = "morelights_vintage:smallblock",
  recipe = {
    {"", morelights.glass, ""},
    {"default:junglewood", "morelights:bulb", "default:junglewood"}
  }
})

minetest.register_craft({
  output = "morelights_vintage:lantern_f",
  recipe = {
    {"", "default:steel_ingot", ""},
    {morelights.glass, "morelights:bulb", morelights.glass},
    {"default:stick", "default:steel_ingot", "default:stick"}
  }
})

minetest.register_craft({
  output = "morelights_vintage:hangingbulb",
  recipe = {
    {"", "default:steel_ingot", ""},
    {"", "default:copper_ingot", ""},
    {"", "morelights:bulb", ""}
  }
})

minetest.register_craft({
  output = "morelights_vintage:oillamp",
  recipe = {
    {"", "default:glass", ""},
    {"farming:cotton", brass_ingot_name, ""},
    {"", "default:glass", ""}
  }
})

minetest.register_craft({
  output = "morelights_vintage:chandelier",
  recipe = {
    {"", brass_ingot_name, ""},
    {"morelights:bulb", brass_ingot_name, "morelights:bulb"},
    {"default:steel_ingot", brass_ingot_name, "default:steel_ingot"}
  }
})


code:
root = true

[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true

[*.{lua,luacheckrc}]
indent_style = tab
indent_size = 4


code:
## Generic ignorable patterns and files
*~
debug.txt


code:
std = "lua51+minetest"
unused_args = false
allow_defined_top = true
max_line_length = 90

stds.minetest = {
	read_globals = {
		"DIR_DELIM",
		"minetest",
		"core",
		"dump",
		"vector",
		"nodeupdate",
		"VoxelManip",
		"VoxelArea",
		"PseudoRandom",
		"ItemStack",
		"default",
		table = {
			fields = {
				"copy",
			},
		},
	}
}

read_globals = {
	"carts",
	"farming",
	"frame",
	"intllib",
	"mg",
	"toolranks",
}


code:
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v2.3.0
    hooks:
      - id: end-of-file-fixer
      - id: trailing-whitespace

      - id: mixed-line-ending
        args: [--fix=lf]

  - repo: https://github.com/Calinou/pre-commit-luacheck
    rev: v1.0.0
    hooks:
      - id: luacheck


code:
dist: bionic
language: python

python:
  - 3.7.1

install:
  - sudo apt-get update -qq
  - sudo apt-get install -qqq luarocks
  - pip3 install pre-commit
  - luarocks install --local luacheck

script:
  # All linters are run with pre-commit hooks
  - export PATH="$HOME/.luarocks/bin:$PATH"
  - pre-commit run --all-files


code:
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Added

- More Ores tools now have [`toolranks`](https://github.com/lisacvuk/minetest-toolranks) support.
- Hungarian translation.

### Changed

- Migrated translations to the
  [Minetest translation file format](https://rubenwardy.com/minetest_modding_book/lua_api.html#translation-file-format).

## [2.0.0] - 2019-11-25

### Added

- More Ores nodes/items/tools can now be placed in item frames
  from the [`frame`](https://github.com/minetest-mods/frame) mod.
- Polish translation.

### Changed

- The minimum supported Minetest version is now 5.0.0.
- Copper rails are now registered using functions from the `carts` mod,
  making them interoperate seamlessly with default rails.
  - Copper rails can no longer be placed in the air.

## [1.1.0] - 2019-03-23

### Added

- Brazilian and Dutch translations.

### Changed

- Ores are now slower to mine and cannot be mined using wooden tools anymore.
- Updated intllib support to avoid using deprecated functions.

### Deprecated

- Deprecated hoes to follow Minetest Game's deprecation of hoes
  made of "rare" materials.
  - Hoes are still available in existing worlds, but they
    cannot be crafted anymore.

### Fixed

- Hoes now use the `farming` mod's handling function and can no longer
  turn desert sand into dirt.
- Handle tin which is now included in [Minetest Game](https://github.com/minetest/minetest_game).
  If it is detected, then the tin nodes and items from More Ores won't be registered.

## 1.0.0 - 2017-02-19

- Initial versioned release.

[Unreleased]: https://github.com/minetest-mods/moreores/compare/v2.0.0...HEAD
[2.0.0]: https://github.com/minetest-mods/moreores/compare/v1.1.0...v2.0.0
[1.1.0]: https://github.com/minetest-mods/moreores/compare/v1.0.0...v1.1.0


code:
# Contributing to More Ores

Thank you for your interest in More Ores! Before contributing,
be sure to know about these few guidelines:

- Contributions have to be licensed under the zlib license (or compatible)
  for code, and CC BY-SA 3.0 (or compatible) for assets.
- Make sure to update the changelog, keeping the
  [changelog format](http://keepachangelog.com/en/1.0.0/) we use.
- Don't bump the version yourself. Maintainers will do this when necessary.


code:
# More Ores

More Ores for [Minetest](https://www.minetest.net/), a free and open source infinite
world block sandbox game.

[**Forum topic**](https://forum.minetest.net/viewtopic.php?f=11&t=549)

## Installation

### Download the mod

To install More Ores, clone this Git repository into your Minetest's `mods/`
directory:

```bash
git clone https://github.com/minetest-mods/moreores.git
```

You can also
[download a ZIP archive](https://github.com/minetest-mods/moreores/archive/master.zip)
of More Ores.

### Enable the mod

Once you have installed More Ores, you need to enable it in Minetest.
The procedure is as follows:

#### Using the client's main menu

This is the easiest way to enable More Ores when playing in singleplayer
(or on a server hosted from a client).

1. Start Minetest and switch to the **Local Game** tab.
2. Select the world you want to enable More Ores in.
3. Click **Configure**, then enable `moreores` by double-clicking it
   (or ticking the **Enabled** checkbox).
4. Save the changes, then start a game on the world you enabled More Ores on.
5. More Ores should now be running on your world.

#### Using a text editor

This is the recommended way to enable the mod on a server without using a GUI.

1. Make sure Minetest is not currently running (otherwise, it will overwrite
   the changes when exiting).
2. Open the world's `world.mt` file using a text editor.
3. Add the following line at the end of the file:

```text
load_mod_moreores = true
```

If the line is already present in the file, then replace `false` with `true`
on that line.

4. Save the file, then start a game on the world you enabled More Ores on.
5. More Ores should now be running on your world.

## Version compatibility

More Ores is currently primarily tested with Minetest 5.1.0.
It may or may not work with newer or older versions. Issues arising in older
versions than 5.0.0 will generally not be fixed.

## License

Copyright © 2011-2020 Hugo Locurcio and contributors

- More Ores code is licensed under the zlib license, see
  [`LICENSE.md`](LICENSE.md) for details.
- Unless otherwise specified, More Ores textures are licensed under
  [CC BY-SA 3.0 Unported](https://creativecommons.org/licenses/by-sa/3.0/).


code:
------------------------------------------------------------------------------
------------------------------ CONFIGURATION ---------------------------------
------------------------------------------------------------------------------

------------------------------------------------------------------------------
-------- Change settings by changing the values after the "=". ---------------
------------------------------------------------------------------------------

-- Chunk sizes for ore generation (bigger = ore deposits are more scattered around)
moreores.tin_chunk_size = 7
moreores.silver_chunk_size = 11
moreores.mithril_chunk_size = 11

-- Amount of ore per chunk (higher = bigger ore deposits)
moreores.tin_ore_per_chunk = 3
moreores.silver_ore_per_chunk = 4
moreores.mithril_ore_per_chunk = 1

-- Minimal depths of ore generation (Y coordinate, 0 being sea level by default)
moreores.tin_min_depth = -31000
moreores.silver_min_depth = -31000
moreores.mithril_min_depth = -31000

-- Maximal depths of ore generation (Y coordinate, 0 being sea level by default)
moreores.tin_max_depth = 8
moreores.silver_max_depth = -2
moreores.mithril_max_depth = -512


code:
--[[
=====================================================================
** More Ores **
By Calinou, with the help of Nore.

Copyright © 2011-2020 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
=====================================================================
--]]

moreores = {}

local modpath = minetest.get_modpath("moreores")

local S = minetest.get_translator("moreores")
moreores.S = S

dofile(modpath .. "/_config.txt")

-- `mg` mapgen support
if minetest.get_modpath("mg") then
	dofile(modpath .. "/mg.lua")
end

-- `frame` support
local use_frame = minetest.get_modpath("frame")

local default_stone_sounds = default.node_sound_stone_defaults()
local default_metal_sounds = default.node_sound_metal_defaults()

-- Returns the crafting recipe table for a given material and item.
local function get_recipe(material, item)
	if item == "sword" then
		return {
			{material},
			{material},
			{"group:stick"},
		}
	end
	if item == "shovel" then
		return {
			{material},
			{"group:stick"},
			{"group:stick"},
		}
	end
	if item == "axe" then
		return {
			{material, material},
			{material, "group:stick"},
			{"", "group:stick"},
		}
	end
	if item == "pick" then
		return {
			{material, material, material},
			{"", "group:stick", ""},
			{"", "group:stick", ""},
		}
	end
	if item == "block" then
		return {
			{material, material, material},
			{material, material, material},
			{material, material, material},
		}
	end
	if item == "lockedchest" then
		return {
			{"group:wood", "group:wood", "group:wood"},
			{"group:wood", material, "group:wood"},
			{"group:wood", "group:wood", "group:wood"},
		}
	end
end

local function add_ore(modname, description, mineral_name, oredef)
	local img_base = modname .. "_" .. mineral_name
	local toolimg_base = modname .. "_tool_"..mineral_name
	local tool_base = modname .. ":"
	local tool_post = "_" .. mineral_name
	local item_base = tool_base .. mineral_name
	local ingot = item_base .. "_ingot"
	local lump_item = item_base .. "_lump"

	if oredef.makes.ore then
		minetest.register_node(modname .. ":mineral_" .. mineral_name, {
			description = S("@1 Ore", S(description)),
			tiles = {"default_stone.png^" .. modname .. "_mineral_" .. mineral_name .. ".png"},
			groups = {cracky = 2},
			sounds = default_stone_sounds,
			drop = lump_item,
		})

		if use_frame then
			frame.register(modname .. ":mineral_" .. mineral_name)
		end
	end

	if oredef.makes.block then
		local block_item = item_base .. "_block"
		minetest.register_node(block_item, {
			description = S("@1 Block", S(description)),
			tiles = {img_base .. "_block.png"},
			groups = {snappy = 1, bendy = 2, cracky = 1, melty = 2, level = 2},
			sounds = default_metal_sounds,
		})
		minetest.register_alias(mineral_name.."_block", block_item)
		if oredef.makes.ingot then
			minetest.register_craft( {
				output = block_item,
				recipe = get_recipe(ingot, "block")
			})
			minetest.register_craft( {
				output = ingot .. " 9",
				recipe = {
					{block_item},
				}
			})
		end
		if use_frame then
			frame.register(block_item)
		end
	end

	if oredef.makes.lump then
		minetest.register_craftitem(lump_item, {
			description = S("@1 Lump", S(description)),
			inventory_image = img_base .. "_lump.png",
		})
		minetest.register_alias(mineral_name .. "_lump", lump_item)
		if oredef.makes.ingot then
			minetest.register_craft({
				type = "cooking",
				output = ingot,
				recipe = lump_item,
			})
		end
		if use_frame then
			frame.register(lump_item)
		end
	end

	if oredef.makes.ingot then
		minetest.register_craftitem(ingot, {
			description = S("@1 Ingot", S(description)),
			inventory_image = img_base .. "_ingot.png",
		})
		minetest.register_alias(mineral_name .. "_ingot", ingot)
		if use_frame then
			frame.register(ingot)
		end
	end

	if oredef.makes.chest then
		minetest.register_craft( {
			output = "default:chest_locked",
			recipe = {
				{ingot},
				{"default:chest"},
			}
		})
		minetest.register_craft( {
			output = "default:chest_locked",
			recipe = get_recipe(ingot, "lockedchest")
		})
	end

	oredef.oredef.ore_type = "scatter"
	oredef.oredef.ore = modname .. ":mineral_" .. mineral_name
	oredef.oredef.wherein = "default:stone"

	minetest.register_ore(oredef.oredef)

	for tool_name, tooldef in pairs(oredef.tools) do
		local tdef = {
			description = "",
			inventory_image = toolimg_base .. tool_name .. ".png",
			tool_capabilities = {
				max_drop_level = 3,
				groupcaps = tooldef,
			},
			sound = {breaks = "default_tool_breaks"},
		}

		if tool_name == "sword" then
			tdef.tool_capabilities.full_punch_interval = oredef.full_punch_interval
			tdef.tool_capabilities.damage_groups = oredef.damage_groups
			tdef.description = S("@1 Sword", S(description))
		end

		if tool_name == "pick" then
			tdef.tool_capabilities.full_punch_interval = oredef.full_punch_interval
			tdef.tool_capabilities.damage_groups = oredef.damage_groups
			tdef.description = S("@1 Pickaxe", S(description))
		end

		if tool_name == "axe" then
			tdef.tool_capabilities.full_punch_interval = oredef.full_punch_interval
			tdef.tool_capabilities.damage_groups = oredef.damage_groups
			tdef.description = S("@1 Axe", S(description))
		end

		if tool_name == "shovel" then
			tdef.full_punch_interval = oredef.full_punch_interval
			tdef.tool_capabilities.damage_groups = oredef.damage_groups
			tdef.description = S("@1 Shovel", S(description))
			tdef.wield_image = toolimg_base .. tool_name .. ".png^[transformR90"
		end

		local fulltool_name = tool_base .. tool_name .. tool_post

		if tool_name == "hoe" and minetest.get_modpath("farming") then
			tdef.max_uses = tooldef.uses
			tdef.description = S("@1 Hoe", S(description))
			farming.register_hoe(fulltool_name, tdef)
		end

		-- Hoe registration is handled above.
		-- There are no crafting recipes for hoes, as they have been
		-- deprecated from Minetest Game:
		-- https://github.com/minetest/minetest_game/commit/9c459e77a
		if tool_name ~= "hoe" then
			minetest.register_tool(fulltool_name, tdef)

			if oredef.makes.ingot then
				minetest.register_craft({
					output = fulltool_name,
					recipe = get_recipe(ingot, tool_name)
				})
			end
		end

		-- Toolranks support
		if minetest.get_modpath("toolranks") then
			minetest.override_item(fulltool_name, {
				original_description = tdef.description,
				description = toolranks.create_description(tdef.description, 0, 1),
				after_use = toolranks.new_afteruse})
		end

		minetest.register_alias(tool_name .. tool_post, fulltool_name)
		if use_frame then
			frame.register(fulltool_name)
		end
	end
end

local oredefs = {
	silver = {
		description = "Silver",
		makes = {ore = true, block = true, lump = true, ingot = true, chest = true},
		oredef = {
			clust_scarcity = moreores.silver_chunk_size ^ 3,
			clust_num_ores = moreores.silver_ore_per_chunk,
			clust_size = moreores.silver_chunk_size,
			y_min = moreores.silver_min_depth,
			y_max = moreores.silver_max_depth,
		},
		tools = {
			pick = {
				cracky = {times = {[1] = 2.60, [2] = 1.00, [3] = 0.60}, uses = 100, maxlevel = 1},
			},
			hoe = {
				uses = 300,
			},
			shovel = {
				crumbly = {times = {[1] = 1.10, [2] = 0.40, [3] = 0.25}, uses = 100, maxlevel = 1},
			},
			axe = {
				choppy = {times = {[1] = 2.50, [2] = 0.80, [3] = 0.50}, uses = 100, maxlevel = 1},
				fleshy = {times = {[2] = 1.10, [3] = 0.60}, uses = 100, maxlevel = 1}
			},
			sword = {
				fleshy = {times = {[2] = 0.70, [3] = 0.30}, uses = 100, maxlevel = 1},
				snappy = {times = {[2] = 0.70, [3] = 0.30}, uses = 100, maxlevel = 1},
				choppy = {times = {[3] = 0.80}, uses = 100, maxlevel = 0},
			},
		},
		full_punch_interval = 1.0,
		damage_groups = {fleshy = 6},
	},
	mithril = {
		description = "Mithril",
		makes = {ore = true, block = true, lump = true, ingot = true, chest = false},
		oredef = {
			clust_scarcity = moreores.mithril_chunk_size ^ 3,
			clust_num_ores = moreores.mithril_ore_per_chunk,
			clust_size = moreores.mithril_chunk_size,
			y_min = moreores.mithril_min_depth,
			y_max = moreores.mithril_max_depth,
		},
		tools = {
			pick = {
				cracky = {times = {[1] = 2.25, [2] = 0.55, [3] = 0.35}, uses = 200, maxlevel = 2}
			},
			hoe = {
				uses = 1000,
			},
			shovel = {
				crumbly = {times = {[1] = 0.70, [2] = 0.35, [3] = 0.20}, uses = 200, maxlevel = 2},
			},
			axe = {
				choppy = {times = {[1] = 1.75, [2] = 0.45, [3] = 0.45}, uses = 200, maxlevel = 2},
				fleshy = {times = {[2] = 0.95, [3] = 0.30}, uses = 200, maxlevel = 1}
			},
			sword = {
				fleshy = {times = {[2] = 0.65, [3] = 0.25}, uses = 200, maxlevel = 2},
				snappy = {times = {[2] = 0.70, [3] = 0.25}, uses = 200, maxlevel = 2},
				choppy = {times = {[3] = 0.65}, uses = 200, maxlevel = 0},
			},
		},
		full_punch_interval = 0.45,
		damage_groups = {fleshy = 9},
	}
}

-- If tin is available in the `default` mod, don't register More Ores' variant of tin
local default_tin
if minetest.registered_items["default:tin_ingot"] then
	default_tin = true
else
	default_tin = false
end

if default_tin then
	minetest.register_alias("moreores:mineral_tin", "default:stone_with_tin")
	minetest.register_alias("moreores:tin_lump", "default:tin_lump")
	minetest.register_alias("moreores:tin_ingot", "default:tin_ingot")
	minetest.register_alias("moreores:tin_block", "default:tinblock")
else
	oredefs.tin = {
		description = "Tin",
		makes = {ore = true, block = true, lump = true, ingot = true, chest = false},
		oredef = {
			clust_scarcity = moreores.tin_chunk_size ^ 3,
			clust_num_ores = moreores.tin_ore_per_chunk,
			clust_size = moreores.tin_chunk_size,
			y_min = moreores.tin_min_depth,
			y_max = moreores.tin_max_depth,
		},
		tools = {},
	}

	-- Bronze has some special cases, because it is made from copper and tin
	minetest.register_craft({
		type = "shapeless",
		output = "default:bronze_ingot 3",
		recipe = {
			"moreores:tin_ingot",
			"default:copper_ingot",
			"default:copper_ingot",
		},
	})
end

-- Copper rail (unique node)
if minetest.get_modpath("carts") then
	carts:register_rail("moreores:copper_rail", {
		description = S("Copper Rail"),
		tiles = {
			"moreores_copper_rail.png",
			"moreores_copper_rail_curved.png",
			"moreores_copper_rail_t_junction.png",
			"moreores_copper_rail_crossing.png",
		},
		inventory_image = "moreores_copper_rail.png",
		wield_image = "moreores_copper_rail.png",
		groups = carts:get_rail_groups(),
	}, {})
end

minetest.register_craft({
	output = "moreores:copper_rail 24",
	recipe = {
		{"default:copper_ingot", "", "default:copper_ingot"},
		{"default:copper_ingot", "group:stick", "default:copper_ingot"},
		{"default:copper_ingot", "", "default:copper_ingot"},
	},
})

for orename, def in pairs(oredefs) do
	-- Register everything
	add_ore("moreores", def.description, orename, def)
end


code:
# textdomain: moreores

# Translation by Xanthin

[moreores] loaded.=[moreores] geladen.

@1 Ore=@1erz
@1 Lump=@1klumpen
@1 Ingot=@1barren
@1 Block=@1block
@1 Pickaxe=@1spitzhacke
@1 Shovel=@1schaufel
@1 Axe=@1axt
@1 Sword=@1schwert

Copper=Kupfer
Tin=Zinn
Bronze=Bronze
Silver=Silber
Gold=Gold
Mithril=Mithril
Copper Rail=Kupferschiene


code:
# textdomain: moreores

[moreores] loaded.=[moreores] loaded.

@1 Ore=@1 Ore
@1 Lump=@1 Lump
@1 Ingot=@1 Ingot
@1 Block=@1 Block
@1 Pickaxe=@1 Pickaxe
@1 Shovel=@1 Shovel
@1 Axe=@1 Axe
@1 Sword=@1 Sword
@1 Hoe=@1 Hoe

Copper=Copper
Tin=Tin
Bronze=Bronze
Silver=Silver
Gold=Gold
Mithril=Mithril
Copper Rail=Copper Rail


code:
# textdomain: moreores

# Translation by kaeza

[moreores] loaded.=[moreores] cargado.

@1 Ore=Mineral de @1
@1 Lump=Pepita de @1
@1 Ingot=Lingote de @1
@1 Block=Bloque de @1
@1 Pickaxe=Pico de @1
@1 Shovel=Pala de @1
@1 Axe=Hacha de @1
@1 Sword=Espada de @1

Copper=cobre
Tin=estaño
Bronze=bronce
Silver=plata
Gold=oro
Mithril=mitrilo
Copper Rail=Riel de Cobre


code:
# textdomain: moreores

# Translation by Calinou

[moreores] loaded.=[moreores] a été chargé.

@1 Ore=Minerai en @1
@1 Lump=Roche en @1
@1 Ingot=Lingot en @1
@1 Block=Bloc en @1
@1 Pickaxe=Pioche en @1
@1 Shovel=Pelle en @1
@1 Axe=Hache en @1
@1 Sword=Épée en @1
@1 Hoe=Houe en @1

Copper=cuivre
Tin=étain
Bronze=bronze
Silver=argent
Gold=or
Mithril=mithril
Copper Rail=Rail en cuivre


code:
# textdomain: moreores

# Translation by An0n3m0us

[moreores] loaded.=[moreores] betöltve.

@1 Ore=@1 érc
@1 Lump=@1 rög
@1 Ingot=@1 öntvény
@1 Block=@1 blokk
@1 Pickaxe=@1 csákány
@1 Shovel=@1 ásó
@1 Axe=@1 fejsze
@1 Sword=@1 kard

Copper=Réz
Tin=Ón
Bronze=Bronz
Silver=Ezüst
Gold=Arany
Mithril=Mithril
Copper Rail=Réz sín


code:
# textdomain: moreores

# Translation by Pagliaccio

[moreores] loaded.=[moreores] caricato.

@1 Ore=Minerale di @1
@1 Lump=@1 grezzo
@1 Ingot=Lingotto di @1
@1 Block=Blocco di @1
@1 Pickaxe=Piccone di @1
@1 Shovel=Badile di @1
@1 Axe=Ascia di @1
@1 Sword=Spada di @1

Copper=Rame
Tin=Stagno
Bronze=Bronzo
Silver=Argento
Gold=Oro
Mithril=Mithril
Copper Rail=Binario di rame


code:
# textdomain: moreores

[moreores] loaded.=[moreores] geladen.

@1 Ore=@1 Erts
@1 Lump=@1 Klomp
@1 Ingot=@1 Staaf
@1 Block=@1 Blok
@1 Pickaxe=@1 Pikhouweel
@1 Shovel=@1 Schep
@1 Axe=@1 Bijl
@1 Sword=@1 Zwaard

Copper=Koper
Tin=Tin
Bronze=Brons
Silver=Silver
Gold=Goud
Mithril=Mithril


code:
# textdomain: moreores

# Translation by mat9117

[moreores] loaded.=[moreores] załadowano.

@1 Ore=@1 Ruda
@1 Lump=@1 Bryłka
@1 Ingot=@1 Sztabka
@1 Block=@1 Blok
@1 Pickaxe=@1 Kilof
@1 Shovel=@1 Łopatka
@1 Axe=@1 Siekiera
@1 Sword=@1 Miecz

Copper=Miedź
Tin=Cyna
Bronze=Brąz
Silver=Srebro
Gold=Złoto
Mithril=Mithril
Copper Rail=Miedziany tor


code:
# textdomain: moreores

# Translation by github.com/caiorrs

[moreores] loaded.=[moreores] carregado.

@1 Ore=Minério de @1
@1 Lump=Pepita de @1
@1 Ingot=Lingote de @1
@1 Block=Bloco de @1
@1 Pickaxe=Picareta de @1
@1 Shovel=Pá de @1
@1 Axe=Machado de @1
@1 Sword=Espada de @1

Copper=Cobre
Tin=Estanho
Bronze=Bronze
Silver=Prata
Gold=Ouro
Mithril=Mitrilo

Copper Rail=Trilho de Cobre


code:
# textdomain: moreores

# Translation by Mahmutelmas06
# mahmutelmas06@hotmail.com

# Türkçe Çeviri
# Turkish translation
# Language 2 letter iso code is "tr"

[moreores] loaded.=[moreores] yüklendi.

@1 Ore=@1 madeni
@1 Lump=@1 yığını
@1 Ingot=@1 külçesi
@1 Block=@1 blok
@1 Pickaxe=@1 kazma
@1 Shovel=@1 kürek
@1 Axe=@1 balta
@1 Sword=@1 kılıç

Copper=Bakır
Tin=Kalay
Bronze=Bronz
Silver=Gümüş
Gold=Altın
Mithril=Mithril

Copper Rail=Bakır ray


code:
--[[
More Ores: `mg` mod support

Copyright © 2011-2020 Hugo Locurcio and contributors.
Licensed under the zlib license. See LICENSE.md for more information.
--]]

if not minetest.registered_items["default:tin_ingot"] then
	mg.register_ore({
		name = "moreores:mineral_tin",
		wherein = "default:stone",
		seeddiff = 8,
		maxvdistance = 10.5,
		maxheight = 8,
		seglenghtn = 15,
		seglenghtdev = 6,
		segincln = 0,
		segincldev = 0.6,
		turnangle = 57,
		forkturnangle = 57,
		numperblock = 2
	})
end

mg.register_ore({
	name = "moreores:mineral_silver",
	wherein = "default:stone",
	seeddiff = 9,
	maxvdistance = 10.5,
	maxheight = -2,
	seglenghtn = 15,
	seglenghtdev = 6,
	sizen = 60,
	sizedev = 30,
	segincln = 0,
	segincldev = 0.6,
	turnangle = 57,
	forkturnangle = 57,
	numperblock = 2
})

mg.register_ore({
	name = "moreores:mineral_mithril",
	wherein = "default:stone",
	seeddiff = 10,
	maxvdistance = 10.5,
	maxheight = -512,
	seglenghtn = 2,
	seglenghtdev = 4,
	sizen = 12,
	sizedev = 5,
	segincln = 0,
	segincldev = 0.6,
	turnangle = 57,
})


code:
name = moreores
description = Adds new ore types.
depends = default
optional_depends = carts,farming,frame,mg,toolranks
min_minetest_version = 5.0.0


code:
## Files related to minetest development cycle
/*.patch
# GNU Patch reject file
*.rej

## Editors and Development environments
*~
*.swp
*.bak*
*.orig
# Vim
*.vim
# Kate
.*.kate-swp
.swp.*
# Eclipse (LDT)
.project
.settings/
.buildpath
.metadata
# Idea IDE
.idea/*


code:
This mod uses nodeboxes to supply a complete set of 3D pipes and tubes,
along devices that work with them.

See https://gitlab.com/VanessaE/pipeworks/wikis/ for detailed information about usage of this mod.

Unlike the previous version of this mod, these pipes are rounded, and when
placed, they'll automatically join together as needed.  Pipes can go vertically
or horizontally, and there are enough nodes defined to allow for all possible
connections.  Valves and pumps can only be placed horizontally, and will
automatically rotate and join with neighboring pipes as objects are added, as
well as joining with each other under certain circumstances.

Pipes come in two variants: one type bears one or more dark windows on each
pipe, suggesting they're empty, while the other type bears green-tinted
windows, as if full (the two colors should also be easy to select if you want
to change them in a paint program).  These windows only appear on straight
lengths and on certain junctions.

This mod is a work in progress.

Please note that owing to the nature of this mod, I have opted to use 64px
textures.  Anything less just looks terrible.

path: mods/pipeworks/README


code:
local S = minetest.get_translator("pipeworks")
local autocrafterCache = {}  -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second

local craft_time = 1

local function count_index(invlist)
	local index = {}
	for _, stack in pairs(invlist) do
		if not stack:is_empty() then
			local stack_name = stack:get_name()
			index[stack_name] = (index[stack_name] or 0) + stack:get_count()
		end
	end
	return index
end

local function get_item_info(stack)
	local name = stack:get_name()
	local def = minetest.registered_items[name]
	local description = def and def.description or S("Unknown item")
	return description, name
end

local function get_craft(pos, inventory, hash)
	local hash = hash or minetest.hash_node_position(pos)
	local craft = autocrafterCache[hash]
	if not craft then
		local recipe = inventory:get_list("recipe")
		local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
		craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
		autocrafterCache[hash] = craft
	end
	return craft
end

local function autocraft(inventory, craft)
	if not craft then return false end
	local output_item = craft.output.item

	-- check if we have enough room in dst
	if not inventory:room_for_item("dst", output_item) then	return false end
	local consumption = craft.consumption
	local inv_index = count_index(inventory:get_list("src"))
	-- check if we have enough material available
	for itemname, number in pairs(consumption) do
		if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
	end
	-- consume material
	for itemname, number in pairs(consumption) do
		for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
			inventory:remove_item("src", ItemStack(itemname))
		end
	end

	-- craft the result into the dst inventory and add any "replacements" as well
	inventory:add_item("dst", output_item)
	for i = 1, 9 do
		inventory:add_item("dst", craft.decremented_input.items[i])
	end
	return true
end

-- returns false to stop the timer, true to continue running
-- is started only from start_autocrafter(pos) after sanity checks and cached recipe
local function run_autocrafter(pos, elapsed)
	local meta = minetest.get_meta(pos)
	local inventory = meta:get_inventory()
	local craft = get_craft(pos, inventory)
	local output_item = craft.output.item
	-- only use crafts that have an actual result
	if output_item:is_empty() then
		meta:set_string("infotext", S("unconfigured Autocrafter: unknown recipe"))
		return false
	end

	for step = 1, math.floor(elapsed/craft_time) do
		local continue = autocraft(inventory, craft)
		if not continue then return false end
	end
	return true
end

local function start_crafter(pos)
	local meta = minetest.get_meta(pos)
	if meta:get_int("enabled") == 1 then
		local timer = minetest.get_node_timer(pos)
		if not timer:is_started() then
			timer:start(craft_time)
		end
	end
end

local function after_inventory_change(pos)
	start_crafter(pos)
end

-- note, that this function assumes allready being updated to virtual items
-- and doesn't handle recipes with stacksizes > 1
local function after_recipe_change(pos, inventory)
	local meta = minetest.get_meta(pos)
	-- if we emptied the grid, there's no point in keeping it running or cached
	if inventory:is_empty("recipe") then
		minetest.get_node_timer(pos):stop()
		autocrafterCache[minetest.hash_node_position(pos)] = nil
		meta:set_string("infotext", S("unconfigured Autocrafter"))
		inventory:set_stack("output", 1, "")
		return
	end
	local recipe_changed = false
	local recipe = inventory:get_list("recipe")

	local hash = minetest.hash_node_position(pos)
	local craft = autocrafterCache[hash]

	if craft then
		-- check if it changed
		local cached_recipe = craft.recipe
		for i = 1, 9 do
			if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
				autocrafterCache[hash] = nil -- invalidate recipe
				craft = nil
				break
			end
		end
	end

	craft = craft or get_craft(pos, inventory, hash)
	local output_item = craft.output.item
	local description, name = get_item_info(output_item)
	meta:set_string("infotext", S("'@1' Autocrafter (@2)", description, name))
	inventory:set_stack("output", 1, output_item)

	after_inventory_change(pos)
end

-- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
-- if minetest supports query by group one day, this might replace them
-- with a canonical version instead
local function normalize(item_list)
	for i = 1, #item_list do
		local name = item_list[i]
		if not minetest.registered_items[name] then
			item_list[i] = ""
		end
	end
	return item_list
end

local function on_output_change(pos, inventory, stack)
	if not stack then
		inventory:set_list("output", {})
		inventory:set_list("recipe", {})
	else
		local input = minetest.get_craft_recipe(stack:get_name())
		if not input.items or input.type ~= "normal" then return end
		local items, width = normalize(input.items), input.width
		local item_idx, width_idx = 1, 1
		for i = 1, 9 do
			if width_idx <= width then
				inventory:set_stack("recipe", i, items[item_idx])
				item_idx = item_idx + 1
			else
				inventory:set_stack("recipe", i, ItemStack(""))
			end
			width_idx = (width_idx < 3) and (width_idx + 1) or 1
		end
		-- we'll set the output slot in after_recipe_change to the actual result of the new recipe
	end
	after_recipe_change(pos, inventory)
end

-- returns false if we shouldn't bother attempting to start the timer again after this
local function update_meta(meta, enabled)
	local state = enabled and "on" or "off"
	meta:set_int("enabled", enabled and 1 or 0)
	local fs = 	"size[8,12]"..
			"list[context;recipe;0,0;3,3;]"..
			"image[3,1;1,1;gui_hb_bg.png^[colorize:#141318:255]"..
			"list[context;output;3,1;1,1;]"..
			"image_button[3,2;1,0.6;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" ..
			"list[context;src;0,4.5;8,3;]"..
			"list[context;dst;4,0;4,3;]"..
			default.gui_bg..
			default.gui_bg_img..
			default.gui_slots..
			default.get_hotbar_bg(0,8) ..
			"list[current_player;main;0,8;8,4;]" ..
			"listring[current_player;main]"..
			"listring[context;src]" ..
			"listring[current_player;main]"..
			"listring[context;dst]" ..
			"listring[current_player;main]"
	if minetest.get_modpath("digilines") then
		fs = fs.."field[1,3.5;4,1;channel;"..S("Channel")..";${channel}]"
		fs = fs.."button_exit[5,3.2;2,1;save;"..S("Save").."]"
	end
	meta:set_string("formspec",fs)

	-- toggling the button doesn't quite call for running a recipe change check
	-- so instead we run a minimal version for infotext setting only
	-- this might be more written code, but actually executes less
	local output = meta:get_inventory():get_stack("output", 1)
	if output:is_empty() then -- doesn't matter if paused or not
		meta:set_string("infotext", S("unconfigured Autocrafter"))
		return false
	end

	local description, name = get_item_info(output)
	local infotext = enabled and S("'@1' Autocrafter (@2)", description, name)
				or S("paused '@1' Autocrafter", description)

	meta:set_string("infotext", infotext)
	return enabled
end

-- 1st version of the autocrafter had actual items in the crafting grid
-- the 2nd replaced these with virtual items, dropped the content on update and set "virtual_items" to string "1"
-- the third added an output inventory, changed the formspec and added a button for enabling/disabling
-- so we work out way backwards on this history and update each single case to the newest version
local function upgrade_autocrafter(pos, meta)
	local meta = meta or minetest.get_meta(pos)
	local inv = meta:get_inventory()

	if inv:get_size("output") == 0 then -- we are version 2 or 1
		inv:set_size("output", 1)
		-- migrate the old autocrafters into an "enabled" state
		update_meta(meta, true)

		if meta:get_string("virtual_items") == "1" then -- we are version 2
			-- we already dropped stuff, so lets remove the metadatasetting (we are not being called again for this node)
			meta:set_string("virtual_items", "")
		else -- we are version 1
			local recipe = inv:get_list("recipe")
			if not recipe then return end
			for idx, stack in ipairs(recipe) do
				if not stack:is_empty() then
					minetest.add_item(pos, stack)
					stack:set_count(1)
					stack:set_wear(0)
					inv:set_stack("recipe", idx, stack)
				end
			end
		end

		-- update the recipe, cache, and start the crafter
		autocrafterCache[minetest.hash_node_position(pos)] = nil
		after_recipe_change(pos, inv)
	end
end

minetest.register_node("pipeworks:autocrafter", {
	description = S("Autocrafter"),
	drawtype = "normal",
	tiles = {"pipeworks_autocrafter.png"},
	groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
	tube = {insert_object = function(pos, node, stack, direction)
			local meta = minetest.get_meta(pos)
			local inv = meta:get_inventory()
			local added = inv:add_item("src", stack)
			after_inventory_change(pos)
			return added
		end,
		can_insert = function(pos, node, stack, direction)
			local meta = minetest.get_meta(pos)
			local inv = meta:get_inventory()
			return inv:room_for_item("src", stack)
		end,
		input_inventory = "dst",
		connect_sides = {left = 1, right = 1, front = 1, back = 1, top = 1, bottom = 1}},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		inv:set_size("src", 3*8)
		inv:set_size("recipe", 3*3)
		inv:set_size("dst", 4*3)
		inv:set_size("output", 1)
		update_meta(meta, false)
	end,
	on_receive_fields = function(pos, formname, fields, sender)
		if not pipeworks.may_configure(pos, sender) then return end
		local meta = minetest.get_meta(pos)
		if fields.on then
			update_meta(meta, false)
			minetest.get_node_timer(pos):stop()
		elseif fields.off then
			if update_meta(meta, true) then
				start_crafter(pos)
			end
		elseif fields.save then
			meta:set_string("channel",fields.channel)
		end
	end,
	can_dig = function(pos, player)
		upgrade_autocrafter(pos)
		local meta = minetest.get_meta(pos)
		local inv = meta:get_inventory()
		return (inv:is_empty("src") and inv:is_empty("dst"))
	end,
	after_place_node = pipeworks.scan_for_tube_objects,
	after_dig_node = function(pos)
		pipeworks.scan_for_tube_objects(pos)
	end,
	on_destruct = function(pos)
		autocrafterCache[minetest.hash_node_position(pos)] = nil
	end,
	allow_metadata_inventory_put = function(pos, listname, index, stack, player)
		if not pipeworks.may_configure(pos, player) then return 0 end
		upgrade_autocrafter(pos)
		local inv = minetest.get_meta(pos):get_inventory()
		if listname == "recipe" then
			stack:set_count(1)
			inv:set_stack(listname, index, stack)
			after_recipe_change(pos, inv)
			return 0
		elseif listname == "output" then
			on_output_change(pos, inv, stack)
			return 0
		end
		after_inventory_change(pos)
		return stack:get_count()
	end,
	allow_metadata_inventory_take = function(pos, listname, index, stack, player)
		if not pipeworks.may_configure(pos, player) then
			minetest.log("action", string.format("%s attempted to take from autocrafter at %s", player:get_player_name(), minetest.pos_to_string(pos)))
			return 0
		end
		upgrade_autocrafter(pos)
		local inv = minetest.get_meta(pos):get_inventory()
		if listname == "recipe" then
			inv:set_stack(listname, index, ItemStack(""))
			after_recipe_change(pos, inv)
			return 0
		elseif listname == "output" then
			on_output_change(pos, inv, nil)
			return 0
		end
		after_inventory_change(pos)
		return stack:get_count()
	end,
	allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
		if not pipeworks.may_configure(pos, player) then return 0 end
		upgrade_autocrafter(pos)
		local inv = minetest.get_meta(pos):get_inventory()
		local stack = inv:get_stack(from_list, from_index)

		if to_list == "output" then
			on_output_change(pos, inv, stack)
			return 0
		elseif from_list == "output" then
			on_output_change(pos, inv, nil)
			if to_list ~= "recipe" then
				return 0
			end -- else fall through to recipe list handling
		end

		if from_list == "recipe" or to_list == "recipe" then
			if from_list == "recipe" then
				inv:set_stack(from_list, from_index, ItemStack(""))
			end
			if to_list == "recipe" then
				stack:set_count(1)
				inv:set_stack(to_list, to_index, stack)
			end
			after_recipe_change(pos, inv)
			return 0
		end

		after_inventory_change(pos)
		return count
	end,
	on_timer = run_autocrafter,
	digiline = {
		receptor = {},
		effector = {
			action = function(pos,node,channel,msg)
				local meta = minetest.get_meta(pos)
				if channel ~= meta:get_string("channel") then return end
				if type(msg) == "table" then
					if #msg < 3 then return end
					local inv = meta:get_inventory()
					for y=0,2,1 do
						for x=1,3,1 do
							local slot = y*3+x
							if minetest.registered_items[msg[y+1][x]] then
								inv:set_stack("recipe",slot,ItemStack(msg[y+1][x]))
							else
								inv:set_stack("recipe",slot,ItemStack(""))
							end
						end
					end
					after_recipe_change(pos,inv)
				elseif msg == "off" then
					update_meta(meta, false)
					minetest.get_node_timer(pos):stop()
				elseif msg == "on" then
					if update_meta(meta, true) then
						start_crafter(pos)
					end
				elseif msg == "single" then
					run_autocrafter(pos,1)
				end
			end,
		},
	},
})

minetest.register_craft( {
	output = "pipeworks:autocrafter 2",
	recipe = {
	        { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" },
	        { "basic_materials:plastic_sheet", "default:steel_ingot", "basic_materials:plastic_sheet" },
	        { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" }
	},
})


code:
-- enable finite liquid in the presence of dynamic liquid to preserve water volume.
local enable = false

if minetest.get_modpath("dynamic_liquid") then
	pipeworks.logger("detected mod dynamic_liquid, enabling finite liquid flag")
	enable = true
end

pipeworks.toggles.finite_water = enable


code:
--[[

	autorouting for pipes

	To connect pipes to some node, include this in the node def...

	pipe_connections = {
		pattern = <string>,    -- if supplied, search for this pattern instead of the exact node name
		left   = <bool>,       -- true (or 1) if the left side of the node needs to connect to a pipe
		right  = <bool>,       -- or from the right side, etc.
		top    = <bool>,
		bottom = <bool>,
		front  = <bool>,
		back   = <bool>,
		left_param2   = <num>, -- the node must have this param2 to connect from the left
		right_param2  = <num>, -- or right, etc.
		top_param2    = <num>, -- Omit some or all of these to skip checking param2 for those sides
		bottom_param2 = <num>,
		front_param2  = <num>,
		back_param2   = <num>,
	},

	...then add,  pipeworks.scan_for_pipe_objects(pos)
	to your node's after_dig_node and after_place_node callbacks.

]]--

-- get the axis dir (just 6 faces) of target node, assumes the pipe is the axis

function pipeworks.get_axis_dir(nodetable, pattern)
	local pxm,pxp,pym,pyp,pzm,pzp

	if string.find(nodetable.nxm.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nxm.param2).x ~= 0 then
		pxm=1
	end

	if string.find(nodetable.nxp.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nxp.param2).x ~= 0 then
		pxp=1
	end

	if string.find(nodetable.nzm.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nzm.param2).z ~= 0 then
		pzm=1
	end

	if string.find(nodetable.nzp.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nzp.param2).z ~= 0 then
		pzp=1
	end

	if string.find(nodetable.nym.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nym.param2).y ~= 0 then
		pym=1
	end

	if string.find(nodetable.nyp.name, pattern)
	  and minetest.facedir_to_dir(nodetable.nyp.param2).y ~= 0 then
		pyp=1
	end
	local match = pxm or pxp or pym or pyp or pzm or pzp
	return match,pxm,pxp,pym,pyp,pzm,pzp
end

local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10}
local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0}

local function autoroute_pipes(pos)
	local nctr = minetest.get_node(pos)
	local state = "_empty"
	if (string.find(nctr.name, "pipeworks:pipe_") == nil) then return end
	if (string.find(nctr.name, "_loaded") ~= nil) then state = "_loaded" end
	local nsurround = pipeworks.scan_pipe_surroundings(pos)

	if nsurround == 0 then nsurround = 9 end
	minetest.swap_node(pos, {name = "pipeworks:pipe_"..tube_table[nsurround]..state,
				param2 = tube_table_facedirs[nsurround]})
end

function pipeworks.scan_for_pipe_objects(pos)
	autoroute_pipes({ x=pos.x-1, y=pos.y  , z=pos.z   })
	autoroute_pipes({ x=pos.x+1, y=pos.y  , z=pos.z   })
	autoroute_pipes({ x=pos.x  , y=pos.y-1, z=pos.z   })
	autoroute_pipes({ x=pos.x  , y=pos.y+1, z=pos.z   })
	autoroute_pipes({ x=pos.x  , y=pos.y  , z=pos.z-1 })
	autoroute_pipes({ x=pos.x  , y=pos.y  , z=pos.z+1 })
	autoroute_pipes(pos)
end

-- auto-rotation code for various devices the pipes attach to

function pipeworks.scan_pipe_surroundings(pos)
	local pxm=0
	local pxp=0
	local pym=0
	local pyp=0
	local pzm=0
	local pzp=0

	local nxm = minetest.get_node({ x=pos.x-1, y=pos.y  , z=pos.z   })
	local nxp = minetest.get_node({ x=pos.x+1, y=pos.y  , z=pos.z   })
	local nym = minetest.get_node({ x=pos.x  , y=pos.y-1, z=pos.z   })
	local nyp = minetest.get_node({ x=pos.x  , y=pos.y+1, z=pos.z   })
	local nzm = minetest.get_node({ x=pos.x  , y=pos.y  , z=pos.z-1 })
	local nzp = minetest.get_node({ x=pos.x  , y=pos.y  , z=pos.z+1 })

	local nodetable = {
		nxm = nxm,
		nxp = nxp,
		nym = nym,
		nyp = nyp,
		nzm = nzm,
		nzp = nzp
	}

-- standard handling for pipes...

	if string.find(nxm.name, "pipeworks:pipe_") then pxm=1 end
	if string.find(nxp.name, "pipeworks:pipe_") then pxp=1 end
	if string.find(nym.name, "pipeworks:pipe_") then pym=1 end
	if string.find(nyp.name, "pipeworks:pipe_") then pyp=1 end
	if string.find(nzm.name, "pipeworks:pipe_") then pzm=1 end
	if string.find(nzp.name, "pipeworks:pipe_") then pzp=1 end

-- Special handling for valves...

	local match,a,b,c,d,e,f = pipeworks.get_axis_dir(nodetable, "pipeworks:valve")
	if match then
		pxm = a or pxm
		pxp = b or pxp
		pym = c or pym
		pyp = d or pyp
		pzm = e or pzm
		pzp = f or pzp
	end

-- ...flow sensors...

	local match,a,b,c,d,e,f = pipeworks.get_axis_dir(nodetable, "pipeworks:flow_sensor")
	if match then
		pxm = a or pxm
		pxp = b or pxp
		pym = c or pym
		pyp = d or pyp
		pzm = e or pzm
		pzp = f or pzp
	end

-- ...sealed pipe entry/exit...

	local match,a,b,c,d,e,f = pipeworks.get_axis_dir(nodetable, "pipeworks:entry_panel")
	if match then
		pxm = a or pxm
		pxp = b or pxp
		pym = c or pym
		pyp = d or pyp
		pzm = e or pzm
		pzp = f or pzp
	end

-- ...straight-only pipe...

	local match,a,b,c,d,e,f = pipeworks.get_axis_dir(nodetable, "pipeworks:straight_pipe")
	if match then
		pxm = a or pxm
		pxp = b or pxp
		pym = c or pym
		pyp = d or pyp
		pzm = e or pzm
		pzp = f or pzp
	end

-- ... other nodes

	local def_left   = minetest.registered_nodes[nxp.name] -- the node that {pos} is to the left of (not the
	local def_right  = minetest.registered_nodes[nxm.name] -- ...note that is AT the left!), etc.
	local def_bottom = minetest.registered_nodes[nyp.name]
	local def_top    = minetest.registered_nodes[nym.name]
	local def_front  = minetest.registered_nodes[nzp.name]
	local def_back   = minetest.registered_nodes[nzm.name]

	if def_left and def_left.pipe_connections and def_left.pipe_connections.left
	  and (not def_left.pipe_connections.pattern or string.find(nxp.name, def_left.pipe_connections.pattern))
	  and (not def_left.pipe_connections.left_param2 or (nxp.param2 == def_left.pipe_connections.left_param2)) then
		pxp = 1
	end
	if def_right and def_right.pipe_connections and def_right.pipe_connections.right
	  and (not def_right.pipe_connections.pattern or string.find(nxm.name, def_right.pipe_connections.pattern))
	  and (not def_right.pipe_connections.right_param2 or (nxm.param2 == def_right.pipe_connections.right_param2)) then
		pxm = 1
	end
	if def_top and def_top.pipe_connections and def_top.pipe_connections.top
	  and (not def_top.pipe_connections.pattern or string.find(nym.name, def_top.pipe_connections.pattern))
	  and (not def_top.pipe_connections.top_param2 or (nym.param2 == def_top.pipe_connections.top_param2)) then
		pym = 1
	end
	if def_bottom and def_bottom.pipe_connections and def_bottom.pipe_connections.bottom
	  and (not def_bottom.pipe_connections.pattern or string.find(nyp.name, def_bottom.pipe_connections.pattern))
	  and (not def_bottom.pipe_connections.bottom_param2 or (nyp.param2 == def_bottom.pipe_connections.bottom_param2)) then
		pyp = 1
	end
	if def_front and def_front.pipe_connections and def_front.pipe_connections.front
	  and (not def_front.pipe_connections.pattern or string.find(nzp.name, def_front.pipe_connections.pattern))
	  and (not def_front.pipe_connections.front_param2 or (nzp.param2 == def_front.pipe_connections.front_param2)) then
		pzp = 1
	end
	if def_back and def_back.pipe_connections and def_back.pipe_connections.back
	  and (not def_back.pipe_connections.pattern or string.find(nzm.name, def_back.pipe_connections.pattern))
	  and (not def_back.pipe_connections.back_param2 or (nzm.param2 == def_back.pipe_connections.back_param2)) then
		pzm = 1
	end

	print("stage 2 returns "..pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp..
		" for nodes surrounding "..minetest.get_node(pos).name.." at "..minetest.pos_to_string(pos))
	return pxm+8*pxp+2*pym+16*pyp+4*pzm+32*pzp
end

function pipeworks.look_for_stackable_tanks(pos)
	local tym = minetest.get_node({ x=pos.x  , y=pos.y-1, z=pos.z   })

	if string.find(tym.name, "pipeworks:storage_tank_") ~= nil or
	    string.find(tym.name, "pipeworks:expansion_tank_") ~= nil then
		minetest.add_node(pos, { name =  "pipeworks:expansion_tank_0", param2 = tym.param2})
	end
end


code:
-- autorouting for pneumatic tubes

local function is_tube(nodename)
	return pipeworks.table_contains(pipeworks.tubenodes, nodename)
end

--a function for determining which side of the node we are on
local function nodeside(node, tubedir)
	if node.param2 < 0 or node.param2 > 23 then
		node.param2 = 0
	end

	local backdir = minetest.facedir_to_dir(node.param2)
	local back = pipeworks.vector_dot(backdir, tubedir)
	if back == 1 then
		return "back"
	elseif back == -1 then
		return "front"
	end

	local topdir = pipeworks.facedir_to_top_dir(node.param2)
	local top = pipeworks.vector_dot(topdir, tubedir)
	if top == 1 then
		return "top"
	elseif top == -1 then
		return "bottom"
	end

	local rightdir = pipeworks.facedir_to_right_dir(node.param2)
	local right = pipeworks.vector_dot(rightdir, tubedir)
	if right == 1 then
		return "right"
	else
		return "left"
	end
end

local vts = {0, 3, 1, 4, 2, 5}
local tube_table = {[0] = 1, 2, 2, 4, 2, 4, 4, 5, 2, 3, 4, 6, 4, 6, 5, 7, 2, 4, 3, 6, 4, 5, 6, 7, 4, 6, 6, 8, 5, 7, 7, 9, 2, 4, 4, 5, 3, 6, 6, 7, 4, 6, 5, 7, 6, 8, 7, 9, 4, 5, 6, 7, 6, 7, 8, 9, 5, 7, 7, 9, 7, 9, 9, 10}
local tube_table_facedirs = {[0] = 0, 0, 5, 0, 3, 4, 3, 0, 2, 0, 2, 0, 6, 4, 3, 0, 7, 12, 5, 12, 7, 4, 5, 5, 18, 20, 16, 0, 7, 4, 7, 0, 1, 8, 1, 1, 1, 13, 1, 1, 10, 8, 2, 2, 17, 4, 3, 6, 9, 9, 9, 9, 21, 13, 1, 1, 10, 10, 11, 2, 19, 4, 3, 0}
local function tube_autoroute(pos)
	local active = {0, 0, 0, 0, 0, 0}
	local nctr = minetest.get_node(pos)
	if not is_tube(nctr.name) then return end

	local adjustments = {
		{x = -1, y =  0, z =  0},
		{x =  1, y =  0, z =  0},
		{x =  0, y = -1, z =  0},
		{x =  0, y =  1, z =  0},
		{x =  0, y =  0, z = -1},
		{x =  0, y =  0, z =  1}
	}
	-- xm = 1, xp = 2, ym = 3, yp = 4, zm = 5, zp = 6

	local positions = {}
	local nodes = {}
	for i, adj in ipairs(adjustments) do
		positions[i] = vector.add(pos, adj)
		nodes[i] = minetest.get_node(positions[i])
	end

	for i, node in ipairs(nodes) do
		local idef = minetest.registered_nodes[node.name]
		-- handle the tubes themselves
		if is_tube(node.name) then
			active[i] = 1
		-- handle new style connectors
		elseif idef and idef.tube and idef.tube.connect_sides then
			local dir = adjustments[i]
			if idef.tube.connect_sides[nodeside(node, vector.multiply(dir, -1))] then
				active[i] = 1
			end
		end
	end

	-- all sides checked, now figure which tube to use.

	local nodedef = minetest.registered_nodes[nctr.name]
	local basename = nodedef.basename
	if nodedef.style == "old" then
		local nsurround = ""
		for i, n in ipairs(active) do
			nsurround = nsurround..n
		end
		nctr.name = basename.."_"..nsurround
	elseif nodedef.style == "6d" then
		local s = 0
		for i, n in ipairs(active) do
			if n == 1 then
				s = s + 2^vts[i]
			end
		end
		nctr.name = basename.."_"..tube_table[s]
		nctr.param2 = tube_table_facedirs[s]
	end
	minetest.swap_node(pos, nctr)
end

function pipeworks.scan_for_tube_objects(pos)
	for side = 0, 6 do
		tube_autoroute(vector.add(pos, pipeworks.directions.side_to_dir(side)))
	end
end

function pipeworks.after_place(pos)
	pipeworks.scan_for_tube_objects(pos)
end

function pipeworks.after_dig(pos)
	pipeworks.scan_for_tube_objects(pos)
end

-- Screwdriver calls this function before rotating a node.
-- However, connections must be updated *after* the node is rotated
-- So, this function does the rotation itself and returns `true`.
-- (Note: screwdriver already checks for protected areas.)

-- This should only be used for tubes that don't autoconnect.
-- (For example, one-way tubes.)
-- Autoconnecting tubes will just revert back to their original state
-- when they are updated.
function pipeworks.on_rotate(pos, node, user, mode, new_param2)
	node.param2 = new_param2
	minetest.swap_node(pos, node)
	pipeworks.scan_for_tube_objects(pos)
	return true
end

if minetest.get_modpath("mesecons_mvps") then
	mesecon.register_on_mvps_move(function(moved_nodes)
		for _, n in ipairs(moved_nodes) do
			pipeworks.scan_for_tube_objects(n.pos)
			pipeworks.scan_for_tube_objects(n.oldpos)
		end
	end)
end