code:
-- craft bones from animalmaterials into bonemeal
if minetest.get_modpath("animalmaterials") then

	minetest.register_craft({
		type = "shapeless",
		output = "bonemeal:bonemeal 2",
		recipe = {"animalmaterials:bone"}
	})
end

if farming and farming.mod and farming.mod == "redo" then

	bonemeal:add_crop({
		{"farming:tomato_", 8},
		{"farming:corn_", 8},
		{"farming:melon_", 8},
		{"farming:pumpkin_", 8},
		{"farming:beanpole_", 5},
		{"farming:blueberry_", 4},
		{"farming:raspberry_", 4},
		{"farming:carrot_", 8},
		{"farming:cocoa_", 4},
		{"farming:coffee_", 5},
		{"farming:cucumber_", 4},
		{"farming:potato_", 4},
		{"farming:grapes_", 8},
		{"farming:rhubarb_", 3},
		{"farming:barley_", 7},
		{"farming:hemp_", 8},
		{"farming:chili_", 8},
		{"farming:garlic_", 5},
		{"farming:onion_", 5},
		{"farming:pepper_", 5},
		{"farming:pineapple_", 8},
		{"farming:pea_", 5},
		{"farming:beetroot_", 5},
		{"farming:rye_", 8},
		{"farming:oat_", 8},
		{"farming:rice_", 8},
		{"farming:mint_", 4},
		{"farming:cabbage_", 6}
	})
end

if minetest.get_modpath("ethereal") then

	bonemeal:add_crop({
		{"ethereal:strawberry_", 8},
		{"ethereal:onion_", 5}
	})

	bonemeal:add_sapling({
		{"ethereal:palm_sapling", ethereal.grow_palm_tree, "soil"},
		{"ethereal:palm_sapling", ethereal.grow_palm_tree, "sand"},
		{"ethereal:yellow_tree_sapling", ethereal.grow_yellow_tree, "soil"},
		{"ethereal:big_tree_sapling", ethereal.grow_big_tree, "soil"},
		{"ethereal:banana_tree_sapling", ethereal.grow_banana_tree, "soil"},
		{"ethereal:frost_tree_sapling", ethereal.grow_frost_tree, "soil"},
		{"ethereal:mushroom_sapling", ethereal.grow_mushroom_tree, "soil"},
		{"ethereal:willow_sapling", ethereal.grow_willow_tree, "soil"},
		{"ethereal:redwood_sapling", ethereal.grow_redwood_tree, "soil"},
		{"ethereal:orange_tree_sapling", ethereal.grow_orange_tree, "soil"},
		{"ethereal:bamboo_sprout", ethereal.grow_bamboo_tree, "soil"},
		{"ethereal:birch_sapling", ethereal.grow_birch_tree, "soil"},
		{"ethereal:sakura_sapling", ethereal.grow_sakura_tree, "soil"}
	})

	local grass = {"default:grass_3", "default:grass_4", "default:grass_5", ""}

	bonemeal:add_deco({
		{"ethereal:crystal_dirt", {"ethereal:crystalgrass", "", "", "", ""}, {}},
		{"ethereal:fiery_dirt", {"ethereal:dry_shrub", "", "", "", ""}, {}},
		{"ethereal:prairie_dirt", grass, {"flowers:dandelion_white",
			"flowers:dandelion_yellow", "flowers:geranium", "flowers:rose",
			"flowers:tulip", "flowers:viola", "ethereal:strawberry_7"}},
		{"ethereal:gray_dirt", {}, {"ethereal:snowygrass", "", ""}},
		{"ethereal:cold_dirt", {}, {"ethereal:snowygrass", "", ""}},
		{"ethereal:mushroom_dirt", {}, {"flowers:mushroom_red", "flowers:mushroom_brown", "", "", ""}},
		{"ethereal:jungle_dirt", grass, {"default:junglegrass", "", "", ""}},
		{"ethereal:grove_dirt", grass, {"ethereal:fern", "", "", ""}},
		{"ethereal:bamboo_dirt", grass, {}}
	})
end

if minetest.get_modpath("moretrees") then

	-- special fir check for snow
	local function fir_grow(pos)

		if minetest.find_node_near(pos, 1,
			{"default:snow", "default:snowblock", "default:dirt_with_snow"}) then

			moretrees.grow_fir_snow(pos)
		else
			moretrees.grow_fir(pos)
		end
	end

	bonemeal:add_sapling({
		{"moretrees:beech_sapling", moretrees.spawn_beech_object, "soil"},
		{"moretrees:apple_tree_sapling", moretrees.spawn_apple_tree_object, "soil"},
		{"moretrees:oak_sapling", moretrees.spawn_oak_object, "soil"},
		{"moretrees:sequoia_sapling", moretrees.spawn_sequoia_object, "soil"},
		--{"moretrees:birch_sapling", moretrees.spawn_birch_object, "soil"},
		{"moretrees:birch_sapling", moretrees.grow_birch, "soil"},
		{"moretrees:palm_sapling", moretrees.spawn_palm_object, "soil"},
		{"moretrees:palm_sapling", moretrees.spawn_palm_object, "sand"},
		{"moretrees:date_palm_sapling", moretrees.spawn_date_palm_object, "soil"},
		{"moretrees:date_palm_sapling", moretrees.spawn_date_palm_object, "sand"},
		--{"moretrees:spruce_sapling", moretrees.spawn_spruce_object, "soil"},
		{"moretrees:spruce_sapling", moretrees.grow_spruce, "soil"},
		{"moretrees:cedar_sapling", moretrees.spawn_cedar_object, "soil"},
		{"moretrees:poplar_sapling", moretrees.spawn_poplar_object, "soil"},
		{"moretrees:willow_sapling", moretrees.spawn_willow_object, "soil"},
		{"moretrees:rubber_tree_sapling", moretrees.spawn_rubber_tree_object, "soil"},
		{"moretrees:fir_sapling", fir_grow, "soil"}
	})

elseif minetest.get_modpath("technic_worldgen") then

	bonemeal:add_sapling({
		{"moretrees:rubber_tree_sapling", technic.rubber_tree_model, "soil"}
	})
end

if minetest.get_modpath("caverealms") then

	local fil = minetest.get_modpath("caverealms") .. "/schematics/shroom.mts"
	local add_shroom = function(pos)

		minetest.swap_node(pos, {name = "air"})

		minetest.place_schematic(
			{x = pos.x - 5, y = pos.y, z = pos.z - 5}, fil, 0, nil, false)
	end

	bonemeal:add_sapling({
		{"caverealms:mushroom_sapling", add_shroom, "soil"}
	})
end

if minetest.get_modpath("dye") then

	local bonemeal_dyes = {
			bonemeal = "white", fertiliser = "green", mulch = "brown"}

	for mat, dye in pairs(bonemeal_dyes) do

		minetest.register_craft({
			output = "dye:" .. dye .. " 4",
			recipe = {
				{"bonemeal:" .. mat}
			},
		})
	end
end


code:
minetest_game mod: bouncy_beds
==============================

# Bouncy Bed
![screenshot](https://www.notabug.org/FreeGamers/bouncy_bed/raw/master/Screenshot.png)

## Description
Add some childish fun to the game by making the default beds bouncy! Yes it does exactly what it says on the tin! Enjoy reckless bounces by abusing your in-game mattresses and getting some airtime.

## How does it work?
The mod essentially just appends the bouncy and fall damage groups onto the default beds in the game and adds a cute bouncing sound! This creative mod was a suggestion from a player, kiopy7, in the server, Sara's Simple Survival Server. Thank you!

#### depends: beds

License of source code
------------------------------
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

https://www.gnu.org/licenses/gpl-3.0.html

License of the sound effect
-------------------
bouncy.ogg, Blender Foundation, CC-BY-3

repo_name: Desour/PlayMinetestServer

license: mit


code:
-- Override the attributes for beds:fancy_bed_bottom.
minetest.override_item("beds:fancy_bed_bottom", {
	groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1, fall_damage_add_percent=-40, bouncy=85},
	sounds = {
		footstep = { name = "bouncy", gain = 0.8 },
		dig = { name = "default_dig_oddly_breakable_by_hand", gain = 1.0 },
		dug = { name = "default_dug_node", gain = 1.0 },
	}
})
-- Override the attributes for beds:fancy_bed_top.
minetest.override_item("beds:fancy_bed_top", {
	groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2, fall_damage_add_percent=-40, bouncy=85},
        sounds = {
		footstep = { name = "bouncy", gain = 0.8 },
                dig = { name = "default_dig_oddly_breakable_by_hand", gain = 1.0 },
                dug = { name = "default_dug_node", gain = 1.0 },
        }
})

-- Override the attributes for beds:bed_bottom.
minetest.override_item("beds:bed_bottom", {
        groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 1, fall_damage_add_percent=-40, bouncy=85},
        sounds = {
                footstep = { name = "bouncy", gain = 0.8 },
                dig = { name = "default_dig_oddly_breakable_by_hand", gain = 1.0 },
                dug = { name = "default_dug_node", gain = 1.0 },
        }
})
-- Override the attributes for beds:bed_top.
minetest.override_item("beds:bed_top", {
        groups = {choppy = 2, oddly_breakable_by_hand = 2, flammable = 3, bed = 2, fall_damage_add_percent=-40, bouncy=85},
        sounds = {
                footstep = { name = "bouncy", gain = 0.8 },
                dig = { name = "default_dig_oddly_breakable_by_hand", gain = 1.0 },
                dug = { name = "default_dug_node", gain = 1.0 },
        }
})


code:
name = bouncy_bed
author = FreeGamers
description = Simply makes beds bouncy. A suggestion made by kiopy7.
depends = beds
release = 3920
title = Bouncy Bed


code:
# Carpets mod for minetest

This mod adds 15 colorized wool carpets to the minetest.

![](https://github.com/bell07/minetest-carpets/blob/master/screenshot.png)

Maintained version, based on https://forum.minetest.net/viewtopic.php?t=15459 and https://forum.minetest.net/viewtopic.php?f=11&t=11637

License: LGPL-2.1+.

The mod provides an api to register more carpets using template nodes
Example:
```lua
carpets.register('default:dirt', {description=S('Carpet dirt')}) -- registers carpet looks like dirt
```


code:
local carpet_proto = {
	drawtype = "nodebox",
	paramtype = "light",
	paramtype2 = "facedir",
	node_box = {
		type = "fixed",
		fixed = {-0.5, -0.5, -0.5, 0.5, -0.45, 0.5}
	},
	groups = {
		snappy = 2,
		flammable = 3,
		oddly_breakable_by_hand = 3,
		choppy = 2,
		carpet = 1,
	}
}

-- Register the carpet and recipe using material
--    material - already registered material item the textures and sounds applied from
--    def - optional additional - or overriding data passed to minetest.register_node()
carpets = {}

function carpets.register(material, def)
	local node = table.copy(carpet_proto)
	if def then
		for k,v in pairs(def) do
			node[k] = v
		end
	end

	local material_def = minetest.registered_nodes[material]
	node.description = node.description or material_def.description.." Carpet"
	node.sounds = table.copy(node.sounds or material_def.sounds or default.node_sound_defaults())
	node.groups = table.copy(node.groups)

	if node.tiles then
		node.tiles = table.copy(node.tiles)
	elseif material_def.tiles[6] then
		node.tiles = {material_def.tiles[6]}
	else
		node.tiles = table.copy(material_def.tiles)
	end

	local name = "carpet:" .. (node.name or material:gsub(":", "_"))
	node.name = nil

	minetest.register_node(":" .. name, node)

	minetest.register_craft({
		output = name .. " 32",
		recipe = {
			{"group:wool", "group:wool", "group:wool"},
			{"group:wool", material, "group:wool"}
		}
	})
end


code:
local modpath = minetest.get_modpath(minetest.get_current_modname())
local S = minetest.get_translator("carpets")
dofile(modpath .. "/api.lua")

if minetest.get_modpath("wool") then
	local nodes = {
		{name="wool:black", description=S("Black Carpet")},
		{name="wool:blue", description=S("Blue Carpet")},
		{name="wool:brown", description=S("Brown Carpet")},
		{name="wool:cyan", description=S("Cyan Carpet")},
		{name="wool:dark_green", description=S("Dark Green Carpet")},
		{name="wool:dark_grey", description=S("Dark Grey Carpet")},
		{name="wool:green", description=S("Green Carpet")},
		{name="wool:grey", description=S("Grey Carpet")},
		{name="wool:magenta", description=S("Magenta Carpet")},
		{name="wool:orange", description=S("Orange Carpet")},
		{name="wool:pink", description=S("Pink Carpet")},
		{name="wool:red", description=S("Red Carpet")},
		{name="wool:violet", description=S("Violet Carpet")},
		{name="wool:white", description=S("White Carpet")},
		{name="wool:yellow", description=S("Yellow Carpet")},
	}
	for _, node in ipairs(nodes) do
		carpets.register(node.name, {description=node.description})
	end
end


code:
# textdomain: carpets

### init.lua ###

Black Carpet=Tapis noir
Blue Carpet=Tapis bleu
Brown Carpet=Tapis marron
Cyan Carpet=Tapis cyan
Dark Green Carpet=Tapis vert foncé
Dark Grey Carpet=Tapis gris foncé
Green Carpet=Tapis vert
Grey Carpet=Tapis gris
Magenta Carpet=Tapis magenta
Orange Carpet=Tapis orange
Pink Carpet=Tapis rose
Red Carpet=Tapis rouge
Violet Carpet=Tapis violet
White Carpet=Tapis blanc
Yellow Carpet=Tapis jaune


code:
# textdomain: carpets

### init.lua ###

Black Carpet=
Blue Carpet=
Brown Carpet=
Cyan Carpet=
Dark Green Carpet=
Dark Grey Carpet=
Green Carpet=
Grey Carpet=
Magenta Carpet=
Orange Carpet=
Pink Carpet=
Red Carpet=
Violet Carpet=
White Carpet=
Yellow Carpet=


code:
name = carpets
description = Adds 16 colorized wool carpets to the minetest.
optional_depends = wool


code:
# Auto detect text files and perform LF normalization
* text=auto


code:
MultiCraft Game mod: cleaner
============================

Introduction
------------
This mod removes unknown items and entities from inventory and map.

License of source code
----------------------
- Copyright (C) 2019 Jean-Patrick Guerrero (kilbith) <jeanpatrick.guerrero@gmail.com>
- Copyright (C) 2019-2020 MultiCraft Development Team

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3.0 of the License, or
(at your option) any later version.

http://www.gnu.org/licenses/lgpl-3.0.html


code:
local radius = 8
local height = 4
local freq = 3
local kpos = {}
local enable_kpos = false

minetest.register_on_joinplayer(function(player)
	local inv = player:get_inventory()

	for i = 1, inv:get_size("main") do
		local stack = inv:get_stack("main", i)
		local itemname = stack:get_name()

		if not minetest.registered_items[itemname] or
		minetest.registered_items[itemname].name == "air" then
			inv:set_stack("main", i, "")
		end
	end
end)

local vnew = vector.new
local function clean()
	local players = minetest.get_connected_players()
	for i = 1, #players do
		local player = players[i]
		local pos = player:get_pos()

		for x = -radius, radius do
		for y = -height, height do
		for z = -radius, radius do
			local pos_scan = vnew(pos.x + x, pos.y + y, pos.z + z)
			local nodename = minetest.get_node(pos_scan).name

			if enable_kpos then
				local hash = minetest.hash_node_position(pos_scan)
				if not kpos[hash] then
					local nodename = minetest.get_node(pos_scan).name

					if not minetest.registered_nodes[nodename] then
						minetest.remove_node(pos_scan)
					end

					kpos[hash] = true
				end
			else
				if not minetest.registered_nodes[nodename] then
					minetest.remove_node(pos_scan)
				end
			end

			local objs = minetest.get_objects_inside_radius(pos_scan, 0.5)
			if #objs > 0 then
				for j = 1, #objs do
					local obj = objs[j]
					if not obj:is_player() then
						local entname = obj:get_entity_name()
						if not minetest.registered_entities[entname] then
							obj:remove()
						end
					end
				end
			end
		end
		end
		end
	end

	minetest.after(freq, clean)
end

minetest.after(freq, clean)


code:
name = cleaner
description = Lightweight remove unknown items and entities from inventory and map.


code:
local compressed_sound = default.node_sound_dirt_defaults()

local nb_iterations = 3

local function add_one_compression(p)
  def = {
    description = p["desc"],
    tiles = p["img"],
    groups = {dig_immediate=3},
    is_ground_content = false,
    sounds = compressed_sound
  }
  minetest.register_node(p["name"], def)

  recipe = {}
  for i=1,8 do
    recipe[i]=p["base"]
  end

  minetest.register_craft({
    output = p["name"],
    type = "shapeless",
    recipe = recipe
  })

  minetest.register_craft({
    output = p["base"].." 8",
    type = "shapeless",
    recipe = {p["name"]}
  })
end

local function shallow_copy(t)
  local t2 = {}
  for k,v in pairs(t) do
    t2[k] = v
  end
  return t2
end

local function mark_texture(t, i)
  mark = "^(compresser_"..i..".png^[opacity:200)"
  t = shallow_copy(t)
  if t["name"] then
    t["name"] = t["name"]..mark
  else
    k = 1
    while t[k] do
      t[k] = t[k]..mark
      k = k+1
    end
  end
  return t
end

local function add_compressions(p, n)
  -- Assume n>=1
  basenode = minetest.registered_nodes[p["base"]]
  p["img"] = basenode.tiles
  add_one_compression({
      desc="\27(compressed)8 "..p["description"],
      name="compresser:compressed1_"..p["name"],
      base=p["base"],
      img=mark_texture(p["img"],1)
    })
  for i=2,n do
    add_one_compression({
      desc="\27(compressed)8^"..i.." "..p["description"],
      name="compresser:compressed"..i.."_"..p["name"],
      base="compresser:compressed"..(i-1).."_"..p["name"],
      img=mark_texture(p["img"],i)
    })
  end
end

local function add_compressions_helper(base)
  basenode = minetest.registered_nodes[base]
  pos_col,_ = string.find(base,":")
  desc = basenode.description
  desc = desc:gsub("\27E", "")
  desc = desc:gsub("\27%(%w*@?%w*%)", "") -- Or keep it maybe?
  add_compressions({
    description=desc,
    name=string.sub(base,pos_col+1),
    base=base
  },nb_iterations)
end

local to_compress_default = {
"glass", "dirt", "stone",
"cobble", "gravel",
"bronzeblock", "coalblock", "copperblock", "diamondblock", "goldblock", "mese_block", "obsidian_block", "steelblock", "tinblock", "stone_block", "sandstone_block", "sand",
"acacia_tree", "tree","silver_sand", "silver_sandstone", "silver_sandstone_brick", "aspen_tree", "pine_tree", "acacia_wood", "wood", "aspen_wood", "pine_wood"
}

for _,p in ipairs(to_compress_default) do
  add_compressions_helper("default:"..p)
end

for i=1,nb_iterations do
  n = minetest.registered_nodes["compresser:compressed"..i.."_glass"]
  n = shallow_copy(n)
  n.drawtype = "glasslike_framed_optional"
  n.paramtype = "light"
  minetest.register_node("compresser:compressed"..i.."_glass", n)
  -- Doesn't work by modifying directly, I don't know why.
end


code:
name = compresser
description = Adds compression blocks.
depends = default


code:
minetest.register_craft( {
	output = "default:dirt_with_grass",
	type = "shapeless",
	recipe =
		{ "default:dirt", "default:grass_1"},
	})


code:
name = craftabledirtwithgrass
description = Adds a craft for Dirt with grass.
depends = default


code:
read_globals = {
	"vector",
	"screwdriver",
	"minetest",
	"default",
	"pipeworks",
	"dump",
	"VoxelArea",
}

globals = {
	"digilines",
}


code:
Basic idea: place this chest down at the end of a pipeline. Feed stuff into it. Attach a luacontroller to it with a digiline in between. Program the luacontroller to turn on a wire to stop the pipeline when the chest is full. Don't put more than one kind of item down the pipeline into the chest, unless you want weird tricksy behavior.

...[F]===[C]--{L}
    |__________|
   [B]
F: filter
B: blinky plant
C: digiline chest
L: luacontroller
==: pipe
__: mesecons
--: digiline

Make sure you use mem in the luacontroller to keep the mesecon wire on indefinitely after the chest signals full. When it signals "take" someone took an item out and you can start the pipeline up again.
This may be a bad idea if they only take half a stack or something. Oh well.

When you put something in, you get a "put" to indicate it's OK (sort of (still buggy)) and can fit inside the chest. When you get a "lost", that means it won't fit inside the chest, and will bounce, possibly popping out. When you get a "overflow" that means you tried to add something to a chest that just filled up, and the stack will bounce. When you get a "full" that means the chest just filled up.

"Filled up" for all intents and purposes, means taking the type of whatever just went into the chest, and seeing if at least 1 of that type can be added to the chest. If it cannot, then it's filled up. That means a chest full of stacks of 30 copper and one spot of 98 gold, and you add one gold to that, it will say it's full. Add 30 copper to it, and it won't.

Generally you'll be working with full stacks in pipeworks. Even the non-mese filters will accumulate items in a chest, and not spread them out into multiple stacks. And generally your destination chests will each have one of any kind of item. So all you have to worry about is when you've got 99 everywhere, and one space possibly free. A mese filter can fail on that in fact, for instance if you have room for 45 gold, and it tries to push a stack of 50 gold. All 50 will bounce! The code for chests isn't smart enough to add the 45 and bounce the leftover 5. So only use mese filters when you're sure a full stack has accumulated for the filter to push, and there are no partial stacks at the destination.

For some reason when an "overflow" happens, when it checks if the stack can fit inside the chest, the answer is yes it can fit! Then it doesn't. Sort of buggy.

itemstack - the qualified name, a space, then the amount. If the space and amount are ommitted, that represents just 1.

examples: "default:chest 33" "default:coal" "default:axe_diamond"

bounce
    - when an item cannot enter the destination container it will travel back up the tube it came from, going along alternate routes if they exist, but otherwise popping out of the tube.

popping out
    - the little thingy travelling through the tube disappears, and an entity of the item appears, as if it was just dropped. This entity can expire, losing your items permanently!

The messages are:

put <itemstack>
    - this means that the inventory claimed it could fit that stack of items inside it. Inventories lie. But with the above caveats this is quite usable.
lost <itemstack>
    - the stack couldn't fit in the chest and bounces.
full <itemstack> <count>
    - the chest has been filled. The itemstack is what filled it. count is what's leftover.
      until chests can suck up part of a stack and not bounce the whole stack, that count will
      always be 0
overflow <itemstack> <count>
    - generally this is the same as lost, except that the "put" event happened, meaning that the
      itemstack was allowed in the chest.
    - this will happen with two stacks in rapid succession, the first filling the chest, and the
      second bouncing. the <count> in this case will be the amount of the second.
    - overflow can't happen with two different kinds of items, you'll get a put, maybe full, then lost for the second kind

Tricky situation:
if you have a blank spot and put say 82 torches down your pipeline, followed by 99 coal, the 82 torches will go in the chest, and the chest will see that 1 more torch can fit since that would only go to 83. Since 1 more torch can fit, no "full" message will fire off. Then when the coal hits the chest, the "fail" message will fire and the coal will bounce out. The chest couldn't predict that coal would be coming next, so it couldn't know that the chest is full, for coal, while not full for torches.

TODO:
    - make chest.lua a mixin that gets both default and locked chests
    - digiline aware furnaces
    - digiline aware technic machines, grinders, alloy furnaces, etc
    - the pipes going into the chests don't snap to the pipe holes in the digiline chests. They still act fine as pipeworks destinations though.
    - digiline chests seem to be immune to filters. But it's late and I'm shipping this. Someone else can figure out why the chests aren't acting like pipeworks chests, despite cloning the pipeworks chest's object. Oh who am I kidding. I'll do it myself I guess, once I've lost hope of aid again.


code:
Digilines
==========
- The minetest counterpart for bus systems like i2c, SPI, RS232, USB -

This mod adds digiline wires, an RTC (Real Time Clock), a light sensor as well as an LCD Screen.
Can be used together with the luacontroller from mesecons. See the luacontroller manual for more information.

Send "GET" to RTC or light sensor to retrieve Data, send any text to LCD to display it.
Select channel by right-clicking items.

License:
  Code: LGPL
  Textures: WTFPL


path: mods/digilines/characters


code: This mod adds digiline wires, an RTC (Real Time Clock), a light sensor as well as an LCD Screen. Can be used together with the luacontroller from mesecons.


code:
digilines = {}

-- Backwards compatibility code.
-- We define a proxy table whose methods can be called with the
-- `foo:bar` notation, and it will redirect the call to the
-- real function, dropping the first implicit argument.
local digiline; digiline = setmetatable({}, {
	__index = function(_, k)
		-- Get method from real table.
		local v = digilines[k]
		if type(v) == "function" then
			-- We need to wrap functions in order to ignore
			-- the implicit `self` argument.
			local f = v
			return function(self, ...)
				-- Trap invalid calls of the form `digiline.foo(...)`.
				assert(self == digiline)
				return f(...)
			end
		end
		return v
	end,
})
rawset(_G, "digiline", digiline)

-- Let's test our proxy table.
function digilines._testproxy(x)
	return x
end

-- Test using old `digiline:foobar` form.
assert(digiline:_testproxy("foobar") == "foobar")

-- Test using new `digilines.foobar` form.
assert(digilines._testproxy("foobar") == "foobar")

-- Test calling incorrect form raises an error.
assert(not pcall(function() digiline._testproxy("foobar") end))

local modpath = minetest.get_modpath("digilines")
dofile(modpath .. "/presetrules.lua")
dofile(modpath .. "/util.lua")
dofile(modpath .. "/internal.lua")
dofile(modpath .. "/wires_common.lua")
dofile(modpath .. "/wire_std.lua")

function digilines.receptor_send(pos, rules, channel, msg)
	local checked = {}
	checked[minetest.hash_node_position(pos)] = true -- exclude itself
	for _,rule in ipairs(rules) do
		if digilines.rules_link(pos, digilines.addPosRule(pos, rule)) then
			digilines.transmit(digilines.addPosRule(pos, rule), channel, msg, checked)
		end
	end
end

minetest.register_craft({
	output = 'digilines:wire_std_00000000 2',
	recipe = {
		{'mesecons_materials:fiber', 'mesecons_materials:fiber', 'mesecons_materials:fiber'},
		{'mesecons_insulated:insulated_off', 'mesecons_insulated:insulated_off', 'default:gold_ingot'},
		{'mesecons_materials:fiber', 'mesecons_materials:fiber', 'mesecons_materials:fiber'},
	}
})

-- For minetest 0.4 support returned nil are also tested:  ~= false
if minetest.settings:get_bool("digilines_enable_inventory", true) ~= false then
	dofile(modpath .. "/inventory.lua")
end

if minetest.settings:get_bool("digilines_enable_lcd", true) ~= false then
	dofile(modpath .. "/lcd.lua")
end

if minetest.settings:get_bool("digilines_enable_lightsensor", true) ~= false then
	dofile(modpath .. "/lightsensor.lua")
end

if minetest.settings:get_bool("digilines_enable_rtc", true) ~= false then
	dofile(modpath .. "/rtc.lua")
end


code:
function digilines.getspec(node)
	local def = minetest.registered_nodes[node.name]
	if not def then return false end
	return def.digilines or def.digiline
end

function digilines.importrules(spec, node)
	if type(spec) == 'function' then
		return spec(node)
	elseif spec then
		return spec
	else
		return digilines.rules.default
	end
end

function digilines.getAnyInputRules(pos)
	local node = digilines.get_node_force(pos)
	local spec = digilines.getspec(node)
	if not spec then return end

	if spec.wire then
		return digilines.importrules(spec.wire.rules, node)
	end
	if spec.effector then
		return digilines.importrules(spec.effector.rules, node)
	end
end

function digilines.getAnyOutputRules(pos)
	local node = digilines.get_node_force(pos)
	local spec = digilines.getspec(node)
	if not spec then return end

	if spec.wire then
		return digilines.importrules(spec.wire.rules, node)
	end
	if spec.receptor then
		return digilines.importrules(spec.receptor.rules, node)
	end
end

function digilines.rules_link(output, input)
	local outputrules = digilines.getAnyOutputRules(output)
	local inputrules  = digilines.getAnyInputRules (input)

	if not outputrules or not inputrules then return false end

	for _, orule in ipairs(outputrules) do
		if digilines.cmpPos(digilines.addPosRule(output, orule), input) then
			for _, irule in ipairs(inputrules) do
				if digilines.cmpPos(digilines.addPosRule(input, irule), output) then
					return true
				end
			end
		end
	end
	return false
end

function digilines.rules_link_anydir(output, input)
	return digilines.rules_link(output, input)
	or     digilines.rules_link(input, output)
end

local function queue_new()
	return {nextRead = 1, nextWrite = 1}
end

local function queue_empty(queue)
	return queue.nextRead == queue.nextWrite
end

local function queue_enqueue(queue, object)
	local nextWrite = queue.nextWrite
	queue[nextWrite] = object
	queue.nextWrite = nextWrite + 1
end

local function queue_dequeue(queue)
	local nextRead = queue.nextRead
	local object = queue[nextRead]
	queue[nextRead] = nil
	queue.nextRead = nextRead + 1
	return object
end

function digilines.transmit(pos, channel, msg, checked)
	local checkedID = minetest.hash_node_position(pos)
	if checked[checkedID] then
		return
	end
	checked[checkedID] = true

	digilines.vm_begin()
	local queue = queue_new()
	queue_enqueue(queue, pos)
	while not queue_empty(queue) do
		local curPos = queue_dequeue(queue)
		local node = digilines.get_node_force(curPos)
		local spec = digilines.getspec(node)
		if spec then
			-- Effector actions --> Receive
			if spec.effector then
				spec.effector.action(curPos, node, channel, msg)
			end

			-- Cable actions --> Transmit
			if spec.wire then
				local rules = digilines.importrules(spec.wire.rules, node)
				for _, rule in ipairs(rules) do
					local nextPos = digilines.addPosRule(curPos, rule)
					if digilines.rules_link(curPos, nextPos) then
						local checkedID = minetest.hash_node_position(nextPos)
						if not checked[checkedID] then
							checked[checkedID] = true
							queue_enqueue(queue, nextPos)
						end
					end
				end
			end
		end
	end
	digilines.vm_end()
end


code:
local pipeworks_enabled = minetest.get_modpath("pipeworks") ~= nil

-- Sends a message onto the Digilines network.
-- pos: the position of the Digilines chest node.
-- action: the action string indicating what happened.
-- stack: the ItemStack that the action acted on (optional).
-- from_slot: the slot number that is taken from (optional).
-- to_slot: the slot number that is put into (optional).
-- side: which side of the chest the action occurred (optional).
local function send_message(pos, action, stack, from_slot, to_slot, side)
	local channel = minetest.get_meta(pos):get_string("channel")
	local msg = {
		action = action,
		stack = stack and stack:to_table(),
		from_slot = from_slot,
		to_slot = to_slot,
		-- Duplicate the vector in case the caller expects it not to change.
		side = side and vector.new(side)
	}
	digilines.receptor_send(pos, digilines.rules.default, channel, msg)
end

-- Checks if the inventory has become empty and, if so, sends an empty message.
local function check_empty(pos)
	if minetest.get_meta(pos):get_inventory():is_empty("main") then
		send_message(pos, "empty")
	end
end

-- Checks if the inventory has become full for a particular type of item and,
-- if so, sends a full message.
local function check_full(pos, stack)
	local one_item_stack = ItemStack(stack)
	one_item_stack:set_count(1)
	if not minetest.get_meta(pos):get_inventory():room_for_item("main", one_item_stack) then
		send_message(pos, "full", one_item_stack)
	end
end

local tubeconn = pipeworks_enabled and "^pipeworks_tube_connection_wooden.png" or ""
local tubescan = pipeworks_enabled and function(pos) pipeworks.scan_for_tube_objects(pos) end or nil

-- A place to remember things from allow_metadata_inventory_put to
-- on_metadata_inventory_put. This is a hack due to issue
-- minetest/minetest#6534 that should be removed once that’s fixed.
local last_inventory_put_index
local last_inventory_put_stack

-- A place to remember things from allow_metadata_inventory_take to
-- tube.remove_items. This is a hack due to issue minetest-mods/pipeworks#205
-- that should be removed once that’s fixed.
local last_inventory_take_index

minetest.register_alias("digilines_inventory:chest", "digilines:chest")
minetest.register_node("digilines:chest", {
	description = "Digiline Chest",
	tiles = {
		"default_chest_top.png"..tubeconn,
		"default_chest_top.png"..tubeconn,
		"default_chest_side.png"..tubeconn,
		"default_chest_side.png"..tubeconn,
		"default_chest_side.png"..tubeconn,
		"default_chest_front.png",
	},
	paramtype2 = "facedir",
	legacy_facedir_simple = true,
	groups = {choppy=2, oddly_breakable_by_hand=2, tubedevice=1, tubedevice_receiver=1},
	sounds = default.node_sound_wood_defaults(),
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("infotext", "Digiline Chest")
		meta:set_string("formspec", "size[8,10]"..
			((default and default.gui_bg) or "")..
			((default and default.gui_bg_img) or "")..
			((default and default.gui_slots) or "")..
			"label[0,0;Digiline Chest]"..
			"list[current_name;main;0,1;8,4;]"..
			"field[2,5.5;5,1;channel;Channel;${channel}]"..
			((default and default.get_hotbar_bg) and default.get_hotbar_bg(0,6) or "")..
			"list[current_player;main;0,6;8,4;]"..
			"listring[]")
		local inv = meta:get_inventory()
		inv:set_size("main", 8*4)
	end,
	after_place_node = tubescan,
	after_dig_node = tubescan,
	can_dig = function(pos)
		return minetest.get_meta(pos):get_inventory():is_empty("main")
	end,
	on_receive_fields = function(pos, _, fields, sender)
		local name = sender:get_player_name()
		if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
			minetest.record_protection_violation(pos, name)
			return
		end
		if fields.channel ~= nil then
			minetest.get_meta(pos):set_string("channel",fields.channel)
		end
	end,
	digiline = {
		receptor = {},
		effector = {
			action = function() end
		}
	},
	tube = {
		connect_sides = {left=1, right=1, back=1, front=1, bottom=1, top=1},
		connects = function(i,param2)
			return not pipeworks.connects.facingFront(i,param2)
		end,
		input_inventory = "main",
		can_insert = function(pos, _, stack, direction)
			local ret = minetest.get_meta(pos):get_inventory():room_for_item("main", stack)
			if not ret then
				-- The stack cannot be accepted. It will never be passed to
				-- insert_object, but it should be reported as a toverflow.
				-- Here, direction = direction item is moving, which is into
				-- side.
				local side = vector.multiply(direction, -1)
				send_message(pos, "toverflow", stack, nil, nil, side)
			end
			return ret
		end,
		insert_object = function(pos, _, original_stack, direction)
			-- Here, direction = direction item is moving, which is into side.
			local side = vector.multiply(direction, -1)
			local inv = minetest.get_meta(pos):get_inventory()
			local inv_contents = inv:get_list("main")
			local any_put = false
			local stack = original_stack
			local stack_name = stack:get_name()
			local stack_count = stack:get_count()
			-- Walk the inventory, adding items to existing stacks of the same
			-- type.
			for i = 1, #inv_contents do
				local existing_stack = inv_contents[i]
				if not existing_stack:is_empty() and existing_stack:get_name() == stack_name then
					local leftover = existing_stack:add_item(stack)
					local leftover_count = leftover:get_count()
					if leftover_count ~= stack_count then
						-- We put some items into the slot. Update the slot in
						-- the inventory, tell Digilines listeners about it,
						-- and keep looking for the a place to put the
						-- leftovers if any.
						any_put = true
						inv:set_stack("main", i, existing_stack)
						local stack_that_was_put
						if leftover_count == 0 then
							stack_that_was_put = stack
						else
							stack_that_was_put = ItemStack(stack)
							stack_that_was_put:set_count(stack_count - leftover_count)
						end
						send_message(pos, "tput", stack_that_was_put, nil, i, side)
						stack = leftover
						stack_count = leftover_count
						if stack_count == 0 then
							break
						end
					end
				end
			end
			if stack_count ~= 0 then
				-- Walk the inventory, adding items to empty slots.
				for i = 1, #inv_contents do
					local existing_stack = inv_contents[i]
					if existing_stack:is_empty() then
						local leftover = existing_stack:add_item(stack)
						local leftover_count = leftover:get_count()
						if leftover_count ~= stack_count then
							-- We put some items into the slot. Update the slot in
							-- the inventory, tell Digilines listeners about it,
							-- and keep looking for the a place to put the
							-- leftovers if any.
							any_put = true
							inv:set_stack("main", i, existing_stack)
							local stack_that_was_put
							if leftover_count == 0 then
								stack_that_was_put = stack
							else
								stack_that_was_put = ItemStack(stack)
								stack_that_was_put:set_count(stack_count - leftover_count)
							end
							send_message(pos, "tput", stack_that_was_put, nil, i, side)
							stack = leftover
							stack_count = leftover_count
							if stack_count == 0 then
								break
							end
						end
					end
				end
			end
			if any_put then
				check_full(pos, original_stack)
			end
			if stack_count ~= 0 then
				-- Some items could not be added and bounced back. Report them.
				send_message(pos, "toverflow", stack, nil, nil, side)
			end
			return stack
		end,
		remove_items = function(pos, _, stack, dir, count)
			-- Here, stack is the ItemStack in our own inventory that is being
			-- pulled from, NOT the stack that is actually pulled out.
			-- Combining it with count gives the stack that is pulled out.
			-- Also, note that Pipeworks doesn’t pass the index to this
			-- function, so we use the one recorded in
			-- allow_metadata_inventory_take; because we don’t implement
			-- tube.can_remove, Pipeworks will call
			-- allow_metadata_inventory_take instead and will pass it the
			-- index.
			local taken = stack:take_item(count)
			minetest.get_meta(pos):get_inventory():set_stack("main", last_inventory_take_index, stack)
			send_message(pos, "ttake", taken, last_inventory_take_index, nil, dir)
			check_empty(pos)
			return taken
		end,
	},
	allow_metadata_inventory_put = function(pos, _, index, stack)
		-- Remember what was in the target slot before the put; see
		-- on_metadata_inventory_put for why we care.
		last_inventory_put_index = index
		last_inventory_put_stack = minetest.get_meta(pos):get_inventory():get_stack("main", index)
		return stack:get_count()
	end,
	allow_metadata_inventory_take = function(_, _, index, stack)
		-- Remember the index value; see tube.remove_items for why we care.
		last_inventory_take_index = index
		return stack:get_count()
	end,
	on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
		-- See what would happen if we were to move the items back from in the
		-- opposite direction. In the event of a normal move, this must
		-- succeed, because a normal move subtracts some items from the from
		-- stack and adds them to the to stack; the two stacks naturally must
		-- be compatible and so the reverse operation must succeed. However, if
		-- the user *swaps* the two stacks instead, then due to issue
		-- minetest/minetest#6534, this function is only called once; however,
		-- when it is called, the stack that used to be in the to stack has
		-- already been moved to the from stack, so we can detect the situation
		-- by the fact that the reverse move will fail due to the from stack
		-- being incompatible with its former contents.
		local inv = minetest.get_meta(pos):get_inventory()
		local from_stack = inv:get_stack("main", from_index)
		local to_stack = inv:get_stack("main", to_index)
		local reverse_move_stack = ItemStack(to_stack)
		reverse_move_stack:set_count(count)
		local swapped = from_stack:add_item(reverse_move_stack):get_count() == count
		if swapped then
			local channel = minetest.get_meta(pos):get_string("channel")
			to_stack:set_count(count)
			local msg = {
				action = "uswap",
				-- The slot and stack do not match because this function is
				-- called after the action has taken place, but the Digilines
				-- message is from the perspective of a viewer who hasn’t
				-- observed the movement yet.
				x_stack = to_stack:to_table(),
				x_slot = from_index,
				y_stack = from_stack:to_table(),
				y_slot = to_index,
			}
			digilines.receptor_send(pos, digilines.rules.default, channel, msg)
		else
			to_stack:set_count(count)
			send_message(pos, "umove", to_stack, from_index, to_index)
		end
		minetest.log("action", player:get_player_name().." moves stuff in chest at "..minetest.pos_to_string(pos))
	end,
	on_metadata_inventory_put = function(pos, _, index, stack, player)
		-- Get what was in the target slot before the put; it has disappeared
		-- by now (been replaced by the result of the put action) but we saved
		-- it in allow_metadata_inventory_put. This should always work
		-- (allow_metadata_inventory_put should AFAICT always be called
		-- immediately before on_metadata_inventory_put), but in case of
		-- something weird happening, just fall back to using an empty
		-- ItemStack rather than crashing.
		local old_stack
		if last_inventory_put_index == index then
			old_stack = last_inventory_put_stack
			last_inventory_put_index = nil
			last_inventory_put_stack = nil
		else
			old_stack = ItemStack(nil)
		end
		-- If the player tries to place a stack into an inventory, there’s
		-- already a stack there, and the existing stack is either of a
		-- different item type or full, then obviously the stacks can’t be
		-- merged; instead the stacks are swapped. This information is not
		-- reported to mods (Minetest core neither tells us that a particular
		-- action was a swap, nor tells us a take followed by a put). In core,
		-- the condition for swapping is that you try to add the new stack to
		-- the existing stack and the leftovers are as big as the original
		-- stack to put. Replicate that logic here using the old stack saved in
		-- allow_metadata_inventory_put. If a swap happened, report it to the
		-- Digilines network as a utake followed by a uput.
		local leftovers = old_stack:add_item(stack)
		if leftovers:get_count() == stack:get_count() then
			send_message(pos, "utake", old_stack, index)
		end
		send_message(pos, "uput", stack, nil, index)
		check_full(pos, stack)
		minetest.log("action", player:get_player_name().." puts stuff into chest at "..minetest.pos_to_string(pos))
	end,
	on_metadata_inventory_take = function(pos, _, index, stack, player)
		send_message(pos, "utake", stack, index)
		check_empty(pos)
		minetest.log("action", player:get_player_name().." takes stuff from chest at "..minetest.pos_to_string(pos))
	end
})

minetest.register_craft({
	type = "shapeless",
	output = "digilines:chest",
	recipe = {"default:chest", "digilines:wire_std_00000000"}
})


code:
--* parts are currently not possible because you cannot set the pitch of an entity from lua

-- Font: 04.jp.org

-- load characters map
local chars_file = io.open(minetest.get_modpath("digilines").."/characters", "r")
local charmap = {}
local max_chars = 12
if not chars_file then
	print("[digilines] E: LCD: character map file not found")
else
	while true do
		local char = chars_file:read("*l")
		if char == nil then
			break
		end
		local img = chars_file:read("*l")
		chars_file:read("*l")
		charmap[char] = img
	end
end

-- CONSTANTS
local LCD_WITH = 100
local LCD_PADDING = 8

local LINE_LENGTH = 12
local NUMBER_OF_LINES = 5

local LINE_HEIGHT = 14
local CHAR_WIDTH = 5

local create_lines = function(text)
	local line = ""
	local line_num = 1
	local tab = {}
	for word in string.gmatch(text, "%S+") do
		if string.len(line)+string.len(word) < LINE_LENGTH and word ~= "|" then
			if line ~= "" then
				line = line.." "..word
			else
				line = word
			end
		else
			table.insert(tab, line)
			if word ~= "|" then
				line = word
			else
				line = ""
			end
			line_num = line_num+1
			if line_num > NUMBER_OF_LINES then
				return tab
			end
		end
	end
	table.insert(tab, line)
	return tab
end

local generate_line = function(s, ypos)
	local i = 1
	local parsed = {}
	local width = 0
	local chars = 0
	while chars < max_chars and i <= #s do
		local file = nil
		if charmap[s:sub(i, i)] ~= nil then
			file = charmap[s:sub(i, i)]
			i = i + 1
		elseif i < #s and charmap[s:sub(i, i + 1)] ~= nil then
			file = charmap[s:sub(i, i + 1)]
			i = i + 2
		else
			print("[digilines] W: LCD: unknown symbol in '"..s.."' at "..i)
			i = i + 1
		end
		if file ~= nil then
			width = width + CHAR_WIDTH
			table.insert(parsed, file)
			chars = chars + 1
		end
	end
	width = width - 1

	local texture = ""
	local xpos = math.floor((LCD_WITH - 2 * LCD_PADDING - width) / 2 + LCD_PADDING)
	for ii = 1, #parsed do
		texture = texture..":"..xpos..","..ypos.."="..parsed[ii]..".png"
		xpos = xpos + CHAR_WIDTH + 1
	end
	return texture
end

local generate_texture = function(lines)
	local texture = "[combine:"..LCD_WITH.."x"..LCD_WITH
	local ypos = 16
	for i = 1, #lines do
		texture = texture..generate_line(lines[i], ypos)
		ypos = ypos + LINE_HEIGHT
	end
	return texture
end

local lcds = {
	-- on ceiling
	--* [0] = {delta = {x = 0, y = 0.4, z = 0}, pitch = math.pi / -2},
	-- on ground
	--* [1] = {delta = {x = 0, y =-0.4, z = 0}, pitch = math.pi /  2},
	-- sides
	[2] = {delta = {x =  0.437, y = 0, z = 0}, yaw = math.pi / -2},
	[3] = {delta = {x = -0.437, y = 0, z = 0}, yaw = math.pi /  2},
	[4] = {delta = {x = 0, y = 0, z =  0.437}, yaw = 0},
	[5] = {delta = {x = 0, y = 0, z = -0.437}, yaw = math.pi},
}

local reset_meta = function(pos)
	minetest.get_meta(pos):set_string("formspec", "field[channel;Channel;${channel}]")
end

local clearscreen = function(pos)
	local objects = minetest.get_objects_inside_radius(pos, 0.5)
	for _, o in ipairs(objects) do
		local o_entity = o:get_luaentity()
		if o_entity and o_entity.name == "digilines_lcd:text" then
			o:remove()
		end
	end
end

local set_texture = function(ent)
	local meta = minetest.get_meta(ent.object:get_pos())
	local text = meta:get_string("text")
	ent.object:set_properties({
		textures = {
			generate_texture(create_lines(text))
		}
	})
end

local get_entity = function(pos)
	local lcd_entity
	local objects = minetest.get_objects_inside_radius(pos, 0.5)
	for _, o in ipairs(objects) do
		local o_entity = o:get_luaentity()
		if o_entity and o_entity.name == "digilines_lcd:text" then
			if not lcd_entity then
				lcd_entity = o_entity
			else
				-- Remove extras, if any
				o:remove()
			end
		end
	end
	return lcd_entity
end

local rotate_text = function(pos, param)
	local entity = get_entity(pos)
	if not entity then
		return
	end
	local lcd_info = lcds[param or minetest.get_node(pos).param2]
	if not lcd_info then
		return
	end
	entity.object:set_pos(vector.add(pos, lcd_info.delta))
	entity.object:set_yaw(lcd_info.yaw or 0)
end

local prepare_writing = function(pos)
	local entity = get_entity(pos)
	if entity then
		set_texture(entity)
		rotate_text(pos)
	end
end

local spawn_entity = function(pos)
	if not get_entity(pos) then
		minetest.add_entity(pos, "digilines_lcd:text")
		rotate_text(pos)
	end
end

local on_digiline_receive = function(pos, _, channel, msg)
	local meta = minetest.get_meta(pos)
	local setchan = meta:get_string("channel")
	if setchan ~= channel then return end

	meta:set_string("text", msg)
	meta:set_string("infotext", msg)

	if msg ~= "" then
		prepare_writing(pos)
	end
end

local lcd_box = {
	type = "wallmounted",
	wall_top = {-8/16, 7/16, -8/16, 8/16, 8/16, 8/16}
}

minetest.register_alias("digilines_lcd:lcd", "digilines:lcd")
minetest.register_node("digilines:lcd", {
	drawtype = "nodebox",
	description = "Digiline LCD",
	inventory_image = "lcd_lcd.png",
	wield_image = "lcd_lcd.png",
	tiles = {"lcd_anyside.png"},
	paramtype = "light",
	sunlight_propagates = true,
	light_source = 6,
	paramtype2 = "wallmounted",
	node_box = lcd_box,
	selection_box = lcd_box,
	groups = {choppy = 3, dig_immediate = 2},
	after_place_node = function(pos)
		local param2 = minetest.get_node(pos).param2
		if param2 == 0 or param2 == 1 then
			minetest.add_node(pos, {name = "digilines:lcd", param2 = 3})
		end
		spawn_entity(pos)
		prepare_writing(pos)
	end,
	on_construct = reset_meta,
	on_destruct = clearscreen,
	on_punch = function(pos, node, puncher, pointed_thing)
		if minetest.is_player(puncher) then
			spawn_entity(pos)
		end
	end,
	on_rotate = function(pos, node, user, mode, new_param2)
		if mode ~= screwdriver.ROTATE_FACE then
			return false
		end
		rotate_text(pos, new_param2)
	end,
	on_receive_fields = function(pos, _, fields, sender)
		local name = sender:get_player_name()
		if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
			minetest.record_protection_violation(pos, name)
			return
		end
		if (fields.channel) then
			minetest.get_meta(pos):set_string("channel", fields.channel)
		end
	end,
	digiline = {
		receptor = {},
		effector = {
			action = on_digiline_receive
		},
	},
})

minetest.register_lbm({
	label = "Replace Missing Text Entities",
	name = "digilines:replace_text",
	nodenames = {"digilines:lcd"},
	run_at_every_load = true,
	action = spawn_entity,
})

minetest.register_entity(":digilines_lcd:text", {
	collisionbox = { 0, 0, 0, 0, 0, 0 },
	visual = "upright_sprite",
	textures = {},
	on_activate = set_texture,
})

minetest.register_craft({
	output = "digilines:lcd 2",
	recipe = {
		{"default:steel_ingot", "digilines:wire_std_00000000", "default:steel_ingot"},
		{"mesecons_lightstone:lightstone_green_off","mesecons_lightstone:lightstone_green_off","mesecons_lightstone:lightstone_green_off"},
		{"default:glass","default:glass","default:glass"}
	}
})


code:
local GET_COMMAND = "GET"

local lsensor_nodebox =
{
	type = "fixed",
	fixed = {
		{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab

		{ -7/16, -7/16, -7/16, -4/16, -5/16,  7/16 }, -- bonds
		{  4/16, -7/16, -7/16,  7/16, -5/16,  7/16 },
		{ -7/16, -7/16, -7/16,  7/16, -5/16, -4/16 },
		{ -7/16, -7/16,  4/16,  7/16, -5/16,  7/16 },

		{ -1/16, -7/16, -1/16, 1/16, -5/16, 1/16 }, -- pin thing in the middle
	}
}

local lsensor_selbox =
{
	type = "fixed",
	fixed = {{ -8/16, -8/16, -8/16, 8/16, -3/16, 8/16 }}
}

local on_digiline_receive = function (pos, _, channel, msg)
	local setchan = minetest.get_meta(pos):get_string("channel")
	if channel == setchan and msg == GET_COMMAND then
		local lightval = minetest.get_node_light(pos)
		digilines.receptor_send(pos, digilines.rules.default, channel, lightval)
	end
end

minetest.register_alias("digilines_lightsensor:lightsensor", "digilines:lightsensor")
minetest.register_node("digilines:lightsensor", {
	description = "Digiline Lightsensor",
	drawtype = "nodebox",
	tiles = {"digilines_lightsensor.png"},

	paramtype = "light",
	groups = {dig_immediate=2},
	selection_box = lsensor_selbox,
	node_box = lsensor_nodebox,
	digiline =
	{
		receptor = {},
		effector = {
			action = on_digiline_receive
		},
	},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("formspec", "field[channel;Channel;${channel}]")
	end,
	on_receive_fields = function(pos, _, fields, sender)
		local name = sender:get_player_name()
		if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
			minetest.record_protection_violation(pos, name)
			return
		end
		if (fields.channel) then
			minetest.get_meta(pos):set_string("channel", fields.channel)
		end
	end,
})


code: name = digilines


code:
local GET_COMMAND = "GET"

local rtc_nodebox =
{
	type = "fixed",
	fixed = {
		{ -8/16, -8/16, -8/16, 8/16, -7/16, 8/16 }, -- bottom slab

		{ -7/16, -7/16, -7/16, 7/16, -5/16,  7/16 },
	}
}

local rtc_selbox =
{
	type = "fixed",
	fixed = {{ -8/16, -8/16, -8/16, 8/16, -3/16, 8/16 }}
}

local on_digiline_receive = function (pos, _, channel, msg)
	local setchan = minetest.get_meta(pos):get_string("channel")
	if channel == setchan and msg == GET_COMMAND then
		local timeofday = minetest.get_timeofday()
		digilines.receptor_send(pos, digilines.rules.default, channel, timeofday)
	end
end

minetest.register_alias("digilines_rtc:rtc", "digilines:rtc")
minetest.register_node("digilines:rtc", {
	description = "Digiline Real Time Clock (RTC)",
	drawtype = "nodebox",
	tiles = {"digilines_rtc.png"},

	paramtype = "light",
	paramtype2 = "facedir",
	groups = {dig_immediate=2},
	selection_box = rtc_selbox,
	node_box = rtc_nodebox,
	digiline =
	{
		receptor = {},
		effector = {
			action = on_digiline_receive
		},
	},
	on_construct = function(pos)
		local meta = minetest.get_meta(pos)
		meta:set_string("formspec", "field[channel;Channel;${channel}]")
	end,
	on_receive_fields = function(pos, _, fields, sender)
		local name = sender:get_player_name()
		if minetest.is_protected(pos, name) and not minetest.check_player_privs(name, {protection_bypass=true}) then
			minetest.record_protection_violation(pos, name)
			return
		end
		if (fields.channel) then
			minetest.get_meta(pos):set_string("channel", fields.channel)
		end
	end,
})


code:
# If enabled, makes some nodes with inventories (like chests) send signals
# when items are moved in the inventory.
digilines_enable_inventory (Enable inventory signals) bool true

# Enable or disable the LCD panel with visible text.
digilines_enable_lcd (Enable LCD) bool true

# Enable or disable the light sensor component.
digilines_enable_lightsensor (Enable light sensor) bool true

# Enable or disable the real time clock component.
digilines_enable_rtc (Enable RTC) bool true


code:
function digilines.addPosRule(p, r)
	return {x = p.x + r.x, y = p.y + r.y, z = p.z + r.z}
end

function digilines.cmpPos(p1, p2)
	return (p1.x == p2.x and p1.y == p2.y and p1.z == p2.z)
end

--Rules rotation Functions:
function digilines.rotate_rules_right(rules)
	local nr={}
	for i, rule in ipairs(rules) do
		nr[i]={}
		nr[i].z=rule.x
		nr[i].x=-rule.z
		nr[i].y=rule.y
	end
	return nr
end

function digilines.rotate_rules_left(rules)
	local nr={}
	for i, rule in ipairs(rules) do
		nr[i]={}
		nr[i].z=-rule.x
		nr[i].x=rule.z
		nr[i].y=rule.y
	end
	return nr
end

function digilines.rotate_rules_down(rules)
	local nr={}
	for i, rule in ipairs(rules) do
		nr[i]={}
		nr[i].y=rule.x
		nr[i].x=-rule.y
		nr[i].z=rule.z
	end
	return nr
end

function digilines.rotate_rules_up(rules)
	local nr={}
	for i, rule in ipairs(rules) do
		nr[i]={}
		nr[i].y=-rule.x
		nr[i].x=rule.y
		nr[i].z=rule.z
	end
	return nr
end

function digilines.tablecopy(table) -- deep table copy
	if type(table) ~= "table" then return table end -- no need to copy
	local newtable = {}

	for idx, item in pairs(table) do
		if type(item) == "table" then
			newtable[idx] = digilines.tablecopy(item)
		else
			newtable[idx] = item
		end
	end

	return newtable
end

-- VoxelManipulator-based node access functions:

-- Maps from a hashed mapblock position (as returned by hash_blockpos) to a
-- table.
--
-- Contents of the table are:
-- “va” → the VoxelArea
-- “data” → the data array
-- “param1” → the param1 array
-- “param2” → the param2 array
--
-- Nil if no bulk-VM operation is in progress.
local vm_cache = nil

-- Starts a bulk-VoxelManipulator operation.
--
-- During a bulk-VoxelManipulator operation, calls to get_node_force operate
-- directly on VM-loaded arrays, which should be faster for reading many nodes
-- in rapid succession. However, the cache must be flushed with vm_end once the
-- scan is finished, to avoid using stale data in future.
function digilines.vm_begin()
	vm_cache = {}
end

-- Ends a bulk-VoxelManipulator operation, freeing the cached data.
function digilines.vm_end()
	vm_cache = nil
end

-- The dimension of a mapblock in nodes.
local MAPBLOCKSIZE = 16

-- Converts a node position into a hash of a mapblock position.
local function vm_hash_blockpos(pos)
	return minetest.hash_node_position({
		x = math.floor(pos.x / MAPBLOCKSIZE),
		y = math.floor(pos.y / MAPBLOCKSIZE),
		z = math.floor(pos.z / MAPBLOCKSIZE)
	})
end

-- Gets the cache entry covering a position, populating it if necessary.
local function vm_get_or_create_entry(pos)
	local hash = vm_hash_blockpos(pos)
	local tbl = vm_cache[hash]
	if not tbl then
		local vm = minetest.get_voxel_manip(pos, pos)
		local min_pos, max_pos = vm:get_emerged_area()
		local va = VoxelArea:new{MinEdge = min_pos, MaxEdge = max_pos}
		tbl = {va = va, data = vm:get_data(), param1 = vm:get_light_data(), param2 = vm:get_param2_data()}
		vm_cache[hash] = tbl
	end
	return tbl
end

-- Gets the node at a position during a bulk-VoxelManipulator operation.
local function vm_get_node(pos)
	local tbl = vm_get_or_create_entry(pos)
	local index = tbl.va:indexp(pos)
	local node_value = tbl.data[index]
	local node_param1 = tbl.param1[index]
	local node_param2 = tbl.param2[index]
	return {name = minetest.get_name_from_content_id(node_value), param1 = node_param1, param2 = node_param2}
end

-- Gets the node at a given position, regardless of whether it is loaded or
-- not.
--
-- Outside a bulk-VoxelManipulator operation, if the mapblock is not loaded, it
-- is pulled into the server’s main map data cache and then accessed from
-- there.
--
-- Inside a bulk-VoxelManipulator operation, the operation’s VM cache is used.
function digilines.get_node_force(pos)
	if vm_cache then
		return vm_get_node(pos)
	end
	local node = minetest.get_node(pos)
	if node.name == "ignore" then
		-- Node is not currently loaded; use a VoxelManipulator to prime
		-- the mapblock cache and try again.
		minetest.get_voxel_manip(pos, pos)
		node = minetest.get_node(pos)
	end
	return node
end


code:
-- naming scheme: wire:(xp)(zp)(xm)(zm)_on/off
-- The conditions in brackets define whether there is a digiline at that place or not
-- 1 = there is one; 0 = there is none
-- y always means y+

local box_center = {-1/16, -.5, -1/16, 1/16, -.5+1/16, 1/16}
local box_bump1 =  { -2/16, -8/16,  -2/16, 2/16, -13/32, 2/16 }
local box_bump2 =  { -3/32, -13/32, -3/32, 3/32, -12/32, 3/32 }

local box_xp = {1/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}
local box_zp = {-1/16, -.5, 1/16, 1/16, -.5+1/16, 8/16}
local box_xm = {-8/16, -.5, -1/16, -1/16, -.5+1/16, 1/16}
local box_zm = {-1/16, -.5, -8/16, 1/16, -.5+1/16, -1/16}

local box_xpy = {.5-1/16, -.5+1/16, -1/16, .5, .4999+1/16, 1/16}
local box_zpy = {-1/16, -.5+1/16, .5-1/16, 1/16, .4999+1/16, .5}
local box_xmy = {-.5, -.5+1/16, -1/16, -.5+1/16, .4999+1/16, 1/16}
local box_zmy = {-1/16, -.5+1/16, -.5, 1/16, .4999+1/16, -.5+1/16}

for xp=0, 1 do
for zp=0, 1 do
for xm=0, 1 do
for zm=0, 1 do
for xpy=0, 1 do
for zpy=0, 1 do
for xmy=0, 1 do
for zmy=0, 1 do
	if (xpy == 1 and xp == 0) or (zpy == 1 and zp == 0)
	or (xmy == 1 and xm == 0) or (zmy == 1 and zm == 0) then break end

	local groups
	local nodeid = 	tostring(xp )..tostring(zp )..tostring(xm )..tostring(zm )..
			tostring(xpy)..tostring(zpy)..tostring(xmy)..tostring(zmy)

	local wiredesc

	if nodeid == "00000000" then
		groups = {dig_immediate = 3}
		wiredesc = "Digiline"
	else
		groups = {dig_immediate = 3, not_in_creative_inventory = 1}
	end

	local nodebox = {}
	local adjx = false
	local adjz = false
	if xp == 1 then table.insert(nodebox, box_xp) adjx = true end
	if zp == 1 then table.insert(nodebox, box_zp) adjz = true end
	if xm == 1 then table.insert(nodebox, box_xm) adjx = true end
	if zm == 1 then table.insert(nodebox, box_zm) adjz = true end
	if xpy == 1 then table.insert(nodebox, box_xpy) end
	if zpy == 1 then table.insert(nodebox, box_zpy) end
	if xmy == 1 then table.insert(nodebox, box_xmy) end
	if zmy == 1 then table.insert(nodebox, box_zmy) end

	local tiles
	if adjx and adjz and (xp + zp + xm + zm > 2) then
		table.insert(nodebox, box_bump1)
		table.insert(nodebox, box_bump2)
		tiles = {
			"digiline_std_bump.png",
			"digiline_std_bump.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png"
		}
	else
		table.insert(nodebox, box_center)
		tiles = {
			"digiline_std.png",
			"digiline_std.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png",
			"digiline_std_vertical.png"
		}
	end

	if nodeid == "00000000" then
		nodebox = {-8/16, -.5, -1/16, 8/16, -.5+1/16, 1/16}
	end

	minetest.register_node("digilines:wire_std_"..nodeid, {
		description = wiredesc,
		drawtype = "nodebox",
		tiles = tiles,
		inventory_image = "digiline_std_inv.png",
		wield_image = "digiline_std_inv.png",
		paramtype = "light",
		paramtype2 = "facedir",
		sunlight_propagates = true,
		digiline =
		{
			wire =
			{
				basename = "digilines:wire_std_",
				use_autoconnect = true
			}
		},
		selection_box = {
			type = "fixed",
			fixed = {-.5, -.5, -.5, .5, -.5+1/16, .5}
		},
		node_box = {
			type = "fixed",
			fixed = nodebox
		},
		groups = groups,
		walkable = false,
		stack_max = 99,
		drop = "digilines:wire_std_00000000"
	})
end
end
end
end
end
end
end
end


code:
minetest.register_on_placenode(function(pos, node)
	if minetest.registered_nodes[node.name].digiline then
		digilines.update_autoconnect(pos)
	end
end)

minetest.register_on_dignode(function(pos, node)
	if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].digiline then
-- need to make sure that node exists (unknown nodes!)
		digilines.update_autoconnect(pos)
	end
end)

function digilines.update_autoconnect(pos, secondcall)
	local xppos = {x=pos.x+1, y=pos.y, z=pos.z}
	local zppos = {x=pos.x, y=pos.y, z=pos.z+1}
	local xmpos = {x=pos.x-1, y=pos.y, z=pos.z}
	local zmpos = {x=pos.x, y=pos.y, z=pos.z-1}
	local xpympos = {x=pos.x+1, y=pos.y-1, z=pos.z}
	local zpympos = {x=pos.x, y=pos.y-1, z=pos.z+1}
	local xmympos = {x=pos.x-1, y=pos.y-1, z=pos.z}
	local zmympos = {x=pos.x, y=pos.y-1, z=pos.z-1}
	local xpypos = {x=pos.x+1, y=pos.y+1, z=pos.z}
	local zpypos = {x=pos.x, y=pos.y+1, z=pos.z+1}
	local xmypos = {x=pos.x-1, y=pos.y+1, z=pos.z}
	local zmypos = {x=pos.x, y=pos.y+1, z=pos.z-1}

	if secondcall == nil then
		digilines.update_autoconnect(xppos, true)
		digilines.update_autoconnect(zppos, true)
		digilines.update_autoconnect(xmpos, true)
		digilines.update_autoconnect(zmpos, true)

		digilines.update_autoconnect(xpypos, true)
		digilines.update_autoconnect(zpypos, true)
		digilines.update_autoconnect(xmypos, true)
		digilines.update_autoconnect(zmypos, true)

		digilines.update_autoconnect(xpympos, true)
		digilines.update_autoconnect(zpympos, true)
		digilines.update_autoconnect(xmympos, true)
		digilines.update_autoconnect(zmympos, true)
	end

	local def = minetest.registered_nodes[minetest.get_node(pos).name]
	local digilinespec = def and def.digiline
	if not (digilinespec and digilinespec.wire and
			digilinespec.wire.use_autoconnect) then
		return nil
	end

	local zmg = 	digilines.rules_link_anydir(pos, zmpos)
	local zmymg = 	digilines.rules_link_anydir(pos, zmympos)
	local xmg = 	digilines.rules_link_anydir(pos, xmpos)
	local xmymg = 	digilines.rules_link_anydir(pos, xmympos)
	local zpg = 	digilines.rules_link_anydir(pos, zppos)
	local zpymg = 	digilines.rules_link_anydir(pos, zpympos)
	local xpg = 	digilines.rules_link_anydir(pos, xppos)
	local xpymg = 	digilines.rules_link_anydir(pos, xpympos)

	local xpyg = digilines.rules_link_anydir(pos, xpypos)
	local zpyg = digilines.rules_link_anydir(pos, zpypos)
	local xmyg = digilines.rules_link_anydir(pos, xmypos)
	local zmyg = digilines.rules_link_anydir(pos, zmypos)

	local zm, xm, zp, xp, xpy, zpy, xmy, zmy
	if zmg or zmymg then zm = 1 else zm = 0 end
	if xmg or xmymg then xm = 1 else xm = 0 end
	if zpg or zpymg then zp = 1 else zp = 0 end
	if xpg or xpymg then xp = 1 else xp = 0 end

	if xpyg then xpy = 1 else xpy = 0 end
	if zpyg then zpy = 1 else zpy = 0 end
	if xmyg then xmy = 1 else xmy = 0 end
	if zmyg then zmy = 1 else zmy = 0 end

	if xpy == 1 then xp = 1 end
	if zpy == 1 then zp = 1 end
	if xmy == 1 then xm = 1 end
	if zmy == 1 then zm = 1 end

	local nodeid = 	tostring(xp )..tostring(zp )..tostring(xm )..tostring(zm )..
				tostring(xpy)..tostring(zpy)..tostring(xmy)..tostring(zmy)

	minetest.set_node(pos, {name = digilinespec.wire.basename..nodeid})
end


code:
# farming_nextGen

Credits:
tm3 for painting the seeder texture
TenPlus1 for his farming_redo mod

Full support of TenPlus1 farmingRedo.

This mod will give you the rechargeable
seeder. If technic mod is not present you will
wearout tools instead. Seeder and harvester can
be repaired on the anvil of anvil mod.

Put any seed on the right side of it in the hotbar
and leftclick on a piece of soil.
All soil will be seeded with your choosen seed while
all weed will be removed before, if any.

30/11/2018 added support of compost:garden_soil if compost mod is present


code:
technic?
farming_plus?
farming?


code:
-- The harvester

local S = farmingNG.S

    -- farming
	farmingNG.harvester_names["farming:wheat_8"] = true
	farmingNG.harvester_names["farming:wheat_7"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:wheat_6"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:cotton_8"] = true
	farmingNG.harvester_names["farming:cotton_7"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:cotton_6"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:weed"] 	= false
	farmingNG.harvester_names["farming:pumpkin"]	= true
	farmingNG.harvester_names["farming:barley_7"]	= true
	farmingNG.harvester_names["farming:barley_6"]	= farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:barley_5"]	= farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:blueberry_4"]	= true
	farmingNG.harvester_names["farming:carrot_8"]	= true
	farmingNG.harvester_names["farming:chili_8"]	= true
	farmingNG.harvester_names["farming:coffee_5"]	= true
	farmingNG.harvester_names["farming:corn_8"]	= true
	farmingNG.harvester_names["farming:cucumber_4"]	= true
	farmingNG.harvester_names["farming:garlic_5"]	= true
	farmingNG.harvester_names["farming:hemp_8"]	= true
	farmingNG.harvester_names["farming:melon_8"]	= true
	farmingNG.harvester_names["farming:onion_5"]	= true
	farmingNG.harvester_names["farming:pepper_5"]	= true
	farmingNG.harvester_names["farming:pineapple_8"]	= true
	farmingNG.harvester_names["farming:potato_4"]	= true
	farmingNG.harvester_names["farming:pumpkin_8"]	= true
	farmingNG.harvester_names["farming:raspberry_4"]	= true
	farmingNG.harvester_names["farming:rhubarb_3"]	= true
	farmingNG.harvester_names["farming:tomato_8"]	= true
	farmingNG.harvester_names["farming:grapes_8"]	= true
	farmingNG.harvester_names["farming:beanpole_5"]	= true
	farmingNG.harvester_names["farming:pea_5"]	= true
	farmingNG.harvester_names["farming:beetroot_5"]	= true
	farmingNG.harvester_names["farming:rice_8"] = true
	farmingNG.harvester_names["farming:rice_7"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:rice_6"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:oat_8"] = true
	farmingNG.harvester_names["farming:oat_7"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:oat_6"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:rye_8"] = true
	farmingNG.harvester_names["farming:rye_7"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:rye_6"] = farmingNG.harvester_nofullg
	farmingNG.harvester_names["farming:cabbage_6"] = true
	farmingNG.harvester_names["farming:mint_4"] = true

    -- beer_test
    farmingNG.harvester_names["beer_test:oats_8"]	= true

    -- farming_plus
    farmingNG.harvester_names["farming_plus:melon"]	= true
	farmingNG.harvester_names["farming_plus:tomato"] = true
	farmingNG.harvester_names["farming_plus:chilli"] = true
	farmingNG.harvester_names["farming_plus:garlic"] = true
	farmingNG.harvester_names["farming_plus:soy_plant"] = true
	farmingNG.harvester_names["farming_plus:cucumber"] = true
	farmingNG.harvester_names["farming_plus:coffee"] = true
	farmingNG.harvester_names["farming_plus:potato"] = true
	farmingNG.harvester_names["farming_plus:carrot"] = true
	farmingNG.harvester_names["farming_plus:garlic"] = true
	farmingNG.harvester_names["farming_plus:rhubarb"]= true
	farmingNG.harvester_names["farming_plus:barley_7"]= true
	farmingNG.harvester_names["farming_plus:hemp_8"]= true
	farmingNG.harvester_names["farming_plus:beanpole_5"]= true
	farmingNG.harvester_names["farming_plus:grapes_8"]= true
	farmingNG.harvester_names["farming_plus:corn"]	= true
	farmingNG.harvester_names["farming_plus:cornb"]	= true
	farmingNG.harvester_names["farming_plus:cornc"]	= true

if not farmingNG.havetech then
      farmingNG.harvester_charge_per_node = math.floor(65535 / farmingNG.harvester_max_charge * farmingNG.harvester_charge_per_node)
      farmingNG.harvester_max_charge = 65535
end

-- Table for saving what was sawed down
local produced = {}

-- Save the items sawed down so that we can drop them in a nice single stack
local function handle_drops(drops)
	for _, item in ipairs(drops) do
		local stack = ItemStack(item)
		local name = stack:get_name()
		local p = produced[name]
		if not p then
			produced[name] = stack
		else
			p:set_count(p:get_count() + stack:get_count())
		end
	end
end

-- This function does all the hard work. Recursively we dig the node at hand
-- if it is in the table and then search the surroundings for more stuff to dig.
local function recursive_harvest(pos, remaining_charge)
	if remaining_charge < farmingNG.harvester_charge_per_node then
		return remaining_charge
	end
	local node = minetest.get_node(pos)

	if not farmingNG.harvester_names[node.name] then
		return remaining_charge
	end

	handle_drops(minetest.get_node_drops(node.name, ""))
	minetest.remove_node(pos)
	remaining_charge = remaining_charge - farmingNG.harvester_charge_per_node
	if remaining_charge < 1 then remaining_charge = 1 end

	-- Check surroundings and run recursively if any charge left
	for npos in farmingNG.iterSawTries(pos) do
		if remaining_charge < farmingNG.harvester_charge_per_node then
			break
		end
		if farmingNG.harvester_names[minetest.get_node(npos).name] then
			remaining_charge = recursive_harvest(npos, remaining_charge)
		end
	end
	return remaining_charge
end

-- Function to randomize positions for new node drops
local function get_drop_pos(pos)
	local drop_pos = {}

	for i = 0, 8 do
		-- Randomize position for a new drop
		drop_pos.x = pos.x + math.random(-3, 3)
		drop_pos.y = pos.y - 1
		drop_pos.z = pos.z + math.random(-3, 3)

		-- Move the randomized position upwards until
		-- the node is air or unloaded.
		for y = drop_pos.y, drop_pos.y + 5 do
			drop_pos.y = y
			local node = minetest.get_node_or_nil(drop_pos)

			if not node then
				-- If the node is not loaded yet simply drop
				-- the item at the original digging position.
				return pos
			elseif node.name == "air" then
				-- Add variation to the entity drop position,
				-- but don't let drops get too close to the edge
				drop_pos.x = drop_pos.x + (math.random() * 0.8) - 0.5
				drop_pos.z = drop_pos.z + (math.random() * 0.8) - 0.5
				return drop_pos
			end
		end
	end

	-- Return the original position if this takes too long
	return pos
end

--  entry point
local function harvester_dig(pos, current_charge)
	-- Start sawing things down
	local remaining_charge = recursive_harvest(pos, current_charge)
	minetest.sound_play("farming_nextgen_seeder", {pos = pos, gain = 0.1,
			max_hear_distance = 10})

	-- Now drop items for the player
	for name, stack in pairs(produced) do
		-- Drop stacks of stack max or less
		local count, max = stack:get_count(), stack:get_stack_max()
		stack:set_count(max)
		while count > max do
			minetest.add_item(get_drop_pos(pos), stack)
			count = count - max
		end
		stack:set_count(count)
		minetest.add_item(get_drop_pos(pos), stack)
	end

	-- Clean up
	produced = {}

	return remaining_charge
end

if farmingNG.havetech then

	  technic.register_power_tool("farming_nextgen:harvester", farmingNG.harvester_max_charge)

	  minetest.register_tool("farming_nextgen:harvester", {
		  description = S("Harvester"),
		  inventory_image = "farming_nextgen_harvester.png",
		  stack_max = 1,
		  wear_represents = "technic_RE_charge",
		  on_refill = technic.refill_RE_charge,
		  on_use = function(itemstack, user, pointed_thing)
		    local name = user:get_player_name()

			  if pointed_thing.type ~= "node" then
				  return itemstack
			  end

			  local meta = minetest.deserialize(itemstack:get_metadata())
			  if not meta or not meta.charge or
					  meta.charge < farmingNG.harvester_charge_per_node then
				  return
			  end

			  if minetest.is_protected(pointed_thing.under, name) then
				  minetest.record_protection_violation(pointed_thing.under, name)
				  return
			  end

			  -- Send current charge to digging function so that the
			  -- harvester will stop after digging a number of nodes
			  meta.charge = harvester_dig(pointed_thing.under, meta.charge)
			  if not technic.creative_mode then
				  technic.set_RE_wear(itemstack, meta.charge, farmingNG.harvester_max_charge)
				  itemstack:set_metadata(minetest.serialize(meta))
			  end
			  return itemstack

		  end,
	  })

	  local mesecons_button = minetest.get_modpath("mesecons_button")
	  local trigger = mesecons_button and "mesecons_button:button_off" or "default:mese_crystal_fragment"

	  minetest.register_craft({
		  output = "farming_nextgen:harvester",
		  recipe = {
			  {"technic:battery", trigger,                      "technic:battery"},
			  {"technic:diamond_drill_head",      "technic:machine_casing",              "technic:diamond_drill_head"},
			  {"technic:rubber",                              "",                           "technic:rubber"},
		  }
	  })

else

		    minetest.register_tool("farming_nextgen:harvester", {
			    description = S("Harvester"),
			    groups = {soil=3,soil=2},
			    inventory_image = "farming_nextgen_harvester.png",
			    stack_max=1,
			    liquids_pointable = false,
			    on_use = function(itemstack, user, pointed_thing)
			      local seednum=0
			      local name = user:get_player_name()
			      local privs = minetest.get_player_privs(name)

				    if pointed_thing.type ~= "node" then
					    return itemstack
				    end

				    local charge = 65535 - itemstack:get_wear()

				    if not charge or
						    charge < farmingNG.harvester_charge_per_node then
						    minetest.chat_send_player(name,S(" *** Your device needs to be serviced"))
					    return
				    end

				    if minetest.is_protected(pointed_thing.under, name) then
					    minetest.record_protection_violation(pointed_thing.under, name)
					    return
				    end

				    charge = harvester_dig(pointed_thing.under, charge)
				    itemstack:set_wear(65535-charge)
				    return itemstack

			    end,
		    })

		    minetest.register_craft({
			    output = "farming_nextgen:harvester",
			    recipe = {
				    {"default:diamondblock",                                    "default:mese_crystal_fragment",                      "default:diamondblock"              },
				    {"default:gold_ingot",      "default:bronze_ingot",              "default:gold_ingot"},
				    {"default:mese_crystal_fragment",                              "",                                 "default:mese_crystal_fragment"},
			    }
		    })

end


code:
-- *** Farming_NextGen mod ***

farmingNG = {}
local path = minetest.get_modpath(minetest.get_current_modname())

if(minetest.get_translator ~= nil) then
    farmingNG.S = minetest.get_translator(minetest.get_current_modname())
else
    farmingNG.S = function ( s ) return s end
end

farmingNG.seeder_seed = {}
farmingNG.seeder_utils = {}
farmingNG.harvester_names = {}

-- register_seed(Seed ,Plantname)
-- Seed = fully name of the seed like "farming:seed_cotton"
-- Plantname = fully Name of the plant like "farming:cotton_1"

function farmingNG.register_seed(seed, plant)
    if(seed ~= "" and plant ~= "") then
       local new_seed = {}
       new_seed = {seed, plant}
       table.insert(farmingNG.seeder_seed, new_seed)
       return true
    end

    return false

end -- register_seed

-- register_util(Seedling, Util)
-- Seedling = fully name of the seedling like "farming_nextgen:grape_seedling"
-- Plantname = fully Name of the tool like "farming_plus:grapes_1"

function farmingNG.register_util(seedling, util)
    if(seedling ~= "" and util ~= "") then
        local new_util = {}
        new_util = {seedling, util}
       table.insert(farmingNG.seeder_utils, new_util)
       return true
    end

    return false

end -- register_seed

dofile(path.."/settings.lua")
dofile(path.."/seeder.lua")

if  farmingNG.harvester_machine then
      dofile(path.."/harvester.lua")

    -- register_harvestername(plantname)
    -- Plantname = fully Name of the plant like "farming:cotton_8"

    function farmingNG.register_harvest(plantname)
        if(plantname ~= "") then
            farmingNG.harvester_names[plantname] = true
            return true

        end -- if(plantname

        return false

    end -- function farmingNG.register_harvestername

else
    function farmingNG.register_harvestername(plantname)
        return false

    end -- function farmingNG.register_harvestername

end -- if(farmingNG.harvester_maschine

-- The following is only on Jungle Server valid
if farmingNG.havetech then
	-- compatibility alias
	minetest.register_alias("technic:seeder", "farming_nextgen:seeder")
end

print("[MOD] " .. minetest.get_current_modname() .. " loaded.")


code:
# textdomain: farming_nextgen

### harvester.lua ###

Harvester=Erntemaschine

### harvester.lua ###
### seeder.lua ###

 *** Your device needs to be serviced= *** Dein Gerät muß repariert werden

### seeder.lua ###

 *** you need valid seeds on the right side of your device= *** du brauchst gültige Samen an der rechten Seite deines Gerätes
*** You used :  @1 seeds=*** Du brauchtest : @1 Samen
*** You used : @1 seeds.=*** Du brauchtest : @1 Samen.
A bean seedling for the seeder=Ein Bohnensetzling für die Saatmaschine
A grape seedling for the seeder=Ein Traubensetzling für die Saatmaschine
Automatik seeding tool=Automatische Saatmaschine
Charge for @1 seeds left.=Insgesamt noch @1 Samen über.
Seed Machine=Saatmaschine


code:
# textdomain: farming_nextgen

### harvester.lua ###

Harvester=Erntemaschine

### harvester.lua ###
### seeder.lua ###

 *** Your device needs to be serviced= *** Dein Gerät muß repariert werden

### seeder.lua ###

 *** you need valid seeds on the right side of your device= *** du brauchst gültige Samen an der rechten Seite deines Gerätes
*** You used :  @1 seeds=*** Du brauchtest : @1 Samen
*** You used : @1 seeds.@\n=*** Du brauchtest : @1 Samen.@\n
A bean seedling for the seeder=Ein Bohnensetzling für die Saatmaschine
A grape seedling for the seeder=Ein Traubensetzling für die Saatmaschine
Automatik seeding tool=Automatische Saatmaschine
Charge for @1 seeds left.=Insgesamt noch @1 Samen über.
Seed Machine=Saatmaschine

##### not used anymore #####

*** You used : @1 seeds.@\n=*** Du brauchtest : @1 Samen.@\n


code:
# textdomain: farming_nextgen

### harvester.lua ###

Harvester=

### harvester.lua ###
### seeder.lua ###

 *** Your device needs to be serviced=

### seeder.lua ###

 *** you need valid seeds on the right side of your device=
*** You used :  @1 seeds=
*** You used : @1 seeds.=
A bean seedling for the seeder=
A grape seedling for the seeder=
Automatik seeding tool=
Charge for @1 seeds left.=
Seed Machine=


code:
name = farming_nextgen
optional depends = technic, farming_plus, farming


code:
--*******************************************************
--****                 The Seeder
--**** All coding made by Gundul except recursive_dig
--**** was taken from technic:chainsaw mod coded by
--**** Maciej Kasatkin (RealBadAngel)
--*******************************************************

local farm_redo = false
local S = farmingNG.S

-- different values if technic not present
if not farmingNG.havetech then
      farmingNG.seeder_charge_per_node = math.floor(65535 / farmingNG.seeder_max_charge * farmingNG.seeder_charge_per_node)
      farmingNG.seeder_max_charge = 65535
end

--check for farming redo mod
if minetest.global_exists("farming") then
    if farming.mod == "redo" then farm_redo = true end
end

-- grapes and beans from farming_plus need helpers to grow
if minetest.get_modpath("farming_plus") or farm_redo then

      minetest.register_craftitem("farming_nextgen:grape_seedling", {
	    description = S("A grape seedling for the seeder"),
	    inventory_image = "farming_grapes_1.png"
      })

      minetest.register_craftitem("farming_nextgen:bean_seedling", {
	    description = S("A bean seedling for the seeder"),
	    inventory_image = "farming_beanpole_1.png"
      })

      if not farm_redo then
	    minetest.register_craft({
			type = "shapeless",
			output = "farming_nextgen:grape_seedling",
			recipe = {"farming_plus:trellis","farming_plus:grapes"}
	    })

	    minetest.register_craft({
			type = "shapeless",
			output = "farming_nextgen:bean_seedling",
			recipe = {"farming_plus:beanpole","farming_plus:beans"}
	    })
      else
	    minetest.register_craft({
			type = "shapeless",
			output = "farming_nextgen:grape_seedling",
			recipe = {"farming:trellis","farming:grapes"}
	    })

	    minetest.register_craft({
			type = "shapeless",
			output = "farming_nextgen:bean_seedling",
			recipe = {"farming:beanpole","farming:beans"}
	    })
      end

end

-- The default soils
local soil_nodenames = {
	["farming:soil"] 	 			= true,
	["farming:soil_wet"] 			= true,
	["farming:desert_sand_soil"]    = true,
	["farming:desert_sand_soil_wet"]= true,
	["farming:dry_soil"]			= true,
	["farming:dry_soil_wet"]		= true
}

--support compost mod
if minetest.get_modpath("compost") then

	soil_nodenames["compost:garden_soil"] = true
end

farmingNG.seeder_seed = {
-- *** farming
		{"farming:seed_barley", "farming:barley_1"},
		{"farming:seed_hemp", "farming:hemp_1"},
		{"farming:pumpkin_seed", "farming:pumpkin_1"},
		{"farming:coffee_beans", "farming:coffee_1"},
		{"farming:chili_pepper", "farming:chili_1"},
		{"farming:carrot", "farming:carrot_1"},
		{"farming:corn", "farming:corn_1"},
		{"farming:cucumber", "farming:cucumber_1"},
		{"farming:garlic_clove", "farming:garlic_1"},
		{"farming:melon_slice", "farming:melon_1"},
		{"farming:onion", "farming:onion_1"},
		{"farming:peppercorn", "farming:pepper_1"},
		{"farming:pineapple_top", "farming:pineapple_1"},
		{"farming:potato", "farming:potato_1"},
		{"farming:pumpkin_slice", "farming:pumpkin_1"},
		{"farming:raspberries", "farming:raspberry_1"},
		{"farming:rhubarb", "farming:rhubarb_1"},
		{"farming:tomato", "farming:tomato_1"},
		{"farming:blueberries", "farming:blueberry_1"},
		{"farming:pea_pod", "farming:pea_1"},
		{"farming:beetroot", "farming:beetroot_1"},
		{"farming:seed_rice", "farming:rice_1"},
		{"farming:seed_oat", "farming:oat_1"},
		{"farming:seed_rye", "farming:rye_1"},
		{"farming:cabbage", "farming:cabbage_1"},
		{"farming:seed_mint", "farming:mint_1"},

-- *** farming_plus
	    {"farming_plus:carrot_seed", "farming_plus:carrot_1"},
	    {"farming_plus:chilli_seeds", "farming_plus:chilli_1"},
	    {"farming_plus:coffee_beans", "farming_plus:coffee_1"},
	    {"farming_plus:corn_seed", "farming_plus:corn_1"},
	    {"farming_plus:cucumber_seed", "farming_plus:cucumber_1"},
	    {"farming_plus:garlic_seed", "farming_plus:garlic_1"},
	    {"farming_plus:seed_hemp", "farming_plus:hemp_1"},
	    {"farming_plus:melon_seed", "farming_plus:melon_1"},
	    {"farming_plus:potato_seed", "farming_plus:potato_1"},
	    {"farming_plus:rhubarb_seed", "farming_plus:rhubarb_1"},
	    {"farming_plus:raspberry_seed", "farming_plus:raspberry_1"},
	    {"farming_plus:strawberry_seed", "farming_plus:strawberry_1"},
	    {"farming_plus:soy_seed", "farming_plus:soy_plant_1"},
	    {"farming_plus:tomato_seed", "farming_plus:tomato_1"},
	    {"farming_plus:walnut_item", "farming_plus:walnut_1"},
	    {"farming_plus:orange_seed", "farming_plus:orange_1"},
	    {"farming_plus:lemon_seed", "farming_plus:lemon_1"},
	    {"farming_plus:peach_seed", "farming_plus:peach_1"},
	    {"farming_plus:seed_barley", "farming_plus:barley_1"},
	    {"farming_plus:coffee_beans", "farming_plus:coffee_1"},

-- *** beer_test
	    {"beer_test:seed_oats", "beer_test:seed_oats"},

-- If you have Problems with growing wheat and cotton, then try the two lines below
	    {"farming:seed_wheat", "farming:wheat_1"},
	    {"farming:seed_cotton", "farming:cotton_1"}

-- If you haven't any Problems with growing wheat and cotton, then use the two lines below
--	    {"farming:seed_wheat", "farming:seed_wheat"},
--	    {"farming:seed_cotton", "farming:seed_cotton"}

}

-- wine and beans need climbing utilities

farmingNG.seeder_utils = {
  {"farming_nextgen:grape_seedling", "farming_plus:grapes_1"},
  {"farming_nextgen:bean_seedling", "farming_plus:beanpole_1"}
}

if farm_redo then
     farmingNG.seeder_utils = {
      {"farming_nextgen:grape_seedling", "farming:grapes_1"},
      {"farming_nextgen:bean_seedling", "farming:beanpole_1"}
      }
end

local function check_valid_util(sname)
     for i in ipairs(farmingNG.seeder_utils) do
      if sname == farmingNG.seeder_utils[i][1] then return true end
     end
    return false
end

-- function to check for valid seeds
local function check_valid_seed(sname)

    for i in ipairs(farmingNG.seeder_seed) do
      if sname == farmingNG.seeder_seed[i][1] then return true end
    end
    return false
end

--function to give name of seedlings
local function give_seedling(sname, util)

     if not util then
	  for i in ipairs(farmingNG.seeder_seed) do
	    if sname == farmingNG.seeder_seed[i][1] then return farmingNG.seeder_seed[i][2] end
	  end
     else
	  for i in ipairs(farmingNG.seeder_utils) do
	    if sname ==farmingNG.seeder_utils[i][1] then return farmingNG.seeder_utils[i][2] end
	  end
     end
    return nil
end

--- Iterator over positions to try to saw around a sawed node.
-- This returns positions in a 3x1x3 area around the position, plus the
-- position above it.  This does not return the bottom position to prevent
-- the seeder from cutting down nodes below the cutting position.
-- @param pos Sawing position.
function farmingNG.iterSawTries(pos)
	-- Copy position to prevent mangling it
	local pos = vector.new(pos)
	local i = 0

	return function()
		i = i + 1
		-- Given a (top view) area like so (where 5 is the starting position):
		-- X -->
		-- Z 123
		-- | 456
		-- V 789
		-- This will return positions 1, 4, 7, 2, 8 (skip 5), 3, 6, 9,
		-- and the position above 5.
		if i == 1 then
			-- Move to starting position
			pos.x = pos.x - 1
			pos.z = pos.z - 1
		elseif i == 4 or i == 7 then
			-- Move to next X and back to start of Z when we reach
			-- the end of a Z line.
			pos.x = pos.x + 1
			pos.z = pos.z - 2
		elseif i == 5 then
			-- Skip the middle position (we've already run on it)
			-- and double-increment the counter.
			pos.z = pos.z + 2
			i = i + 1
		elseif i <= 9 then
			-- Go to next Z.
			pos.z = pos.z + 1
		elseif i == 10 then
			-- Move back to center and up.
			-- The Y+ position must be last so that we don't dig
			-- straight upward and not come down (since the Y-
			-- position isn't checked).
			pos.x = pos.x - 1
			pos.z = pos.z - 1
			pos.y = pos.y + 1
		else
			return nil
		end
		return pos
	end
end

-- This function does all the hard work. Recursively we dig the node at hand
-- if it is in the table and then search the surroundings for more stuff to dig.
local function recursive_dig(pos, remaining_charge, seednum,seedstack, user)
	local uppos = {x =pos.x, y =(pos.y) +1,z =pos.z}
	local toppos = {x =pos.x, y =(pos.y) +2,z =pos.z}
	local name = user:get_player_name()

	if remaining_charge < farmingNG.seeder_charge_per_node or seedstack:is_empty() then
		return remaining_charge, seednum, seedstack
	end
	local node = minetest.get_node(pos)
	local upper = minetest.get_node(uppos)
	local top = minetest.get_node(toppos)
	local seedname = seedstack:get_name()
	local helpers = check_valid_util(upper.name)

	if node.name == "farming:weed" then
	    remaining_charge, seednum, seedstack = recursive_dig( {x=pos.x, y=pos.y-1, z=pos.z}, remaining_charge, seednum, seedstack, user)
	    return remaining_charge, seednum, seedstack
	end

	if not soil_nodenames[node.name] then
		return remaining_charge, seednum, seedstack
	end

	if not check_valid_util(seedname) then
	      if upper.name == "air" or upper.name == "farming:weed" or string.match(upper.name,"default:grass")then
		    minetest.set_node(uppos, {name="air"})
		    remaining_charge = remaining_charge - farmingNG.seeder_charge_per_node
		    seednum = seednum +1
		    seedstack:take_item()
		    if remaining_charge < 1 then remaining_charge = 1 end

		    if give_seedling(seedname,false) then
			  minetest.add_node(uppos, {name = give_seedling(seedname,false), param2 = 1})
			  minetest.get_node_timer(uppos):start(math.random(166, 286))
		    end
	      else
		    return remaining_charge, seednum, seedstack
	      end
	else
	     if (upper.name == "air" or upper.name == "farming:weed" or string.match(upper.name,"default:grass")) and top.name == "air" then
		    minetest.set_node(uppos, {name="air"})
		    remaining_charge = remaining_charge - farmingNG.seeder_charge_per_node
		    seednum = seednum +1
		    seedstack:take_item()
		    if remaining_charge < 1 then remaining_charge = 1 end

		    if give_seedling(seedname, true) then
			  minetest.add_node(uppos, {name = give_seedling(seedname, true), param2 = 1})
			  minetest.get_node_timer(uppos):start(math.random(166, 286))
		    end
	     else
		    return remaining_charge, seednum, seedstack
	     end
	end

	-- Check surroundings and run recursively if any charge left
	for npos in farmingNG.iterSawTries(pos) do
		if remaining_charge < farmingNG.seeder_charge_per_node then
			break
		end
		if soil_nodenames[minetest.get_node(npos).name] then
			remaining_charge, seednum, seedstack = recursive_dig(npos, remaining_charge, seednum, seedstack, user)
		end
	end
	return remaining_charge, seednum, seedstack
end

-- Seeder entry point
local function seeder_dig(pos, current_charge, seednum, seedstack, user)
	-- Start sawing things down
	local remaining_charge, seednum, seedstack = recursive_dig(pos, current_charge, seednum, seedstack, user)
	minetest.sound_play("farming_nextgen_seeder", {pos = pos, gain = 0.1, max_hear_distance = 10})
	return remaining_charge, seednum, seedstack
end

if farmingNG.havetech then

	  --local S = technic.getter

	  technic.register_power_tool("farming_nextgen:seeder", farmingNG.seeder_max_charge)

	  minetest.register_tool("farming_nextgen:seeder", {
		  description = S("Seed Machine"),
		  inventory_image = "farming_nextgen_seeder.png",
		  stack_max = 1,
		  wear_represents = "technic_RE_charge",
		  on_refill = technic.refill_RE_charge,
		  on_use = function(itemstack, user, pointed_thing)
		    local seednum=0
		    local name = user:get_player_name()
		    local privs = minetest.get_player_privs(name)

			  if pointed_thing.type ~= "node" then
				  return itemstack
			  end

			  local meta = minetest.deserialize(itemstack:get_metadata())
			  if not meta or not meta.charge or
					  meta.charge < farmingNG.seeder_charge_per_node then
				  return
			  end

			  local inv = user:get_inventory()
			  local indexnumber = user:get_wield_index()+1
			  local seedstack = inv:get_stack("main", indexnumber)
			  local seedname = seedstack:get_name()

			  if minetest.is_protected(pointed_thing.under, name) then
				  minetest.record_protection_violation(pointed_thing.under, name)
				  return
			  end

			  -- Send current charge to digging function so that the
			  -- seeder will stop after digging a number of nodes
			  if seedname then

			    if check_valid_seed(seedname) or check_valid_util(seedname) then
				meta.charge, seednum, seedstack = seeder_dig(pointed_thing.under, meta.charge, seednum, seedstack, user)
				minetest.chat_send_player(name,S("*** You used :  @1 seeds",seednum))
			    else
				minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
			    end

			  else
			      minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
			  end

			  if not technic.creative_mode then
				  technic.set_RE_wear(itemstack, meta.charge, farmingNG.seeder_max_charge)
				  itemstack:set_metadata(minetest.serialize(meta))
			  end
			  inv:set_stack("main", indexnumber, seedstack)
			  return itemstack

		  end,
	  })

	  local mesecons_button = minetest.get_modpath("mesecons_button")
	  local trigger = mesecons_button and "mesecons_button:button_off" or "default:mese_crystal_fragment"

	  if farmingNG.easy then
		    minetest.register_craft({
			    output = "farming_nextgen:seeder",
			    recipe = {
				    {"technic:battery",                                    trigger,                      "technic:battery"              },
				    {"technic:stainless_steel_ingot",      "technic:stainless_steel_ingot",              "technic:stainless_steel_ingot"},
				    {"default:diamond",                              "",                                 "default:diamond"},
			    }
		    })
	  else
		    minetest.register_craft({
				    output = "farming_nextgen:seeder",
				    recipe = {
					    {"technic:red_energy_crystal",                                    trigger,                      "technic:red_energy_crystal"              },
					    {"technic:composite_plate",      "technic:composite_plate",              "technic:composite_plate"},
					    {"technic:rubber",                              "",                                 "technic:rubber"},
				    }
			    })
	  end

else

	  minetest.register_tool("farming_nextgen:seeder", {
		  description = S("Automatik seeding tool"),
		  groups = {soil=3,soil=2},
		  inventory_image = "farming_nextgen_seeder.png",
		  stack_max=1,
		  liquids_pointable = false,
		  on_use = function(itemstack, user, pointed_thing)
		    local seednum=0
		    local name = user:get_player_name()
		    local privs = minetest.get_player_privs(name)

			  if pointed_thing.type ~= "node" then
				  return itemstack
			  end

			  local charge = 65535 - itemstack:get_wear()

			  if not charge or
					  charge < farmingNG.seeder_charge_per_node then
					  minetest.chat_send_player(name,S(" *** Your device needs to be serviced"))
				  return
			  end

			  local inv = user:get_inventory()
			  local indexnumber = user:get_wield_index()+1
			  local seedstack = inv:get_stack("main", indexnumber)
			  local seedname = seedstack:get_name()

			  if minetest.is_protected(pointed_thing.under, name) then
				  minetest.record_protection_violation(pointed_thing.under, name)
				  return
			  end

			  if seedname then
			    if check_valid_seed(seedname) or check_valid_util(seedname) then
				charge, seednum, seedstack = seeder_dig(pointed_thing.under, charge, seednum, seedstack, user)
				if farmingNG.chaton then
				     minetest.chat_send_player(name,S("*** You used : @1 seeds.",seednum) .. "\n" ..
                                                    S("Charge for @1 seeds left.",math.floor(charge/farmingNG.seeder_charge_per_node))
                                              )
				end
			    else
				minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
			    end
			  else
			      minetest.chat_send_player(name,S(" *** you need valid seeds on the right side of your device"))
			  end

			  itemstack:set_wear(65535-charge)

			  inv:set_stack("main", indexnumber, seedstack)
			  return itemstack

		  end,
	  })

	  minetest.register_craft({
		  output = "farming_nextgen:seeder",
		  recipe = {
			  {"default:mese",                                    "default:mese_crystal_fragment",                      "default:mese"              },
			  {"default:gold_ingot",      "default:bronze_ingot",              "default:gold_ingot"},
			  {"default:diamond",                              "",                                 "default:diamond"},
		  }
	  })
end


code:
--
-- The settings section for seeder
--
--
--
farmingNG.havetech = minetest.get_modpath("technic")		-- Is technic mod present ? If not use wearout tool instead
--
--
farmingNG.seeder_max_charge      =  minetest.settings:get("farmingNG_seeder_max_charge") or 900000      			-- Maximum charge of the seeder
farmingNG.seeder_charge_per_node = minetest.settings:get("farmingNG_seeder_charge_per_node") or 1800				-- How much it costs to place a seed
--
farmingNG.chaton = minetest.settings:get_bool("farmingNG_chaton", false)					-- more verbose chat messages
farmingNG.easy = minetest.settings:get_bool("farmingNG_easy", false)						-- easy recipe if technic mod is present
--
farmingNG.harvester_max_charge      = minetest.settings:get("farmingNG_harvester_max_charge") or 650000 			-- Maximum charge of the harvester
farmingNG.harvester_charge_per_node = minetest.settings:get("farmingNG_harvester_charge_per_node") or 1300 			-- Costs of harvesting one node
farmingNG.harvester_machine 	= minetest.settings:get_bool("farmingNG_harvester_machine", true)    				-- make the tool available
farmingNG.harvester_nofullg     = minetest.settings:get_bool("farmingNG_harvester_nofullg", true)    				-- harvests also wheat_7, rice_7 etc no need to wait until full grown


code:
#farmingNG settings

#maximum charge of the seeder, lower values mean faster load if technic present
farmingNG_seeder_max_charge (Maximum charge of the seeder) int  900000

#costs to place a seed: maxcharge devided by charge_per_node = number of
#nodes which can be placed (default 900000 / 1800 = 500 nodes)
farmingNG_seeder_charge_per_node (How much it costs to place a seed) int 1800

#more verbose, tells you how many seeds were used and more
farmingNG_chaton (more verbose chat messages) bool false

#less expensive recipe if technic mod is present
farmingNG_easy (easy recipe if technic mod is present) bool false

#maximum charge of the harvster, lower values mean faster load if technic present
farmingNG_harvester_max_charge (Maximum charge of the harvester) int 650000

#costs to place a seed: maxcharge devided by charge_per_node = number of
#nodes which can be harvested (default 650000 / 1300 = 500 nodes)
farmingNG_harvester_charge_per_node (Costs of harvesting one node) int 1300

#plants like wheat, rice, oat etc do not grow equally but already give drops
#if only 90% grown, set to false if you only want to harvest 100% grown nodes
farmingNG_harvester_nofullg (harvest not already fully grown) bool true

#set to false if you you do not need the harvester
farmingNG_harvester_machine (harvester tool available) bool true


code:
# Minetest mod first_hour

This mod makes a player invicible during his first hour on a server. Moreover, the player is not able to hit the other players during this hour.