initial commit

master
Juraj Vajda 2016-12-11 02:23:08 +01:00
commit 4aed8f559e
46 changed files with 5410 additions and 0 deletions

22
README Normal file
View File

@ -0,0 +1,22 @@
BASIC_MACHINES: lightweight automation mod for minetest
minetest 0.4.14
(c) 2015-2016 rnd
MANUAL:
1.WIKI PAGES: https://github.com/ac-minetest/basic_machines/wiki
2.ingame help: right click mover/detector/keypad.. and click help button
---------------------------------------------------------------------
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.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
----------------------------------------------------------------------

347
autocrafter.lua Normal file
View File

@ -0,0 +1,347 @@
-- modified and adapted from pipeworks mod by VanessaE
-- by rnd
-- disabled timers and on/off button, now autocrafter is only activated by signal
local autocrafterCache = {} -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second
local craft_time = 1
local function count_index(invlist)
local index = {}
for _, stack in pairs(invlist) do
if not stack:is_empty() then
local stack_name = stack:get_name()
index[stack_name] = (index[stack_name] or 0) + stack:get_count()
end
end
return index
end
local function get_item_info(stack)
local name = stack:get_name()
local def = minetest.registered_items[name]
local description = def and def.description or "Unknown item"
return description, name
end
local function get_craft(pos, inventory, hash)
local hash = hash or minetest.hash_node_position(pos)
local craft = autocrafterCache[hash]
if not craft then
local recipe = inventory:get_list("recipe")
local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
autocrafterCache[hash] = craft
end
return craft
end
local function autocraft(inventory, craft)
if not craft then return false end
local output_item = craft.output.item
-- check if we have enough room in dst
if not inventory:room_for_item("dst", output_item) then return false end
local consumption = craft.consumption
local inv_index = count_index(inventory:get_list("src"))
-- check if we have enough material available
for itemname, number in pairs(consumption) do
if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
end
-- consume material
for itemname, number in pairs(consumption) do
for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
inventory:remove_item("src", ItemStack(itemname))
end
end
-- craft the result into the dst inventory and add any "replacements" as well
inventory:add_item("dst", output_item)
for i = 1, 9 do
inventory:add_item("dst", craft.decremented_input.items[i])
end
return true
end
-- returns false to stop the timer, true to continue running
-- is started only from start_autocrafter(pos) after sanity checks and cached recipe
local function run_autocrafter(pos, elapsed)
local meta = minetest.get_meta(pos)
local inventory = meta:get_inventory()
local craft = get_craft(pos, inventory)
local output_item = craft.output.item
-- only use crafts that have an actual result
if output_item:is_empty() then
meta:set_string("infotext", "unconfigured Autocrafter: unknown recipe")
return false
end
for step = 1, math.floor(elapsed/craft_time) do
local continue = autocraft(inventory, craft)
if not continue then return false end
end
return true
end
local function start_crafter(pos) -- rnd we dont need timer anymore
-- local meta = minetest.get_meta(pos)
-- if meta:get_int("enabled") == 1 then
-- local timer = minetest.get_node_timer(pos)
-- if not timer:is_started() then
-- timer:start(craft_time)
-- end
-- end
end
local function after_inventory_change(pos)
start_crafter(pos)
end
-- note, that this function assumes allready being updated to virtual items
-- and doesn't handle recipes with stacksizes > 1
local function after_recipe_change(pos, inventory)
local meta = minetest.get_meta(pos)
-- if we emptied the grid, there's no point in keeping it running or cached
if inventory:is_empty("recipe") then
--minetest.get_node_timer(pos):stop()
autocrafterCache[minetest.hash_node_position(pos)] = nil
meta:set_string("infotext", "unconfigured Autocrafter")
return
end
local recipe_changed = false
local recipe = inventory:get_list("recipe")
local hash = minetest.hash_node_position(pos)
local craft = autocrafterCache[hash]
if craft then
-- check if it changed
local cached_recipe = craft.recipe
for i = 1, 9 do
if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
autocrafterCache[hash] = nil -- invalidate recipe
craft = nil
break
end
end
end
craft = craft or get_craft(pos, inventory, hash)
local output_item = craft.output.item
local description, name = get_item_info(output_item)
meta:set_string("infotext", string.format("'%s' Autocrafter (%s)", description, name))
inventory:set_stack("output", 1, output_item)
after_inventory_change(pos)
end
-- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
-- if minetest supports query by group one day, this might replace them
-- with a canonical version instead
local function normalize(item_list)
for i = 1, #item_list do
local name = item_list[i]
if not minetest.registered_items[name] then
item_list[i] = ""
end
end
return item_list
end
local function on_output_change(pos, inventory, stack)
if not stack then
inventory:set_list("output", {})
inventory:set_list("recipe", {})
else
local input = minetest.get_craft_recipe(stack:get_name())
if not input.items or input.type ~= "normal" then return end
local items, width = normalize(input.items), input.width
local item_idx, width_idx = 1, 1
for i = 1, 9 do
if width_idx <= width then
inventory:set_stack("recipe", i, items[item_idx])
item_idx = item_idx + 1
else
inventory:set_stack("recipe", i, ItemStack(""))
end
width_idx = (width_idx < 3) and (width_idx + 1) or 1
end
-- we'll set the output slot in after_recipe_change to the actual result of the new recipe
end
after_recipe_change(pos, inventory)
end
-- returns false if we shouldn't bother attempting to start the timer again after this
local function update_meta(meta, enabled)
--local state = enabled and "on" or "off"
--meta:set_int("enabled", enabled and 1 or 0)
meta:set_string("formspec",
"size[8,11]"..
"list[context;recipe;0,0;3,3;]"..
"image[3,1;1,1;gui_hb_bg.png^[colorize:#141318:255]"..
"list[context;output;3,1;1,1;]"..
--"image_button[3,2;1,1;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" .. -- rnd disable button
"list[context;src;0,3.5;8,3;]"..
"list[context;dst;4,0;4,3;]"..
default.gui_bg..
default.gui_bg_img..
default.gui_slots..
default.get_hotbar_bg(0,7) ..
"list[current_player;main;0,7;8,4;]")
-- toggling the button doesn't quite call for running a recipe change check
-- so instead we run a minimal version for infotext setting only
-- this might be more written code, but actually executes less
local output = meta:get_inventory():get_stack("output", 1)
if output:is_empty() then -- doesn't matter if paused or not
meta:set_string("infotext", "unconfigured Autocrafter: Place items for recipe top left. To operate place required items in bottom space (src inventory) and activated with keypad signal. Obtain crafted item from top right (dst inventory).")
return false
end
local description, name = get_item_info(output)
local infotext = enabled and string.format("'%s' Autocrafter (%s)", description, name)
or string.format("paused '%s' Autocrafter", description)
meta:set_string("infotext", infotext)
return enabled
end
-- 1st version of the autocrafter had actual items in the crafting grid
-- the 2nd replaced these with virtual items, dropped the content on update and set "virtual_items" to string "1"
-- the third added an output inventory, changed the formspec and added a button for enabling/disabling
-- so we work out way backwards on this history and update each single case to the newest version
local function upgrade_autocrafter(pos, meta)
local meta = meta or minetest.get_meta(pos)
local inv = meta:get_inventory()
if inv:get_size("output") == 0 then -- we are version 2 or 1
inv:set_size("output", 1)
-- migrate the old autocrafters into an "enabled" state
update_meta(meta, true)
if meta:get_string("virtual_items") == "1" then -- we are version 2
-- we allready dropped stuff, so lets remove the metadatasetting (we are not being called again for this node)
meta:set_string("virtual_items", "")
else -- we are version 1
local recipe = inv:get_list("recipe")
if not recipe then return end
for idx, stack in ipairs(recipe) do
if not stack:is_empty() then
minetest.item_drop(stack, "", pos)
stack:set_count(1)
stack:set_wear(0)
inv:set_stack("recipe", idx, stack)
end
end
end
-- update the recipe, cache, and start the crafter
autocrafterCache[minetest.hash_node_position(pos)] = nil
after_recipe_change(pos, inv)
end
end
minetest.register_node("basic_machines:autocrafter", {
description = "Autocrafter",
drawtype = "normal",
tiles = {"pipeworks_autocrafter.png"},
groups = {snappy = 3, tubedevice = 1, tubedevice_receiver = 1},
on_construct = function(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
inv:set_size("src", 3*8)
inv:set_size("recipe", 3*3)
inv:set_size("dst", 4*3)
inv:set_size("output", 1)
update_meta(meta, false)
end,
on_receive_fields = function(pos, formname, fields, sender)
--if not pipeworks.may_configure(pos, sender) then return end
local meta = minetest.get_meta(pos)
if fields.on then
update_meta(meta, false)
--minetest.get_node_timer(pos):stop()
elseif fields.off then
if update_meta(meta, true) then
start_crafter(pos)
end
end
end,
can_dig = function(pos, player)
upgrade_autocrafter(pos)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return (inv:is_empty("src") and inv:is_empty("dst"))
end,
after_place_node = function(pos, placer) -- rnd : set owner
local meta = minetest.get_meta(pos);
meta:set_string("owner", placer:get_player_name());
end,
--after_place_node = pipeworks.scan_for_tube_objects,
--after_dig_node = function(pos)
--pipeworks.scan_for_tube_objects(pos)
--end,
on_destruct = function(pos)
autocrafterCache[minetest.hash_node_position(pos)] = nil
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
--if not pipeworks.may_configure(pos, player) then return 0 end
local meta = minetest.get_meta(pos);if meta:get_string("owner")~=player:get_player_name() then return 0 end -- rnd
upgrade_autocrafter(pos)
local inv = minetest.get_meta(pos):get_inventory()
if listname == "recipe" then
stack:set_count(1)
inv:set_stack(listname, index, stack)
after_recipe_change(pos, inv)
return 0
elseif listname == "output" then
on_output_change(pos, inv, stack)
return 0
end
after_inventory_change(pos)
return stack:get_count()
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
--if not pipeworks.may_configure(pos, player) then
-- minetest.log("action", string.format("%s attempted to take from autocrafter at %s", player:get_player_name(), minetest.pos_to_string(pos)))
-- return 0
-- end
local meta = minetest.get_meta(pos);if meta:get_string("owner")~=player:get_player_name() then return 0 end -- rnd
upgrade_autocrafter(pos)
local inv = minetest.get_meta(pos):get_inventory()
if listname == "recipe" then
inv:set_stack(listname, index, ItemStack(""))
after_recipe_change(pos, inv)
return 0
elseif listname == "output" then
on_output_change(pos, inv, nil)
return 0
end
after_inventory_change(pos)
return stack:get_count()
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0; -- no internal inventory moves!
end,
mesecons = {effector = { -- rnd: run machine when activated by signal
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
run_autocrafter(pos, craft_time);
end
}
}
--on_timer = run_autocrafter -- rnd
})
-- minetest.register_craft( {
-- output = "basic_machines:autocrafter",
-- recipe = {
-- { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" },
-- { "default:diamondblock", "default:steel_ingot", "default:diamondblock" },
-- { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" }
-- },
-- })

629
ball.lua Normal file
View File

@ -0,0 +1,629 @@
-- BALL: energy ball that flies around, can bounce and activate stuff
-- rnd 2016:
-- TO DO: move mode: ball just rolling around on ground without hopping, also if inside slope it would "roll down", just increased velocity in slope direction
-- SETTINGS
basic_machines.ball = {};
basic_machines.ball.maxdamage = 10; -- player health 20
basic_machines.ball.bounce_materials = { -- to be used with bounce setting 2 in ball spawner: 1: bounce in x direction, 2: bounce in z direction, otherwise it bounces in y direction
["default:wood"]=1,
["xpanes:bar_2"]=1,
["xpanes:bar_10"]=1,
["darkage:iron_bars"]=1,
["default:glass"] = 2,
};
-- END OF SETTINGS
local ballcount = {};
local function round(x)
if x < 0 then
return -math.floor(-x+0.5);
else
return math.floor(x+0.5);
end
end
local ball_spawner_update_form = function (pos)
local meta = minetest.get_meta(pos);
local x0,y0,z0;
x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0"); -- direction of velocity
local energy,bounce,g,puncheable, gravity,hp,hurt,solid;
local speed = meta:get_float("speed"); -- if positive sets initial ball speed
energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta:get_float("gravity"); -- gravity
hp = meta:get_float("hp");
hurt = meta:get_float("hurt");
puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta:get_int("solid"); -- if 1 then entity is solid - cant be walked on
local texture = meta:get_string("texture") or "basic_machines_ball.png";
local visual = meta:get_string("visual") or "sprite";
local scale = meta:get_int("scale");
local form =
"size[4.25,4.75]" .. -- width, height
"field[0.25,0.5;1,1;x0;target;"..x0.."] field[1.25,0.5;1,1;y0;;"..y0.."] field[2.25,0.5;1,1;z0;;"..z0.."]"..
"field[3.25,0.5;1,1;speed;speed;"..speed.."]"..
--speed, jump, gravity,sneak
"field[0.25,1.5;1,1;energy;energy;"..energy.."]"..
"field[1.25,1.5;1,1;bounce;bounce;".. bounce.."]"..
"field[2.25,1.5;1,1;gravity;gravity;"..gravity.."]"..
"field[3.25,1.5;1,1;puncheable;puncheable;"..puncheable.."]"..
"field[3.25,2.5;1,1;solid;solid;"..solid.."]"..
"field[0.25,2.5;1,1;hp;hp;"..hp.."]".."field[1.25,2.5;1,1;hurt;hurt;"..hurt.."]"..
"field[0.25,3.5;4,1;texture;texture;"..minetest.formspec_escape(texture).."]"..
"field[0.25,4.5;1,1;scale;scale;"..scale.."]".."field[1.25,4.5;1,1;visual;visual;"..visual.."]"..
"button_exit[3.25,4.25;1,1;OK;OK]";
if meta:get_int("admin")==1 then
local lifetime = meta:get_int("lifetime");
if lifetime <= 0 then lifetime = 20 end
form = form .. "field[2.25,2.5;1,1;lifetime;lifetime;"..lifetime.."]"
end
meta:set_string("formspec",form);
end
minetest.register_entity("basic_machines:ball",{
timer = 0,
lifetime = 20, -- how long it exists before disappearing
energy = 1, -- if negative it will deactivate stuff, positive will activate, 0 wont do anything
puncheable = 1, -- can be punched by players in protection
bounce = 0, -- 0: absorbs in block, 1 = proper bounce=lag buggy, -- to do: 2 = line of sight bounce
gravity = 0,
speed = 5, -- velocity when punched
hurt = 0, -- how much damage it does to target entity, if 0 damage disabled
owner = "",
origin = {x=0,y=0,z=0},
lastpos = {x=0,y=0,z=0}, -- last not-colliding position
hp_max = 100,
elasticity = 0.9, -- speed gets multiplied by this after bounce
visual="sprite",
visual_size={x=.6,y=.6},
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
physical=false,
--textures={"basic_machines_ball"},
on_activate = function(self, staticdata)
self.object:set_properties({textures={"basic_machines_ball.png"}})
self.object:set_properties({visual_size = {x=1, y=1}});
self.timer = 0;self.owner = "";
self.origin = self.object:getpos();
self.lifetime = 20;
end,
on_punch = function (self, puncher, time_from_last_punch, tool_capabilities, dir)
if self.puncheable == 0 then return end
if self.puncheable == 1 then -- only those in protection
local name = puncher:get_player_name();
local pos = self.object:getpos();
if minetest.is_protected(pos,name) then return end
end
--minetest.chat_send_all(minetest.pos_to_string(dir))
if time_from_last_punch<0.5 then return end
local v = self.speed or 1;
local velocity = dir;
velocity.x = velocity.x*v;velocity.y = velocity.y*v;velocity.z = velocity.z*v;
self.object:setvelocity(velocity)
end,
on_step = function(self, dtime)
self.timer=self.timer+dtime
if self.timer>self.lifetime then
local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
self.object:remove()
return
end
local pos=self.object:getpos()
local origin = self.origin;
local r = 30;-- maximal distance when balls disappear
local dist = math.max(math.abs(pos.x-origin.x), math.abs(pos.y-origin.y), math.abs(pos.z-origin.z));
if dist>r then -- remove if it goes too far
local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
self.object:remove()
return
end
local nodename = minetest.get_node(pos).name;
local walkable = false;
if nodename ~= "air" then
walkable = minetest.registered_nodes[nodename].walkable;
if nodename == "basic_machines:ball_spawner" and dist>0.5 then walkable = true end -- ball can activate spawner, just not originating one
end
if not walkable then
self.lastpos = pos
if self.hurt~=0 then -- check for coliding nearby objects
local objects = minetest.get_objects_inside_radius(pos,1);
if #objects>1 then
for _, obj in pairs(objects) do
local p = obj:getpos();
local d = math.sqrt((p.x-pos.x)^2+(p.y-pos.y)^2+(p.z-pos.z)^2);
if d>0 then
--if minetest.is_protected(p,self.owner) then return end
if math.abs(p.x)<32 and math.abs(p.y)<32 and math.abs(p.z)<32 then return end -- no damage around spawn
if obj:is_player() then -- dont hurt owner
if obj:get_player_name()==self.owner then break end
end
obj:set_hp(obj:get_hp()-self.hurt)
local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
self.object:remove();
return
end
end
end
end
end
if walkable then -- we hit a node
--minetest.chat_send_all(" hit node at " .. minetest.pos_to_string(pos))
local node = minetest.get_node(pos);
local table = minetest.registered_nodes[node.name];
if table and table.mesecons and table.mesecons.effector then -- activate target
if minetest.is_protected(pos,self.owner) then return end
local effector = table.mesecons.effector;
local energy = self.energy;
self.object:remove();
if energy>0 then
if not effector.action_on then return end
effector.action_on(pos,node,16);
elseif energy<0 then
if not effector.action_off then return end
effector.action_off(pos,node,16);
end
else -- bounce ( copyright rnd, 2016 )
local bounce = self.bounce;
if self.bounce == 0 then
local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
self.object:remove()
return end
local n = {x=0,y=0,z=0}; -- this will be bounce normal
local v = self.object:getvelocity();
local opos = {x=round(pos.x),y=round(pos.y), z=round(pos.z)}; -- obstacle
local bpos ={ x=(pos.x-opos.x),y=(pos.y-opos.y),z=(pos.z-opos.z)}; -- boundary position on cube, approximate
if bounce == 2 then -- uses special blocks for non buggy lag proof bouncing: by default it bounces in y direction
local bounce_direction = basic_machines.ball.bounce_materials[node.name] or 0;
if bounce_direction == 0 then
if v.y>=0 then n.y = -1 else n.y = 1 end
elseif bounce_direction == 1 then
if v.x>=0 then n.x = -1 else n.x = 1 end
n.y = 0;
elseif bounce_direction == 2 then
if v.z>=0 then n.z = -1 else n.z = 1 end
n.y = 0;
end
else -- algorithm to determine bounce direction - problem: with lag its impossible to determine reliable which node was hit and which face ..
if v.x<=0 then n.x = 1 else n.x = -1 end -- possible bounce directions
if v.y<=0 then n.y = 1 else n.y = -1 end
if v.z<=0 then n.z = 1 else n.z = -1 end
local dpos = {};
dpos.x = 0.5*n.x; dpos.y = 0; dpos.z = 0; -- calculate distance to bounding surface midpoints
local d1 = (bpos.x-dpos.x)^2 + (bpos.y)^2 + (bpos.z)^2;
dpos.x = 0; dpos.y = 0.5*n.y; dpos.z = 0;
local d2 = (bpos.x)^2 + (bpos.y-dpos.y)^2 + (bpos.z)^2;
dpos.x = 0; dpos.y = 0; dpos.z = 0.5*n.z;
local d3 = (bpos.x)^2 + (bpos.y)^2 + (bpos.z-dpos.z)^2;
local d = math.min(d1,d2,d3); -- we obtain bounce direction from minimal distance
if d1==d then --x
n.y=0;n.z=0
elseif d2==d then --y
n.x=0;n.z=0
elseif d3==d then --z
n.x=0;n.y=0
end
nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
walkable = nodename ~= "air";
if walkable then -- problem, nonempty node - incorrect normal, fix it
if n.x ~=0 then -- x direction is wrong, try something else
n.x=0;
if v.y>=0 then n.y = -1 else n.y = 1 end -- try y
nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
walkable = nodename ~= "air";
if walkable then -- still problem, only remaining is z
n.y=0;
if v.z>=0 then n.z = -1 else n.z = 1 end
nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
walkable = nodename ~= "air";
if walkable then -- messed up, just remove the ball
self.object:remove()
return
end
end
end
end
end
local elasticity = self.elasticity;
-- bounce
if n.x~=0 then
v.x=-elasticity*v.x
elseif n.y~=0 then
v.y=-elasticity*v.y
elseif n.z~=0 then
v.z=-elasticity*v.z
end
local r = 0.2
bpos = {x=pos.x+n.x*r,y=pos.y+n.y*r,z=pos.z+n.z*r}; -- point placed a bit further away from box
self.object:setpos(bpos) -- place object at last known outside point
self.object:setvelocity(v);
minetest.sound_play("default_dig_cracky", {pos=pos,gain=1.0,max_hear_distance = 8,})
end
end
return
end,
})
minetest.register_node("basic_machines:ball_spawner", {
description = "Spawns energy ball one block above",
tiles = {"basic_machines_ball.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
drawtype = "allfaces",
paramtype = "light",
param1=1,
walkable = false,
alpha = 150,
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.env:get_meta(pos)
meta:set_string("owner", placer:get_player_name());
local privs = minetest.get_player_privs(placer:get_player_name()); if privs.privs then meta:set_int("admin",1) end
if privs.machines then meta:set_int("machines",1) end
meta:set_float("hurt",0);
meta:set_string("texture", "basic_machines_ball.png");
meta:set_float("hp",100);
meta:set_float("speed",5); -- if positive sets initial ball speed
meta:set_float("energy",1); -- if positive activates, negative deactivates, 0 does nothing
meta:set_int("bounce",0); -- if nonzero bounces when hit obstacle, 0 gets absorbed
meta:set_float("gravity",0); -- gravity
meta:set_int("puncheable",0); -- if 0 not puncheable, if 1 can be punched by players in protection, if 2 can be punched by anyone
meta:set_int("scale",100);
meta:set_string("visual","sprite");
ball_spawner_update_form(pos);
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if ttl<0 then return end
local meta = minetest.get_meta(pos);
local t0 = meta:get_int("t");
local t1 = minetest.get_gametime();
local T = meta:get_int("T"); -- temperature
if t0>t1-2 then -- activated before natural time
T=T+1;
else
if T>0 then
T=T-1
if t1-t0>5 then T = 0 end
end
end
meta:set_int("T",T);
meta:set_int("t",t1); -- update last activation time
if T > 2 then -- overheat
minetest.sound_play("default_cool_lava",{pos = pos, max_hear_distance = 16, gain = 0.25})
meta:set_string("infotext","overheat: temperature ".. T)
return
end
if meta:get_int("machines")~=1 then -- no machines priv, limit ball count
local owner = meta:get_string("owner");
local count = ballcount[owner];
if not count or count<0 then count = 0 end
if count>=2 then
if t1-t0>20 then count = 0
else return
end
end
count = count + 1;
ballcount[owner]=count;
--minetest.chat_send_all("count " .. count);
end
pos.x = round(pos.x);pos.y = round(pos.y);pos.z = round(pos.z);
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
local luaent = obj:get_luaentity();
local meta = minetest.get_meta(pos);
local speed,energy,bounce,gravity,puncheable,solid;
speed = meta:get_float("speed");
energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta:get_float("gravity"); -- gravity
puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta:get_int("solid");
if energy<0 then
obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
end
luaent.bounce = bounce;
luaent.energy = energy;
if gravity>0 then
obj:setacceleration({x=0,y=-gravity,z=0});
end
luaent.puncheable = puncheable;
luaent.owner = meta:get_string("owner");
luaent.hurt = meta:get_float("hurt");
if solid==1 then
luaent.physical = true
end
obj:set_hp( meta:get_float("hp") );
local x0,y0,z0;
if speed>0 then luaent.speed = speed end
x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0"); -- direction of velocity
if speed~=0 and (x0~=0 or y0~=0 or z0~=0) then -- set velocity direction
local velocity = {x=x0,y=y0,z=z0};
local v = math.sqrt(velocity.x^2+velocity.y^2+velocity.z^2); if v == 0 then v = 1 end
v = v / speed;
velocity.x=velocity.x/v;velocity.y=velocity.y/v;velocity.z=velocity.z/v;
obj:setvelocity(velocity);
end
if meta:get_int("admin")==1 then
luaent.lifetime = meta:get_float("lifetime");
end
local visual = meta:get_string("visual")
obj:set_properties({visual=visual});
local texture = meta:get_string("texture");
if visual=="sprite" then
obj:set_properties({textures={texture}})
elseif visual == "cube" then
obj:set_properties({textures={texture,texture,texture,texture,texture,texture}})
end
local scale = meta:get_int("scale");if scale<=0 then scale = 1 else scale = scale/100 end
obj:set_properties({visual_size = {x=scale, y=scale}});
end,
action_off = function (pos, node,ttl)
if ttl<0 then return end
pos.x = round(pos.x);pos.y = round(pos.y);pos.z = round(pos.z);
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
local luaent = obj:get_luaentity();
luaent.energy = -1;
obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name();if minetest.is_protected(pos,name) then return end
if fields.OK then
local privs = minetest.get_player_privs(sender:get_player_name());
local meta = minetest.get_meta(pos);
local x0=0; local y0=0; local z0=0;
--minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
if fields.x0 then x0 = tonumber(fields.x0) or 0 end
if fields.y0 then y0 = tonumber(fields.y0) or 0 end
if fields.z0 then z0 = tonumber(fields.z0) or 0 end
if not privs.privs and (math.abs(x0)>10 or math.abs(y0)>10 or math.abs(z0) > 10) then return end
meta:set_int("x0",x0);meta:set_int("y0",y0);meta:set_int("z0",z0);
local speed,energy,bounce,gravity,puncheable,solid;
energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = meta:get_float("gravity"); -- gravity
puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
solid = meta:get_int("solid");
if fields.speed then
local speed = tonumber(fields.speed) or 0;
if (speed > 10 or speed < 0) and not privs.privs then return end
meta:set_float("speed", speed)
end
if fields.energy then
local energy = tonumber(fields.energy) or 1;
meta:set_float("energy", energy)
end
if fields.bounce then
local bounce = tonumber(fields.bounce) or 1;
meta:set_int("bounce",bounce)
end
if fields.gravity then
local gravity = tonumber(fields.gravity) or 1;
if (gravity<0 or gravity>30) and not privs.privs then return end
meta:set_float("gravity", gravity)
end
if fields.puncheable then
meta:set_int("puncheable", tonumber(fields.puncheable) or 0)
end
if fields.solid then
meta:set_int("solid", tonumber(fields.solid) or 0)
end
if fields.lifetime then
meta:set_int("lifetime", tonumber(fields.lifetime) or 0)
end
if fields.hurt then
meta:set_float("hurt", tonumber(fields.hurt) or 0)
end
if fields.hp then
meta:set_float("hp", math.abs(tonumber(fields.hp)) or 0)
end
if fields.texture then
meta:set_string ("texture", fields.texture);
end
if fields.scale then
local scale = math.abs(tonumber(fields.scale)) or 100;
if scale>1000 and not privs.privs then scale = 1000 end
meta:set_int("scale", scale)
end
if fields.visual then
local visual = fields.visual or "";
if visual~="sprite" and visual~="cube" then return end
meta:set_string ("visual", fields.visual);
end
ball_spawner_update_form(pos);
end
end,
after_dig_node = function(pos, oldnode, oldmetadata, digger)
local name = digger:get_player_name();
local inv = digger:get_inventory();
inv:remove_item("main", ItemStack("basic_machines:ball_spawner"));
local stack = ItemStack("basic_machines:ball_spell");
local meta = oldmetadata["fields"];
meta["formspec"]=nil;
stack:set_metadata(minetest.serialize(meta));
inv:add_item("main",stack);
end
})
local spelltime = {};
-- ball as magic spell user can cast
minetest.register_tool("basic_machines:ball_spell", {
description = "ball spawner",
inventory_image = "basic_machines_ball.png",
tool_capabilities = {
full_punch_interval = 2,
max_drop_level=0,
},
on_use = function(itemstack, user, pointed_thing)
local pos = user:getpos();pos.y=pos.y+1;
local meta = minetest.deserialize(itemstack:get_metadata());
if not meta then return end
local owner = meta["owner"] or "";
--if minetest.is_protected(pos,owner) then return end
local t0 = spelltime[owner] or 0;
local t1 = minetest.get_gametime();
if t1-t0<2 then return end -- too soon
spelltime[owner]=t1;
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
local luaent = obj:get_luaentity();
local speed,energy,bounce,gravity,puncheable;
speed = tonumber(meta["speed"]) or 0;
energy = tonumber(meta["energy"]) or 0; -- if positive activates, negative deactivates, 0 does nothing
bounce = tonumber(meta["bounce"]) or 0; -- if nonzero bounces when hit obstacle, 0 gets absorbed
gravity = tonumber(meta["gravity"]) or 0; -- gravity
puncheable = tonumber(meta["puncheable"]) or 0; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
if energy<0 then
obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
end
luaent.bounce = bounce;
luaent.energy = energy;
if gravity>0 then
obj:setacceleration({x=0,y=-gravity,z=0});
end
luaent.puncheable = puncheable;
luaent.owner = meta["owner"];
luaent.hurt = math.min(tonumber(meta["hurt"]),basic_machines.ball.maxdamage);
obj:set_hp( tonumber(meta["hp"]) );
local x0,y0,z0;
if speed>0 then luaent.speed = speed end
local v = user:get_look_dir();
v.x=v.x*speed;v.y=v.y*speed;v.z=v.z*speed;
obj:setvelocity(v);
if tonumber(meta["admin"])==1 then
luaent.lifetime = tonumber(meta["lifetime"]);
end
obj:set_properties({textures={meta["texture"]}})
end,
})
-- minetest.register_craft({
-- output = "basic_machines:ball_spawner",
-- recipe = {
-- {"basic_machines:power_cell"},
-- {"basic_machines:keypad"}
-- }
-- })

211
constructor.lua Normal file
View File

@ -0,0 +1,211 @@
-- rnd 2016:
-- CONSTRUCTOR machine: used to make all other basic_machines
basic_machines.craft_recipes = {
["keypad"] = {item = "basic_machines:keypad", description = "Turns on/off lights and activates machines or opens doors", craft = {"default:wood","default:stick"}, tex = "keypad"},
["light"]={item = "basic_machines:light_on", description = "Light in darkness", craft = {"default:torch 4"}, tex = "light"},
["mover"]={item = "basic_machines:mover", description = "Can dig, harvest, plant, teleport or move items from/in inventories", craft = {"default:mese_crystal 6","default:stone 2", "basic_machines:keypad"}, tex = "basic_machine_mover_side"},
["detector"] = {item = "basic_machines:detector", description = "Detect and measure players, objects,blocks,light level", craft = {"default:mese_crystal 4","basic_machines:keypad"}, tex = "detector"},
["distributor"]= {item = "basic_machines:distributor", description = "Organize your circuits better", craft = {"default:steel_ingot","default:mese_crystal", "basic_machines:keypad"}, tex = "distributor"},
["clock_generator"]= {item = "basic_machines:clockgen", description = "For making circuits that run non stop", craft = {"default:diamondblock","basic_machines:keypad"}, tex = "basic_machine_clock_generator"},
["recycler"]= {item = "basic_machines:recycler", description = "Recycle old tools", craft = {"default:mese_crystal 8","default:diamondblock"}, tex = "recycler"},
["enviroment"] = {item = "basic_machines:enviro", description = "Change gravity and more", craft = {"basic_machines:generator 8","basic_machines:clockgen"}, tex = "enviro"},
["ball_spawner"]={item = "basic_machines:ball_spawner", description = "Spawn moving energy balls", craft = {"basic_machines:power_cell","basic_machines:keypad"}, tex = "basic_machines_ball"},
["battery"]={item = "basic_machines:battery", description = "Power for machines", craft = {"default:steel_ingot 3","default:mese","default:diamond"}, tex = "basic_machine_battery"},
["generator"]={item = "basic_machines:generator", description = "Generate power crystals", craft = {"default:diamondblock 5","basic_machines:battery"}, tex = "basic_machine_generator"},
["autocrafter"] = {item = "basic_machines:autocrafter", description = "Automate crafting", craft = { "default:steel_ingot 5", "default:mese_crystal 2", "default:diamondblock 2"}, tex = "pipeworks_autocrafter"},
["grinder"] = {item = "basic_machines:grinder", description = "Makes dusts and grinds materials", craft = {"default:diamond 13","default:mese 4"}, tex = "grinder"},
}
basic_machines.craft_recipe_order = { -- order in which nodes appear
"keypad","light","grinder","mover", "battery","generator","detector", "distributor", "clock_generator","recycler","autocrafter","ball_spawner", "enviroment"
}
local constructor_process = function(pos)
local meta = minetest.get_meta(pos);
local craft = basic_machines.craft_recipes[meta:get_string("craft")];
if not craft then return end
local item = craft.item;
local craftlist = craft.craft;
local inv = meta:get_inventory();
for _,v in pairs(craftlist) do
if not inv:contains_item("main", ItemStack(v)) then
meta:set_string("infotext", "#CRAFTING: you need " .. v .. " to craft " .. craft.item)
return
end
end
for _,v in pairs(craftlist) do
inv:remove_item("main", ItemStack(v));
end
inv:add_item("dst", ItemStack(item));
end
local constructor_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local craft = meta:get_string("craft");
local description = basic_machines.craft_recipes[craft];
local tex;
if description then
tex = description.tex;
local i = 0;
local itex;
local inv = meta:get_inventory(); -- set up craft list
for _,v in pairs(description.craft) do
i=i+1;
inv:set_stack("recipe", i, ItemStack(v))
end
for j = i+1,6 do
inv:set_stack("recipe", j, ItemStack(""))
end
description = description.description
else
description = ""
tex = ""
end
local textlist = " ";
local selected = meta:get_int("selected") or 1;
for _,v in ipairs(basic_machines.craft_recipe_order) do
textlist = textlist .. v .. ", ";
end
local form =
"size[8,11]"..
"textlist[0,0;3,1.5;craft;" .. textlist .. ";" .. selected .."]"..
"button[3.5,1;1.25,0.75;CRAFT;CRAFT]"..
"image[3.65,0;1,1;".. tex .. ".png]"..
"label[0,1.85;".. description .. "]"..
"list[context;recipe;0,2.35;8,1;]"..
"label[0,3.3;Put crafting materials here]"..
"list[context;main;0,3.7;8,3;]"..
"list[context;dst;5,0;3,2;]"..
"label[0,6.5;player inventory]"..
"list[current_player;main;0,7;8,4;]"
meta:set_string("formspec", form);
end
minetest.register_node("basic_machines:constructor", {
description = "Constructor: used to make machines",
tiles = {"grinder.png","default_furnace_top.png", "basic_machine_side.png","basic_machine_side.png","basic_machine_side.png","basic_machine_side.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext", "Constructor: To operate it insert materials, select item to make and click craft button.")
meta:set_string("owner", placer:get_player_name());
meta:set_string("craft","keypad")
meta:set_int("selected",1);
local inv = meta:get_inventory();inv:set_size("main", 24);inv:set_size("dst",6);
inv:set_size("recipe",8);
end,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
constructor_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "recipe" then return 0 end
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
if listname == "recipe" then return 0 end
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "recipe" then return 0 end
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
constructor_process(pos);
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
if minetest.is_protected(pos, sender:get_player_name()) then return end
local meta = minetest.get_meta(pos);
if fields.craft then
if string.sub(fields.craft,1,3)=="CHG" then
local sel = tonumber(string.sub(fields.craft,5)) or 1
meta:set_int("selected",sel);
local i = 0;
for _,v in ipairs(basic_machines.craft_recipe_order) do
i=i+1;
if i == sel then meta:set_string("craft",v); break; end
end
else
return
end
end
if fields.CRAFT then
constructor_process(pos);
end
constructor_update_meta(pos);
end,
})
minetest.register_craft({
output = "basic_machines:constructor",
recipe = {
{"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
{"default:steel_ingot","default:copperblock","default:steel_ingot"},
{"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
}
})

3
depends.txt Normal file
View File

@ -0,0 +1,3 @@
default
protector?
areas?

348
enviro.lua Normal file
View File

@ -0,0 +1,348 @@
-- ENVIRO block: change physics and skybox for players
-- note: nonadmin players are limited in changes ( cant change skybox and have limits on other allowed changes)
-- rnd 2016:
local enviro = {};
enviro.skyboxes = {
["default"]={type = "regular", tex = {}},
["space"]={type="skybox", tex={"sky_pos_y.png","sky_neg_y.png","sky_pos_z.png","sky_neg_z.png","sky_neg_x.png","sky_pos_x.png",}}, -- need textures installed!
["caves"]={type = "cavebox", tex = {"black.png","black.png","black.png","black.png","black.png","black.png",}}};
local space_start = 1500;
local enviro_update_form = function (pos)
local meta = minetest.get_meta(pos);
local x0,y0,z0;
x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0");
local skybox = meta:get_string("skybox");
local skylist = "";
local sky_ind,j;
j=1;sky_ind = 3;
for i,_ in pairs(enviro.skyboxes) do
if i == skybox then sky_ind = j end
skylist = skylist .. i .. ",";
j=j+1;
end
local r = meta:get_int("r");
local speed,jump, g, sneak;
speed = meta:get_float("speed");jump = meta:get_float("jump");
g = meta:get_float("g"); sneak = meta:get_int("sneak");
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z;
local form =
"size[8,8.5]" .. -- width, height
"field[0.25,0.5;1,1;x0;target;"..x0.."] field[1.25,0.5;1,1;y0;;"..y0.."] field[2.25,0.5;1,1;z0;;"..z0.."]"..
"field[3.25,0.5;1,1;r;radius;"..r.."]"..
--speed, jump, gravity,sneak
"field[0.25,1.5;1,1;speed;speed;"..speed.."]"..
"field[1.25,1.5;1,1;jump;jump;".. jump.."]"..
"field[2.25,1.5;1,1;g;gravity;"..g.."]"..
"field[3.25,1.5;1,1;sneak;sneak;"..sneak.."]"..
"label[0.,3.0;Skybox selection]"..
"dropdown[0.,3.35;3,1;skybox;"..skylist..";".. sky_ind .."]"..
"button_exit[3.25,3.25;1,1;OK;OK]"..
"list["..list_name..";fuel;3.25,2.25;1,1;]"..
"list[current_player;main;0,4.5;8,4;]";
meta:set_string("formspec",form);
end
-- enviroment changer
minetest.register_node("basic_machines:enviro", {
description = "Changes enviroment for players around target location",
tiles = {"basic_machine_side.png^[invert:rgb^[brighten^[invert:rgb^enviro.png"},
groups = {oddly_breakable_by_hand=2},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.env:get_meta(pos)
meta:set_string("infotext", "Right click to set it. Activate by signal.")
meta:set_string("owner", placer:get_player_name()); meta:set_int("public",1);
meta:set_int("x0",0);meta:set_int("y0",0);meta:set_int("z0",0); -- target
meta:set_int("r",5); meta:set_string("skybox","default");
meta:set_float("speed",1);
meta:set_float("jump",1);
meta:set_float("g",1);
meta:set_int("sneak",1);
meta:set_int("admin",0);
local name = placer:get_player_name();
meta:set_string("owner",name);
local privs = minetest.get_player_privs(name);
if privs.privs then meta:set_int("admin",1) end
local inv = meta:get_inventory();
inv:set_size("fuel",1*1);
enviro_update_form(pos);
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
local meta = minetest.get_meta(pos);
local admin = meta:get_int("admin");
local inv = meta:get_inventory(); local stack = ItemStack("default:diamond 1");
if inv:contains_item("fuel", stack) then
inv:remove_item("fuel", stack);
else
meta:set_string("infotext","Error. Insert diamond in fuel inventory")
return
end
local x0,y0,z0,r,skybox,speed,jump,g,sneak;
x0=meta:get_int("x0"); y0=meta:get_int("y0");z0=meta:get_int("z0"); -- target
r= meta:get_int("r",5); skybox=meta:get_string("skybox");
speed=meta:get_float("speed");jump= meta:get_float("jump");
g=meta:get_float("g");sneak=meta:get_int("sneak"); if sneak~=0 then sneak = true else sneak = false end
local players = minetest.get_connected_players();
for _,player in pairs(players) do
local pos1 = player:getpos();
local dist = math.sqrt((pos1.x-pos.x)^2 + (pos1.y-pos.y)^2 + (pos1.z-pos.z)^2 );
if dist<=r then
player:set_physics_override({speed=speed,jump=jump,gravity=g,sneak=sneak})
if admin == 1 then -- only admin can change skybox
local sky = enviro.skyboxes[skybox];
player:set_sky(0,sky["type"],sky["tex"]);
end
end
end
-- attempt to set acceleration to balls, if any around
local objects = minetest.get_objects_inside_radius(pos, r)
for _,obj in pairs(objects) do
if obj:get_luaentity() then
local obj_name = obj:get_luaentity().name or ""
if obj_name == "basic_machines:ball" then
obj:setacceleration({x=0,y=-g,z=0});
end
end
end
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
local name = sender:get_player_name();if minetest.is_protected(pos,name) then return end
if fields.OK then
local privs = minetest.get_player_privs(sender:get_player_name());
local meta = minetest.get_meta(pos);
local x0=0; local y0=0; local z0=0;
--minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
if fields.x0 then x0 = tonumber(fields.x0) or 0 end
if fields.y0 then y0 = tonumber(fields.y0) or 0 end
if fields.z0 then z0 = tonumber(fields.z0) or 0 end
if not privs.privs and (math.abs(x0)>10 or math.abs(y0)>10 or math.abs(z0) > 10) then return end
meta:set_int("x0",x0);meta:set_int("y0",y0);meta:set_int("z0",z0);
if privs.privs then -- only admin can set sky
if fields.skybox then meta:set_string("skybox", fields.skybox) end
end
if fields.r then
local r = tonumber(fields.r) or 0;
if r > 10 and not privs.privs then return end
meta:set_int("r", r)
end
if fields.g then
local g = tonumber(fields.g) or 1;
if (g<0.1 or g>40) and not privs.privs then return end
meta:set_float("g", g)
end
if fields.speed then
local speed = tonumber(fields.speed) or 1;
if (speed>1 or speed < 0) and not privs.privs then return end
meta:set_float("speed", speed)
end
if fields.jump then
local jump = tonumber(fields.jump) or 1;
if (jump<0 or jump>2) and not privs.privs then return end
meta:set_float("jump", jump)
end
if fields.sneak then
meta:set_int("sneak", tonumber(fields.sneak) or 0)
end
enviro_update_form(pos);
end
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
})
-- DEFAULT (SPAWN) PHYSICS VALUE/SKYBOX
local reset_player_physics = function(player)
if player then
player:set_physics_override({speed=1,jump=1,gravity=1,sneak=true}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["default"]; -- default skybox is "default"
player:set_sky(0,skybox["type"],skybox["tex"]);
end
end
-- globally available function
enviro_adjust_physics = function(player) -- adjust players physics/skybox 1 second after various events
minetest.after(1, function()
if player then
local pos = player:getpos(); if not pos then return end
if pos.y > space_start then -- is player in space or not?
player:set_physics_override({speed=1,jump=0.6,gravity=0.2,sneak=true}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["space"];
player:set_sky(0,skybox["type"],skybox["tex"]);
else
player:set_physics_override({speed=1,jump=1,gravity=1,sneak=true}) -- value set for extreme test space spawn
local skybox = enviro.skyboxes["default"];
player:set_sky(0,skybox["type"],skybox["tex"]);
end
end
end)
end
-- restore default values/skybox on respawn of player
minetest.register_on_respawnplayer(reset_player_physics)
-- when player joins, check where he is and adjust settings
minetest.register_on_joinplayer(enviro_adjust_physics)
-- SERVER GLOBAL SPACE CODE: uncomment to enable it
local stimer = 0
local enviro_space = {};
minetest.register_globalstep(function(dtime)
stimer = stimer + dtime;
if stimer >= 5 then
stimer = 0;
local players = minetest.get_connected_players();
for _,player in pairs(players) do
local name = player:get_player_name();
local pos = player:getpos();
local inspace=0; if pos.y>space_start then inspace = 1 end
local inspace0=enviro_space[name];
if inspace~=inspace0 then -- only adjust player enviroment ONLY if change occured ( earth->space or space->earth !)
enviro_space[name] = inspace;
enviro_adjust_physics(player);
end
if inspace==1 then -- special space code
local dist = math.abs(pos.x)+math.abs(pos.z);
if dist > 50 then -- close to spawn normal
local populated = minetest.find_node_near(pos, 5, "protector:protect");
if not populated then -- do damage if player found not close to protectors
local hp = player:get_hp();
local privs = minetest.get_player_privs(name);
if hp>0 and not privs.kick then
player:set_hp(hp-10); -- dead in 20/10 = 2 events
minetest.chat_send_player(name,"WARNING: in space you must stay close to spawn or protected areas");
end
end
end
end
end
end
end)
-- END OF SPACE CODE
-- AIR EXPERIMENT
-- minetest.register_node("basic_machines:air", {
-- description = "enables breathing in space",
-- drawtype = "liquid",
-- tiles = {"default_water_source_animated.png"},
-- drawtype = "glasslike",
-- paramtype = "light",
-- alpha = 150,
-- sunlight_propagates = true, -- Sunlight shines through
-- walkable = false, -- Would make the player collide with the air node
-- pointable = false, -- You can't select the node
-- diggable = false, -- You can't dig the node
-- buildable_to = true,
-- drop = "",
-- groups = {not_in_creative_inventory=1},
-- after_place_node = function(pos, placer, itemstack, pointed_thing)
-- local r = 3;
-- for i = -r,r do
-- for j = -r,r do
-- for k = -r,r do
-- local p = {x=pos.x+i,y=pos.y+j,z=pos.z+k};
-- if minetest.get_node(p).name == "air" then
-- minetest.set_node(p,{name = "basic_machines:air"})
-- end
-- end
-- end
-- end
-- end
-- })
-- minetest.register_abm({
-- nodenames = {"basic_machines:air"},
-- neighbors = {"air"},
-- interval = 10,
-- chance = 1,
-- action = function(pos, node, active_object_count, active_object_count_wider)
-- minetest.set_node(pos,{name = "air"})
-- end
-- });
minetest.register_on_punchplayer( -- bring gravity closer to normal with each punch
function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
if player:get_physics_override() == nil then return end
local gravity = player:get_physics_override().gravity;
if gravity<1 then
gravity = 0.5*gravity+0.5;
player:set_physics_override({gravity=gravity})
end
end
)
-- RECIPE: extremely expensive
-- minetest.register_craft({
-- output = "basic_machines:enviro",
-- recipe = {
-- {"basic_machines:generator", "basic_machines:clockgen","basic_machines:generator"},
-- {"basic_machines:generator", "basic_machines:generator","basic_machines:generator"},
-- {"basic_machines:generator", "basic_machines:generator", "basic_machines:generator"}
-- }
-- })

279
grinder.lua Normal file
View File

@ -0,0 +1,279 @@
-- rnd 2016:
-- this node works as technic grinder
-- There is a certain fuel cost to operate
-- recipe list: [in] ={fuel cost, out, quantity of material required for processing}
basic_machines.grinder_recipes = {
["default:stone"] = {2,"default:sand",1},
["default:cobble"] = {1,"default:gravel",1},
["default:gravel"] = {0.5,"default:dirt",1},
["default:dirt"] = {0.5,"default:clay_lump 4",1},
["es:aikerum_crystal"] ={16,"es:aikerum_dust 2",1}, -- added for es mod
["es:ruby_crystal"] = {16,"es:ruby_dust 2",1},
["es:emerald_crystal"] = {16,"es:emerald_dust 2",1},
["es:purpellium_lump"] = {16,"es:purpellium_dust 2",1},
["default:obsidian_shard"] = {199,"default:lava_source",1},
["gloopblocks:basalt"] = {1, "default:cobble",1}, -- enable coble farms with gloopblocks mod
};
-- es gems dust cooking
local es_gems = function()
local es_gems = {
{name = "emerald", cooktime = 1200},{name = "ruby", cooktime = 1500},{name = "purpellium", cooktime = 1800},
{name = "aikerum", cooktime = 2000}}
for _,v in pairs(es_gems) do
minetest.register_craft({
type = "cooking",
recipe = "es:"..v.name.."_dust",
output = "es:"..v.name .."_crystal",
cooktime = v.cooktime
})
end
end
minetest.after(0,es_gems);
local grinder_process = function(pos)
local node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
local meta = minetest.get_meta(pos);local inv = meta:get_inventory();
-- PROCESS: check out inserted items
local stack = inv:get_stack("src",1);
if stack:is_empty() then return end; -- nothing to do
local src_item = stack:to_string();
local p=string.find(src_item," "); if p then src_item = string.sub(src_item,1,p-1) else p = 0 end -- take first word to determine what item was
local def = basic_machines.grinder_recipes[src_item];
if not def then
meta:set_string("infotext", "please insert valid materials"); return
end-- unknown node
if stack:get_count()< def[3] then
meta:set_string("infotext", "Recipe requires at least " .. def[3] .. " " .. src_item);
return
end
-- FUEL CHECK
local fuel = meta:get_float("fuel");
if fuel-def[1]<0 then -- we need new fuel, check chest below
local fuellist = inv:get_list("fuel")
if not fuellist then return end
local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
local supply=0;
if fueladd.time == 0 then -- no fuel inserted, try look for outlet
-- No valid fuel in fuel list
supply = basic_machines.check_power({x=pos.x,y=pos.y-1,z=pos.z} , def[1]) or 0; -- tweaked so 1 coal = 1 energy
if supply>0 then
fueladd.time = supply -- same as 10 coal
else
meta:set_string("infotext", "Please insert fuel");
return;
end
else
if supply==0 then -- Take fuel from fuel list if no supply available
inv:set_stack("fuel", 1, afterfuel.items[1])
fueladd.time=fueladd.time*0.1/4 -- thats 1 for coal
--minetest.chat_send_all("FUEL ADD TIME " .. fueladd.time)
end
end
if fueladd.time>0 then
fuel=fuel + fueladd.time
meta:set_float("fuel",fuel);
meta:set_string("infotext", "added fuel furnace burn time " .. fueladd.time .. ", fuel status " .. fuel);
end
if fuel-def[1]<0 then
meta:set_string("infotext", "need at least " .. def[1]-fuel .. " fuel to complete operation "); return
end
end
-- process items
-- TO DO: check if there is room for item yyy
local addstack = ItemStack(def[2]);
if inv:room_for_item("dst", addstack) then
inv:add_item("dst",addstack);
else return
end
--take 1 item from src inventory for each activation
stack=stack:take_item(1); inv:remove_item("src", stack)
minetest.sound_play("grinder", {pos=pos,gain=0.5,max_hear_distance = 16,})
fuel = fuel-def[1]; -- burn fuel
meta:set_float("fuel",fuel);
meta:set_string("infotext", "fuel " .. fuel);
end
local grinder_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local form =
"size[8,8]" .. -- width, height
--"size[6,10]" .. -- width, height
"label[0,0;IN] label[1,0;OUT] label[0,2;FUEL] "..
"list["..list_name..";src;0.,0.5;1,1;]"..
"list["..list_name..";dst;1.,0.5;3,3;]"..
"list["..list_name..";fuel;0.,2.5;1,1;]"..
"list[current_player;main;0,4;8,4;]"..
"button[6.5,0.5;1,1;OK;OK]";
meta:set_string("formspec", form);
end
minetest.register_node("basic_machines:grinder", {
description = "Grinder",
tiles = {"grinder.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext", "Grinder: To operate it insert fuel, then insert item to grind or use keypad to activate it.")
meta:set_string("owner", placer:get_player_name());
meta:set_float("fuel",0);
local inv = meta:get_inventory();inv:set_size("src", 1);inv:set_size("dst",9);inv:set_size("fuel",1);
end,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
grinder_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname =="dst" then return end
grinder_process(pos);
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
grinder_process(pos);
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then return end
local meta = minetest.get_meta(pos);
grinder_update_meta(pos);
end,
})
-- minetest.register_craft({
-- output = "basic_machines:grinder",
-- recipe = {
-- {"default:diamond","default:mese","default:diamond"},
-- {"default:mese","default:diamondblock","default:mese"},
-- {"default:diamond","default:mese","default:diamond"},
-- }
-- })
-- REGISTER DUSTS
local function register_dust(name,input_node_name,ingot,grindcost,cooktime,R,G,B)
if not R then R = "FF" end
if not G then G = "FF" end
if not B then B = "FF" end
local purity_table = {"33","66"};
for i = 1,#purity_table do
local purity = purity_table[i];
minetest.register_craftitem("basic_machines:"..name.."_dust_".. purity, {
description = name.. " dust purity " .. purity .. "%" ,
inventory_image = "basic_machines_dust.png^[colorize:#"..R..G..B..":180",
})
end
basic_machines.grinder_recipes[input_node_name] = {grindcost,"basic_machines:"..name.."_dust_".. purity_table[1].." 2",1} -- register grinder recipe
if ingot~="" then
for i = 1,#purity_table-1 do
minetest.register_craft({
type = "cooking",
recipe = "basic_machines:"..name.."_dust_".. purity_table[i],
output = "basic_machines:"..name.."_dust_".. purity_table[i+1],
cooktime = cooktime
})
end
minetest.register_craft({
type = "cooking",
recipe = "basic_machines:"..name.."_dust_".. purity_table[#purity_table],
groups = {not_in_creative_inventory=1},
output = ingot,
cooktime = cooktime
})
end
end
register_dust("iron","default:iron_lump","default:steel_ingot",4,8,"99","99","99")
register_dust("copper","default:copper_lump","default:copper_ingot",4,8,"C8","80","0D") --c8800d
register_dust("gold","default:gold_lump","default:gold_ingot",6,25,"FF","FF","00")
-- grinding ingots gives dust too
basic_machines.grinder_recipes["default:steel_ingot"] = {4,"basic_machines:iron_dust_33 2",1};
basic_machines.grinder_recipes["default:copper_ingot"] = {4,"basic_machines:copper_dust_33 2",1};
basic_machines.grinder_recipes["default:gold_ingot"] = {6,"basic_machines:gold_dust_33 2",1};
-- are moreores (tin, silver, mithril) present?
local table = minetest.registered_nodes["moreores:tin_lump"]; if table then
register_dust("tin","moreores:tin_lump","moreores:tin_ingot",4,8,"FF","FF","FF")
register_dust("silver","moreores:silver_lump","moreores:silver_ingot",5,15,"BB","BB","BB")
register_dust("mithril","moreores:mithril_lump","moreores:mithril_ingot",16,750,"00","00","FF")
basic_machines.grinder_recipes["moreores:tin_ingot"] = {4,"basic_machines:tin_dust_33 2",1};
basic_machines.grinder_recipes["moreores:silver_ingot"] = {5,"basic_machines:silver_dust_33 2",1};
basic_machines.grinder_recipes["moreores:mithril_ingot"] = {16,"basic_machines:mithril_dust_33 2",1};
end
register_dust("mese","default:mese_crystal","default:mese_crystal",8,250,"CC","CC","00")
register_dust("diamond","default:diamond","default:diamond",16,500,"00","EE","FF") -- 0.3hr cooking time to make diamond!

82
init.lua Normal file
View File

@ -0,0 +1,82 @@
-- BASIC_MACHINES: lightweight automation mod for minetest
-- minetest 0.4.14
-- (c) 2015-2016 rnd
-- 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.
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
basic_machines = {};
dofile(minetest.get_modpath("basic_machines").."/mark.lua") -- used for markings, borrowed and adapted from worldedit mod
dofile(minetest.get_modpath("basic_machines").."/mover.lua") -- mover, detector, keypad, distributor
dofile(minetest.get_modpath("basic_machines").."/technic_power.lua") -- technic power for mover
-- dofile(minetest.get_modpath("basic_machines").."/recycler.lua") -- recycle old used tools
dofile(minetest.get_modpath("basic_machines").."/grinder.lua") -- grind materials into dusts
-- dofile(minetest.get_modpath("basic_machines").."/autocrafter.lua") -- borrowed and adapted from pipeworks mod
-- dofile(minetest.get_modpath("basic_machines").."/constructor.lua") -- enable crafting of all machines
--dofile(minetest.get_modpath("basic_machines").."/cpu.lua") -- experimental
dofile(minetest.get_modpath("basic_machines").."/protect.lua") -- enable interaction with players, adds local on protect/chat event handling
-- OPTIONAL ADDITIONAL STUFF ( comment to disable )
-- dofile(minetest.get_modpath("basic_machines").."/ball.lua") -- interactive flying ball, can activate blocks or be used as a weapon
-- dofile(minetest.get_modpath("basic_machines").."/enviro.lua") -- enviro blocks that can change surrounding enviroment physics, uncomment spawn/join code to change global physics, disabled by default
minetest.after(0, function()
-- dofile(minetest.get_modpath("basic_machines").."/mesecon_doors.lua") -- if you want open/close doors with signal, also steel doors are made impervious to dig through, removal by repeat punch
-- dofile(minetest.get_modpath("basic_machines").."/mesecon_lights.lua") -- adds ability for other light blocks to toggle light
end)
-- MACHINE PRIVILEGE
minetest.register_privilege("machines", {
description = "Player is expert basic_machine user: his machines work while not present on server, can spawn more than 2 balls at once",
})
-- machines fuel related recipes
-- CHARCOAL
minetest.register_craftitem("basic_machines:charcoal", {
description = "Wood charcoal",
inventory_image = "default_coal_lump.png",
})
minetest.register_craft({
type = 'cooking',
recipe = "default:tree",
cooktime = 30,
output = "basic_machines:charcoal",
})
minetest.register_craft({
output = "default:coal_lump",
recipe = {
{"basic_machines:charcoal"},
{"basic_machines:charcoal"},
}
})
minetest.register_craft({
type = "fuel",
recipe = "basic_machines:charcoal",
-- note: to make it you need to use 1 tree block for fuel + 1 tree block, thats 2, caloric value 2*30=60
burntime = 40, -- coal lump has 40, tree block 30, coal block 370 (9*40=360!)
})
-- COMPATIBILITY
print("[basic machines] loaded")

154
mark.lua Normal file
View File

@ -0,0 +1,154 @@
-- rnd: code borrowed from machines, mark.lua
-- need for marking
machines = {};
machines.pos1 = {};machines.pos11 = {}; machines.pos2 = {};
machines.marker1 = {}
machines.marker11 = {}
machines.marker2 = {}
machines.marker_region = {}
--marks machines region position 1
machines.mark_pos1 = function(name)
local pos1, pos2 = machines.pos1[name], machines.pos2[name]
if pos1 ~= nil then
--make area stay loaded
local manip = minetest.get_voxel_manip()
manip:read_from_map(pos1, pos1)
end
if not machines[name] then machines[name]={} end
machines[name].timer = 10;
if machines.marker1[name] ~= nil then --marker already exists
machines.marker1[name]:remove() --remove marker
machines.marker1[name] = nil
end
if pos1 ~= nil then
--add marker
machines.marker1[name] = minetest.add_entity(pos1, "machines:pos1")
if machines.marker1[name] ~= nil then
machines.marker1[name]:get_luaentity().name = name
end
end
end
--marks machines region position 1
machines.mark_pos11 = function(name)
local pos11 = machines.pos11[name];
if pos11 ~= nil then
--make area stay loaded
local manip = minetest.get_voxel_manip()
manip:read_from_map(pos11, pos11)
end
if not machines[name] then machines[name]={} end
machines[name].timer = 10;
if machines.marker11[name] ~= nil then --marker already exists
machines.marker11[name]:remove() --remove marker
machines.marker11[name] = nil
end
if pos11 ~= nil then
--add marker
machines.marker11[name] = minetest.add_entity(pos11, "machines:pos11")
if machines.marker11[name] ~= nil then
machines.marker11[name]:get_luaentity().name = name
end
end
end
--marks machines region position 2
machines.mark_pos2 = function(name)
local pos1, pos2 = machines.pos1[name], machines.pos2[name]
if pos2 ~= nil then
--make area stay loaded
local manip = minetest.get_voxel_manip()
manip:read_from_map(pos2, pos2)
end
if not machines[name] then machines[name]={} end
machines[name].timer = 10;
if machines.marker2[name] ~= nil then --marker already exists
machines.marker2[name]:remove() --remove marker
machines.marker2[name] = nil
end
if pos2 ~= nil then
--add marker
machines.marker2[name] = minetest.add_entity(pos2, "machines:pos2")
if machines.marker2[name] ~= nil then
machines.marker2[name]:get_luaentity().name = name
end
end
end
minetest.register_entity(":machines:pos1", {
initial_properties = {
visual = "cube",
visual_size = {x=1.1, y=1.1},
textures = {"machines_pos1.png", "machines_pos1.png",
"machines_pos1.png", "machines_pos1.png",
"machines_pos1.png", "machines_pos1.png"},
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
physical = false,
},
on_step = function(self, dtime)
if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
machines[self.name].timer = machines[self.name].timer - dtime
if machines[self.name].timer<=0 or machines.marker1[self.name] == nil then
self.object:remove()
end
end,
on_punch = function(self, hitter)
self.object:remove()
machines.marker1[self.name] = nil
machines[self.name].timer = 10
end,
})
minetest.register_entity(":machines:pos11", {
initial_properties = {
visual = "cube",
visual_size = {x=1.1, y=1.1},
textures = {"machines_pos11.png", "machines_pos11.png",
"machines_pos11.png", "machines_pos11.png",
"machines_pos11.png", "machines_pos11.png"},
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
physical = false,
},
on_step = function(self, dtime)
if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
machines[self.name].timer = machines[self.name].timer - dtime
if machines[self.name].timer<=0 or machines.marker11[self.name] == nil then
self.object:remove()
end
end,
on_punch = function(self, hitter)
self.object:remove()
machines.marker11[self.name] = nil
machines[self.name].timer = 10
end,
})
minetest.register_entity(":machines:pos2", {
initial_properties = {
visual = "cube",
visual_size = {x=1.1, y=1.1},
textures = {"machines_pos2.png", "machines_pos2.png",
"machines_pos2.png", "machines_pos2.png",
"machines_pos2.png", "machines_pos2.png"},
collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
physical = false,
},
on_step = function(self, dtime)
if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
if machines[self.name].timer<=0 or machines.marker2[self.name] == nil then
self.object:remove()
end
end,
})

141
mesecon_doors.lua Normal file
View File

@ -0,0 +1,141 @@
-- make doors open/close with signal
local function door_signal_overwrite(name)
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
local door_on_rightclick = table.on_rightclick;
-- this will make door toggle whenever its used
table2.mesecons = {effector = {
action_on = function (pos,node,ttl)
if ttl<0 then return end
local meta = minetest.get_meta(pos);local name = meta:get_string("doors_owner");
-- create virtual player
local clicker = {};
function clicker:get_player_name() return name end; -- define method get_player_name() returning owner name so that we can call on_rightclick function in door
function clicker:is_player() return false end; -- method needed for mods that check this: like denaid areas mod
if door_on_rightclick then door_on_rightclick(pos, node, clicker) end -- safety if it doesnt exist
--minetest.swap_node(pos, {name = "protector:trapdoor", param1 = node.param1, param2 = node.param2})
end
}
};
minetest.register_node(":"..name, table2)
end
minetest.after(0,function()
door_signal_overwrite("doors:door_wood_a");door_signal_overwrite("doors:door_wood_b");
door_signal_overwrite("doors:door_steel_a");door_signal_overwrite("doors:door_steel_b");
door_signal_overwrite("doors:trapdoor");door_signal_overwrite("doors:trapdoor_open");
door_signal_overwrite("doors:trapdoor_steel");door_signal_overwrite("doors:trapdoor_steel_open");
end
);
local function make_it_noclip(name)
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
table2.walkable = false; -- cant be walked on
minetest.register_node(":"..name, table2)
end
minetest.after(0,function()
make_it_noclip("doors:trapdoor_open");
make_it_noclip("doors:trapdoor_steel_open");
end);
local function make_it_nondiggable_but_removable(name, dropname)
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
table2.groups.level = 99; -- cant be digged, but it can be removed by owner or if not protected
table2.on_punch = function(pos, node, puncher, pointed_thing) -- remove node if owner repeatedly punches it 3x
local pname = puncher:get_player_name();
local meta = minetest.get_meta(pos);
local owner = meta:get_string("doors_owner")
if pname==owner or not minetest.is_protected(pos,pname) then -- can be dug by owner or if unprotected
local t0 = meta:get_int("punchtime");local count = meta:get_int("punchcount");
local t = minetest.get_gametime();
if t-t0<2 then count = (count +1 ) % 3 else count = 0 end
if count == 1 then
minetest.chat_send_player(pname, "#steel door: punch me one more time to remove me");
end
if count == 2 then -- remove steel door and drop it
minetest.set_node(pos, {name = "air"});
local stack = ItemStack(dropname);minetest.add_item(pos,stack)
end
meta:set_int("punchcount",count);meta:set_int("punchtime",t);
--minetest.chat_send_all("punch by "..name .. " count " .. count)
end
end
minetest.register_node(":"..name, table2)
end
minetest.after(0,function()
make_it_nondiggable_but_removable("doors:door_steel_a","doors:door_steel");
make_it_nondiggable_but_removable("doors:door_steel_b","doors:door_steel");
make_it_nondiggable_but_removable("doors:trapdoor_steel","doors:trapdoor_steel");
make_it_nondiggable_but_removable("doors:trapdoor_steel_open","doors:trapdoor_steel");
end);
-- make protected trapdoor open close and when open make it unwalkable
local function trapdoor_open_overwrite()
local name = "protector:trapdoor_open";
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
table2.walkable = false; -- opened trapdoor cant be walked on
table2.mesecons = {effector = {
action_off = function (pos,node,ttl)
if ttl<0 then return end
minetest.swap_node(pos, {name = "protector:trapdoor", param1 = node.param1, param2 = node.param2})
end
}
};
minetest.register_node(":"..name, table2)
end
minetest.after(0,trapdoor_open_overwrite);
local function trapdoor_close_overwrite()
local name = "protector:trapdoor";
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
table2.mesecons = {effector = {
action_on = function (pos,node,ttl)
if ttl<0 then return end
minetest.swap_node(pos, {name = "protector:trapdoor_open", param1 = node.param1, param2 = node.param2})
end
}
};
minetest.register_node(":"..name, table2)
end
minetest.after(0,trapdoor_close_overwrite);

52
mesecon_lights.lua Normal file
View File

@ -0,0 +1,52 @@
-- make other light blocks work with mesecon signals - can toggle on/off
local function enable_toggle_light(name)
local table = minetest.registered_nodes[name]; if not table then return end
local table2 = {}
for i,v in pairs(table) do
table2[i] = v
end
if table2.mesecons then return end -- we dont want to overwrite existing stuff!
local offname = "basic_machines:"..string.gsub(name, ":", "_").. "_OFF";
table2.mesecons = {effector = { -- action to toggle light off
action_off = function (pos,node,ttl)
if ttl<0 then return end
minetest.swap_node(pos,{name = offname});
end
}
};
minetest.register_node(":"..name, table2) -- redefine item
-- STRANGE BUG1: if you dont make new table table3 and reuse table2 definition original node (definition one line above) is changed by below code too!???
-- STRANGE BUG2: if you dont make new table3.. original node automatically changes to OFF node when placed ????
local table3 = {}
for i,v in pairs(table) do
table3[i] = v
end
table3.light_source = 0; -- off block has light off
table3.mesecons = {effector = {
action_on = function (pos,node,ttl)
if ttl<0 then return end
minetest.swap_node(pos,{name = name});
end
}
};
-- REGISTER OFF BLOCK
minetest.register_node(":"..offname, table3);
end
enable_toggle_light("xdecor:wooden_lightbox");
enable_toggle_light("xdecor:iron_lightbox");
enable_toggle_light("moreblocks:slab_meselamp_1");
enable_toggle_light("moreblocks:slab_super_glow_glass");
enable_toggle_light("darkage:lamp");

2381
mover.lua Normal file

File diff suppressed because it is too large Load Diff

54
protect.lua Normal file
View File

@ -0,0 +1,54 @@
-- adds event handler for attempt to dig in protected area
-- tries to activate specially configured nearby distributor at points with coordinates of form 20i, registers dig attempts in radius 10 around
-- distributor must have first target filter set to 0 ( disabled ) to handle dig events
local old_is_protected = minetest.is_protected
local round = math.floor;
local machines_TTL=5
function minetest.is_protected(pos, digger)
local is_protected = old_is_protected(pos, digger);
if is_protected then -- only if protected
local r = 20;local p = {x=round(pos.x/r+0.5)*r,y=round(pos.y/r+0.5)*r+1,z=round(pos.z/r+0.5)*r}
if minetest.get_node(p).name == "basic_machines:distributor" then -- attempt to activate distributor at special grid location: coordinates of the form 10+20*i
local meta = minetest.get_meta(p);
if meta:get_int("active1") == 0 then -- first output is disabled, indicating ready to be used as event handler
if meta:get_int("x1") ~= 0 then -- trigger protection event
meta:set_string("infotext",digger); -- record diggers name onto distributor
local table = minetest.registered_nodes["basic_machines:distributor"];
local effector=table.mesecons.effector;
local node = nil;
effector.action_on(p,node,machines_TTL);
end
end
end
end
return is_protected;
end
minetest.register_on_chat_message(function(name, message)
local player = minetest.get_player_by_name(name);
if not player then return end
local pos = player:getpos();
local r = 20;local p = {x=round(pos.x/r+0.5)*r,y=round(pos.y/r+0.5)*r+1,z=round(pos.z/r+0.5)*r}
--minetest.chat_send_all(minetest.pos_to_string(p))
if minetest.get_node(p).name == "basic_machines:distributor" then -- attempt to activate distributor at special grid location: coordinates of the form 20*i
local meta = minetest.get_meta(p);
if meta:get_int("active1") == 0 then -- first output is disabled, indicating ready to be used as event handler
local y1 = meta:get_int("y1");
if y1 ~= 0 then -- chat event, positive relays message, negative drops it
meta:set_string("infotext",message); -- record diggers message
local table = minetest.registered_nodes["basic_machines:distributor"];
local effector=table.mesecons.effector;
local node = nil;
effector.action_on(p,node,machines_TTL);
if y1<0 then return true
end
end
end
end
end
)

237
recycler.lua Normal file
View File

@ -0,0 +1,237 @@
-- rnd 2015:
-- this node works as a reverse of crafting process with a 25% loss of items (aka recycling). You can select which recipe to use when recycling.
-- There is a fuel cost to recycle
-- prevent unrealistic recyclings
local no_recycle_list = {
["default:steel_ingot"]=1,["default:copper_ingot"]=1,["default:bronze_ingot"]=1,["default:gold_ingot"]=1,
["dye:white"]=1,["dye:grey"]=1,["dye:dark_grey"]=1,["dye:black"]=1,
["dye:violet"]=1,["dye:blue"]=1,["dye:cyan"]=1,["dye:dark_green"]=1,
["dye:green"]=1,["dye:yellow"]=1,["dye:brown"]=1,["dye:orange"]=1,
["dye:red"]=1,["dye:magenta"]=1,["dye:pink"]=1,
}
local recycler_process = function(pos)
local node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
local meta = minetest.get_meta(pos);local inv = meta:get_inventory();
-- FUEL CHECK
local fuel = meta:get_float("fuel");
if fuel-1<0 then -- we need new fuel, check chest below
local fuellist = inv:get_list("fuel")
if not fuellist then return end
local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
local supply=0;
if fueladd.time == 0 then -- no fuel inserted, try look for outlet
-- No valid fuel in fuel list
supply = basic_machines.check_power({x=pos.x,y=pos.y-1,z=pos.z},1) or 0;
if supply>0 then
fueladd.time = 40*supply -- same as 10 coal
else
meta:set_string("infotext", "Please insert fuel.");
return;
end
else
if supply==0 then -- Take fuel from fuel list if no supply available
inv:set_stack("fuel", 1, afterfuel.items[1])
fueladd.time = fueladd.time*0.1; -- thats 4 for coal
end
end
if fueladd.time>0 then
fuel=fuel + fueladd.time
meta:set_float("fuel",fuel);
meta:set_string("infotext", "added fuel furnace burn time " .. fueladd.time .. ", fuel status " .. fuel);
end
if fuel-1<0 then return end
end
-- RECYCLING: check out inserted items
local stack = inv:get_stack("src",1);
if stack:is_empty() then return end; -- nothing to do
local src_item = stack:to_string();
local p=string.find(src_item," "); if p then src_item = string.sub(src_item,1,p-1) end -- take first word to determine what item was
-- look if we already handled this item
local known_recipe=true;
if src_item~=meta:get_string("node") then-- did we already handle this? if yes read from cache
meta:set_string("node",src_item);
meta:set_string("itemlist","{}");
meta:set_int("reqcount",0);
known_recipe=false;
end
local itemlist, reqcount;
reqcount = 1; -- needed count of materials for recycle to work
if not known_recipe then
if no_recycle_list[src_item] then meta:set_string("node","") return end -- dont allow recycling of forbidden items
local recipe = minetest.get_all_craft_recipes( src_item );
local recipe_id = tonumber(meta:get_int("recipe")) or 1;
if not recipe then
return
else
itemlist = recipe[recipe_id];
if not itemlist then meta:set_string("node","") return end;
itemlist=itemlist.items;
end
local output = recipe[recipe_id].output or "";
if string.find(output," ") then
local par = string.find(output," ");
--if (tonumber(string.sub(output, par)) or 0)>1 then itemlist = {} end
if par then
reqcount = tonumber(string.sub(output, par)) or 1;
end
end
meta:set_string("itemlist",minetest.serialize(itemlist)); -- read cached itemlist
meta:set_int("reqcount",reqcount);
else
itemlist=minetest.deserialize(meta:get_string("itemlist")) or {};
reqcount = meta:get_int("reqcount") or 1;
end
if stack:get_count()<reqcount then
meta:set_string("infotext", "at least " .. reqcount .. " of " .. src_item .. " is needed ");
return
end
--empty dst inventory before proceeding
-- local size = inv:get_size("dst");
-- for i=1,size do
-- inv:set_stack("dst", i, ItemStack(""));
-- end
for _, v in pairs(itemlist) do
if math.random(1, 4)<=3 then -- probability 3/4 = 75%
if not string.find(v,"group") then -- dont add if item described with group
local par = string.find(v,"\"") or 0;
if inv:room_for_item("dst", ItemStack(v)) then -- can item be put in
inv:add_item("dst",ItemStack(v));
else return
end
end
end
end
--take 1 item from src inventory for each activation
stack=stack:take_item(reqcount); inv:remove_item("src", stack)
minetest.sound_play("recycler", {pos=pos,gain=0.5,max_hear_distance = 16,})
fuel = fuel-1; -- burn fuel on succesful operation
meta:set_float("fuel",fuel); meta:set_string("infotext", "fuel status " .. fuel .. ", recycling " .. meta:get_string("node"));
end
local recycler_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local form =
"size[8,8]" .. -- width, height
--"size[6,10]" .. -- width, height
"label[0,0;IN] label[1,0;OUT] label[0,2;FUEL] "..
"list["..list_name..";src;0.,0.5;1,1;]"..
"list["..list_name..";dst;1.,0.5;3,3;]"..
"list["..list_name..";fuel;0.,2.5;1,1;]"..
"list[current_player;main;0,4;8,4;]"..
"field[4.5,0.75;2,1;recipe;select recipe: ;" .. (meta:get_int("recipe")) .. "]"..
"button[6.5,0.5;1,1;OK;OK]";
--"field[0.25,4.5;2,1;mode;mode;"..mode.."]";
meta:set_string("formspec", form);
end
minetest.register_node("basic_machines:recycler", {
description = "Recycler - use to get some ingredients back from crafted things",
tiles = {"recycler.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext", "Recycler: put one item in it (src) and obtain 75% of raw materials (dst). To operate it insert fuel, then insert item to recycle or use keypad to activate it.")
meta:set_string("owner", placer:get_player_name());
meta:set_int("recipe",1);
meta:set_float("fuel",0);
local inv = meta:get_inventory();inv:set_size("src", 1);inv:set_size("dst",9);inv:set_size("fuel",1);
end,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
recycler_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname =="dst" then return end
recycler_process(pos);
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
recycler_process(pos);
end
}
},
on_receive_fields = function(pos, formname, fields, sender)
if minetest.is_protected(pos, sender:get_player_name()) then return end
if fields.quit then return end
local meta = minetest.get_meta(pos);
local recipe=1;
if fields.recipe then
recipe = tonumber(fields.recipe) or 1;
else return;
end
meta:set_int("recipe",recipe);
meta:set_string("node",""); -- this will force to reread recipe on next use
recycler_update_meta(pos);
end,
})
-- minetest.register_craft({
-- output = "basic_machines:recycler",
-- recipe = {
-- {"default:mese_crystal","default:mese_crystal","default:mese_crystal"},
-- {"default:mese_crystal","default:diamondblock","default:mese_crystal"},
-- {"default:mese_crystal","default:mese_crystal","default:mese_crystal"},
-- }
-- })

Binary file not shown.

BIN
sounds/electric_zap.ogg Normal file

Binary file not shown.

BIN
sounds/grinder.ogg Normal file

Binary file not shown.

BIN
sounds/recycler.ogg Normal file

Binary file not shown.

BIN
sounds/tng_transporter1.ogg Normal file

Binary file not shown.

BIN
sounds/transporter.ogg Normal file

Binary file not shown.

470
technic_power.lua Normal file
View File

@ -0,0 +1,470 @@
local machines_timer=5
local machines_minstep = 1
-- BATTERY
local battery_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local capacity = meta:get_float("capacity");
local maxpower = meta:get_float("maxpower");
local energy = math.ceil(10*meta:get_float("energy"))/10;
local form =
"size[8,6.5]" .. -- width, height
"label[0,0;FUEL] ".."label[6,0;UPGRADE] "..
"label[1,0;ENERGY ".. energy .."/ ".. capacity..", maximum power output ".. maxpower .."]"..
"label[1,1;UPGRADE LEVEL ".. meta:get_int("upgrade") .. " (mese and diamond block)]"..
"list["..list_name..";fuel;0.,0.5;1,1;]".. "list["..list_name..";upgrade;6.,0.5;2,1;]" ..
"list[current_player;main;0,2.5;8,4;]"..
"button[4.5,0.35;1.5,1;OK;REFRESH]";
meta:set_string("formspec", form);
end
--[power crystal name] = energy provided
basic_machines.energy_crystals = {
["basic_machines:power_cell"]=1,
["basic_machines:power_block"]=11,
["basic_machines:power_rod"]=100,
}
battery_recharge = function(pos)
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
local inv = meta:get_inventory();
local stack = inv:get_stack("fuel", 1); local item = stack:get_name();
local crystal = false;
local add_energy=0;
add_energy = basic_machines.energy_crystals[item] or 0;
if add_energy>0 then
crystal = true;
if energy+add_energy<=capacity then
stack:take_item(1);
inv:set_stack("fuel", 1, stack)
else
meta:set_string("infotext", "recharge problem: capacity " .. capacity .. ", needed " .. energy+add_energy)
end
else -- try do determine caloric value
local fuellist = inv:get_list("fuel");if not fuellist then return energy end
local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
if fueladd.time > 0 then
add_energy = fueladd.time/40;
if energy+add_energy<=capacity then
inv:set_stack("fuel", 1, afterfuel.items[1]);
end
end
end
if add_energy>0 then
if energy+add_energy<=capacity then
energy=energy+add_energy
meta:set_float("energy",energy);
meta:set_string("infotext", "(R) energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
--TODO2: add entity power status display
minetest.sound_play("electric_zap", {pos=pos,gain=0.05,max_hear_distance = 8,})
end
end
return energy; -- new battery energy level
end
battery_upgrade = function(pos)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory();
local count1,count2;count1=0;count2=0;
local stack,item,count;
for i=1,2 do
stack = inv:get_stack("upgrade", i);item = stack:get_name();count= stack:get_count();
if item == "default:mese" then
count1=count1+count
elseif item == "default:diamondblock" then
count2=count2+count
end
end
if count1<count2 then count =count1 else count=count2 end
meta:set_int("upgrade",count);
-- adjust capacity
local capacity = 10+20*count;
local maxpower = capacity*0.1;
capacity = math.ceil(capacity*10)/10;
local energy = 0;
meta:set_float("capacity",capacity)
meta:set_float("maxpower",maxpower)
meta:set_float("energy",0)
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
end
local machines_activate_furnace = minetest.registered_nodes["default:furnace"].on_metadata_inventory_put; -- this function will activate furnace
minetest.register_node("basic_machines:battery", {
description = "battery - stores energy, generates energy from fuel, can power nearby machines, or accelerate/run furnace above it. Its upgradeable.",
tiles = {"basic_machine_outlet.png","basic_machine_side.png","basic_machine_battery.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext","battery - stores energy, generates energy from fuel, can power nearby machines, or accelerate/run furnace above it when activated by keypad");
meta:set_string("owner",placer:get_player_name());
local inv = meta:get_inventory();inv:set_size("fuel", 1*1); -- place to put crystals
inv:set_size("upgrade", 2*1);
meta:set_int("upgrade",0); -- upgrade level determines energy storage capacity and max energy output
meta:set_float("capacity",10);meta:set_float("maxpower",1);
meta:set_float("energy",0);
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
-- try to power furnace on top of it
if energy>=1 then -- need at least 1 energy
pos.y=pos.y+1; local node = minetest.get_node(pos).name;
if node== "default:furnace" or node=="default:furnace_active" then
local fmeta = minetest.get_meta(pos);
local fuel_totaltime = fmeta:get_float("fuel_totaltime") or 0;
local fuel_time = fmeta:get_float("fuel_time") or 0;
local t0 = meta:get_int("ftime"); -- furnace time
local t1 = minetest.get_gametime();
if t1-t0<machines_minstep then -- to prevent too quick furnace acceleration, punishment is cooking reset
fmeta:set_float("src_time",0); return
end
meta:set_int("ftime",t1);
local upgrade = meta:get_int("upgrade");upgrade=upgrade*0.1;
--if fuel_time>4 then -- accelerated cooking
local src_time = fmeta:get_float("src_time") or 0
energy = energy - 0.25*upgrade; -- use energy to accelerate burning
fmeta:set_float("src_time",src_time+machines_timer*upgrade); -- with max 99 upgrades battery furnace works 6x faster
--end
if fuel_time>40 or fuel_totaltime == 0 or node=="default:furnace" then -- must burn for at least 40 secs or furnace out of fuel
fmeta:set_float("fuel_totaltime",60);fmeta:set_float("fuel_time",0) -- add 60 second burn time to furnace
energy=energy-0.5; -- use up energy to add fuel
-- make furnace start if not already started
if node~="default:furnace_active" and machines_activate_furnace then machines_activate_furnace(pos) end
-- update energy display
end
meta:set_float("energy",energy);
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
if energy>=1 then -- no need to recharge yet, will still work next time
return
else
local infotext = meta:get_string("infotext");
local new_infotext = "furnace needs at least 1 energy";
if new_infotext~=infotext then -- dont update unnecesarilly
meta:set_string("infotext", new_infotext);
pos.y=pos.y-1; -- so that it points to battery again!
end
end
else
pos.y=pos.y-1;
end
end
-- try to recharge by converting inserted fuel/power cells into energy
if energy<capacity then -- not full, try to recharge
battery_recharge(pos);
end
end
}},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
battery_update_meta(pos);
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then return end
local meta = minetest.get_meta(pos);
battery_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname=="fuel" then
battery_recharge(pos);
battery_update_meta(pos);
elseif listname == "upgrade" then
battery_upgrade(pos);
battery_update_meta(pos);
end
return stack:get_count();
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
if listname == "upgrade" then
battery_upgrade(pos);
battery_update_meta(pos);
end
return stack:get_count();
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
can_dig = function(pos)
local meta = minetest.get_meta(pos);
if meta:get_int("upgrade")~=0 then return false else return true end
end
})
-- GENERATOR
local generator_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local form =
"size[8,6.5]" .. -- width, height
"label[0,0;POWER CRYSTALS] ".."label[6,0;UPGRADE] "..
"label[1,1;UPGRADE LEVEL ".. meta:get_int("upgrade") .. " (gold and diamond block)]"..
"list["..list_name..";fuel;0.,0.5;1,1;]".. "list["..list_name..";upgrade;6.,0.5;2,1;]" ..
"list[current_player;main;0,2.5;8,4;]"..
"button[4.5,1.5;1.5,1;OK;REFRESH]" .. "button[6,1.5;1.5,1;help;help]";
meta:set_string("formspec", form);
end
generator_upgrade = function(pos)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory();
local count1,count2;count1=0;count2=0;
local stack,item,count;
for i=1,2 do
stack = inv:get_stack("upgrade", i);item = stack:get_name();count= stack:get_count();
if item == "default:goldblock" then
count1=count1+count
elseif item == "default:diamondblock" then
count2=count2+count
end
end
if count1<count2 then count =count1 else count=count2 end
meta:set_int("upgrade",count);
end
minetest.register_node("basic_machines:generator", {
description = "Generator - very expensive, generates power crystals that provide power. Its upgradeable.",
tiles = {"basic_machine_side.png","basic_machine_side.png","basic_machine_generator.png"},
groups = {oddly_breakable_by_hand=2,mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext","generator - generates power crystals that provide power. Upgrade with up to 99 gold/diamond blocks.");
meta:set_string("owner",placer:get_player_name());
local inv = meta:get_inventory();
inv:set_size("fuel", 1*1); -- here generated power crystals are placed
inv:set_size("upgrade", 2*1);
meta:set_int("upgrade",0); -- upgrade level determines quality of produced crystals
end,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
generator_update_meta(pos);
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then return end
if fields.help then
local text = "Generator slowly produces power crystals. Those can be used to recharge batteries and come in 3 flavors:\n\n low (0-20), medium (20-99) and high level (99). Upgrading the generator will increase the rate at which the crystals are produces.\n\nYou can automate the process of recharging by using mover in inventory mode, taking from inventory \"fuel\"";
local form = "size [6,7] textarea[0,0;6.5,8.5;help;GENERATOR HELP;".. text.."]"
minetest.show_formspec(sender:get_player_name(), "basic_machines:help_mover", form)
return
end
local meta = minetest.get_meta(pos);
generator_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "upgrade" then
generator_upgrade(pos);
generator_update_meta(pos);
end
return stack:get_count();
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
if listname == "upgrade" then
generator_upgrade(pos);
generator_update_meta(pos);
end
return stack:get_count();
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
can_dig = function(pos)
local meta = minetest.get_meta(pos);
if meta:get_int("upgrade")~=0 then return false else return true end
end
})
minetest.register_abm({
nodenames = {"basic_machines:generator"},
neighbors = {""},
interval = 19,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos);
local upgrade = meta:get_int("upgrade");
local inv = meta:get_inventory();
local stack = inv:get_stack("fuel", 1);
local crystal, text;
if upgrade >= 99 then
crystal = "basic_machines:power_rod"
text = "high upgrade: power rod";
elseif upgrade >=20 then
crystal ="basic_machines:power_block " .. math.floor(1+(upgrade-20)*9/79);
text = "medium upgrade: power block";
else
crystal ="basic_machines:power_cell " .. math.floor(1+upgrade*9/20);
text = "low upgrade: power cell";
end
local morecrystal = ItemStack(crystal)
stack:add_item(morecrystal);
inv:set_stack("fuel", 1, stack)
meta:set_string("infotext",text)
end
})
-- API for power distribution
function basic_machines.check_power(pos, power_draw) -- mover checks power source - battery
--minetest.chat_send_all(" battery: check_power " .. minetest.pos_to_string(pos) .. " " .. power_draw)
if minetest.get_node(pos).name ~= "basic_machines:battery"
then return 0
end
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
local maxpower = meta:get_float("maxpower");
if power_draw>maxpower then
meta:set_string("infotext", "Power draw required : " .. power_draw .. " maximum power output " .. maxpower .. ". Please upgrade battery")
return 0;
end
if power_draw>energy then
energy = battery_recharge(pos); -- try recharge battery and continue operation immidiately
end
energy = energy-power_draw;
if energy<0 then
meta:set_string("infotext", "used fuel provides too little power for current power draw ".. power_draw);
return 0
end -- recharge wasnt enough, needs to be repeated manually, return 0 power available
meta:set_float("energy", energy);
-- update energy display
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
return power_draw;
end
------------------------
-- CRAFTS
------------------------
-- minetest.register_craft({
-- output = "basic_machines:battery",
-- recipe = {
-- {"","default:steel_ingot",""},
-- {"default:steel_ingot","default:mese","default:steel_ingot"},
-- {"","default:diamond",""},
-- }
-- })
-- minetest.register_craft({
-- output = "basic_machines:generator",
-- recipe = {
-- {"","",""},
-- {"default:diamondblock","basic_machines:battery","default:diamondblock"},
-- {"default:diamondblock","default:diamondblock","default:diamondblock"}
-- }
-- })
minetest.register_craftitem("basic_machines:power_cell", {
description = "Power cell - provides 1 power",
inventory_image = "power_cell.png",
stack_max = 25
})
minetest.register_craftitem("basic_machines:power_block", {
description = "Power block - provides 11 power",
inventory_image = "power_block.png",
stack_max = 25
})
minetest.register_craftitem("basic_machines:power_rod", {
description = "Power rod - provides 100 power",
inventory_image = "power_rod.png",
stack_max = 25
})

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1014 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

BIN
textures/compass_top.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 913 B

BIN
textures/cpu.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 676 B

BIN
textures/detector.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

BIN
textures/distributor.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 960 B

BIN
textures/enviro.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
textures/grinder.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
textures/keypad.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 987 B

BIN
textures/light.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 B

BIN
textures/light_off.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

BIN
textures/machines_pos1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

BIN
textures/machines_pos11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

BIN
textures/machines_pos2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 B

BIN
textures/power_block.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

BIN
textures/power_cell.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
textures/power_rod.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 B

BIN
textures/recycler.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B