├── README
├── autocrafter.lua
├── ball.lua
├── constructor.lua
├── depends.txt
├── enviro.lua
├── grinder.lua
├── init.lua
├── mark.lua
├── mesecon_adapter.lua
├── mesecon_doors.lua
├── mesecon_lights.lua
├── mod.conf
├── mover.lua
├── plans.txt
├── protect.lua
├── recycler.lua
├── sounds
├── chest_inventory_move.ogg
├── electric_zap.ogg
├── grinder.ogg
├── recycler.ogg
├── tng_transporter1.ogg
└── transporter.ogg
├── technic_power.lua
└── textures
├── basic_machine_battery.png
├── basic_machine_battery_0.png
├── basic_machine_battery_1.png
├── basic_machine_battery_2.png
├── basic_machine_clock_generator.png
├── basic_machine_generator.png
├── basic_machine_mover_side.png
├── basic_machine_outlet.png
├── basic_machine_side.png
├── basic_machines_ball.png
├── basic_machines_dust.png
├── basic_machines_stars.png
├── charcoal.png
├── compass_top.png
├── constructor.png
├── detector.png
├── distributor.png
├── enviro.png
├── grinder.png
├── keypad.png
├── light.png
├── light_off.png
├── machines_pos1.png
├── machines_pos11.png
├── machines_pos2.png
├── ore_extractor.png
├── pipeworks_autocrafter.png
├── power_block.png
├── power_cell.png
├── power_rod.png
└── recycler.png
/README:
--------------------------------------------------------------------------------
1 | BASIC_MACHINES: lightweight automation mod for minetest
2 | minetest 0.4.14+
3 | (c) 2015-2016 rnd
4 | textures by rnd, new textures by SaKeL (2016) and Jozet (2017)
5 |
6 |
7 | MANUAL:
8 | 1.WIKI PAGES: https://github.com/ac-minetest/basic_machines/wiki
9 | 2.ingame help: right click mover/detector/keypad.. and click help button
10 |
11 | ---------------------------------------------------------------------
12 | This program is free software: you can redistribute it and/or modify
13 | it under the terms of the GNU General Public License as published by
14 | the Free Software Foundation, either version 3 of the License, or
15 | (at your option) any later version.
16 |
17 | This program is distributed in the hope that it will be useful,
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 | GNU General Public License for more details.
21 |
22 | You should have received a copy of the GNU General Public License
23 | along with this program. If not, see .
24 | ----------------------------------------------------------------------
--------------------------------------------------------------------------------
/autocrafter.lua:
--------------------------------------------------------------------------------
1 | -- modified and adapted from pipeworks mod by VanessaE
2 | -- by rnd
3 | -- disabled timers and on/off button, now autocrafter is only activated by signal
4 |
5 | local autocrafterCache = {} -- caches some recipe data to avoid to call the slow function minetest.get_craft_result() every second
6 |
7 | local craft_time = 1
8 |
9 | local function count_index(invlist)
10 | local index = {}
11 | for _, stack in pairs(invlist) do
12 | if not stack:is_empty() then
13 | local stack_name = stack:get_name()
14 | index[stack_name] = (index[stack_name] or 0) + stack:get_count()
15 | end
16 | end
17 | return index
18 | end
19 |
20 | local function get_item_info(stack)
21 | local name = stack:get_name()
22 | local def = minetest.registered_items[name]
23 | local description = def and def.description or "Unknown item"
24 | return description, name
25 | end
26 |
27 | local function get_craft(pos, inventory, hash)
28 | local hash = hash or minetest.hash_node_position(pos)
29 | local craft = autocrafterCache[hash]
30 | if not craft then
31 | local recipe = inventory:get_list("recipe")
32 | local output, decremented_input = minetest.get_craft_result({method = "normal", width = 3, items = recipe})
33 | craft = {recipe = recipe, consumption=count_index(recipe), output = output, decremented_input = decremented_input}
34 | autocrafterCache[hash] = craft
35 | end
36 | return craft
37 | end
38 |
39 | local function autocraft(inventory, craft)
40 | if not craft then return false end
41 | local output_item = craft.output.item
42 |
43 | -- check if we have enough room in dst
44 | if not inventory:room_for_item("dst", output_item) then return false end
45 | local consumption = craft.consumption
46 | local inv_index = count_index(inventory:get_list("src"))
47 | -- check if we have enough material available
48 | for itemname, number in pairs(consumption) do
49 | if (not inv_index[itemname]) or inv_index[itemname] < number then return false end
50 | end
51 | -- consume material
52 | for itemname, number in pairs(consumption) do
53 | for i = 1, number do -- We have to do that since remove_item does not work if count > stack_max
54 | inventory:remove_item("src", ItemStack(itemname))
55 | end
56 | end
57 |
58 | -- craft the result into the dst inventory and add any "replacements" as well
59 | inventory:add_item("dst", output_item)
60 | for i = 1, 9 do
61 | inventory:add_item("dst", craft.decremented_input.items[i])
62 | end
63 | return true
64 | end
65 |
66 | -- returns false to stop the timer, true to continue running
67 | -- is started only from start_autocrafter(pos) after sanity checks and cached recipe
68 | local function run_autocrafter(pos, elapsed)
69 | local meta = minetest.get_meta(pos)
70 | local inventory = meta:get_inventory()
71 | local craft = get_craft(pos, inventory)
72 | local output_item = craft.output.item
73 | -- only use crafts that have an actual result
74 | if output_item:is_empty() then
75 | meta:set_string("infotext", "unconfigured Autocrafter: unknown recipe")
76 | return false
77 | end
78 |
79 | for step = 1, math.floor(elapsed/craft_time) do
80 | local continue = autocraft(inventory, craft)
81 | if not continue then return false end
82 | end
83 | return true
84 | end
85 |
86 | local function start_crafter(pos) -- rnd we dont need timer anymore
87 | -- local meta = minetest.get_meta(pos)
88 | -- if meta:get_int("enabled") == 1 then
89 | -- local timer = minetest.get_node_timer(pos)
90 | -- if not timer:is_started() then
91 | -- timer:start(craft_time)
92 | -- end
93 | -- end
94 | end
95 |
96 | local function after_inventory_change(pos)
97 | start_crafter(pos)
98 | end
99 |
100 | -- note, that this function assumes allready being updated to virtual items
101 | -- and doesn't handle recipes with stacksizes > 1
102 | local function after_recipe_change(pos, inventory)
103 | local meta = minetest.get_meta(pos)
104 | -- if we emptied the grid, there's no point in keeping it running or cached
105 | if inventory:is_empty("recipe") then
106 | --minetest.get_node_timer(pos):stop()
107 | autocrafterCache[minetest.hash_node_position(pos)] = nil
108 | meta:set_string("infotext", "unconfigured Autocrafter")
109 | return
110 | end
111 | local recipe_changed = false
112 | local recipe = inventory:get_list("recipe")
113 |
114 | local hash = minetest.hash_node_position(pos)
115 | local craft = autocrafterCache[hash]
116 |
117 | if craft then
118 | -- check if it changed
119 | local cached_recipe = craft.recipe
120 | for i = 1, 9 do
121 | if recipe[i]:get_name() ~= cached_recipe[i]:get_name() then
122 | autocrafterCache[hash] = nil -- invalidate recipe
123 | craft = nil
124 | break
125 | end
126 | end
127 | end
128 |
129 | craft = craft or get_craft(pos, inventory, hash)
130 | local output_item = craft.output.item
131 | local description, name = get_item_info(output_item)
132 | meta:set_string("infotext", string.format("'%s' Autocrafter (%s)", description, name))
133 | inventory:set_stack("output", 1, output_item)
134 |
135 | after_inventory_change(pos)
136 | end
137 |
138 | -- clean out unknown items and groups, which would be handled like unknown items in the crafting grid
139 | -- if minetest supports query by group one day, this might replace them
140 | -- with a canonical version instead
141 | local function normalize(item_list)
142 | for i = 1, #item_list do
143 | local name = item_list[i]
144 | if not minetest.registered_items[name] then
145 | item_list[i] = ""
146 | end
147 | end
148 | return item_list
149 | end
150 |
151 | local function on_output_change(pos, inventory, stack)
152 | if not stack then
153 | inventory:set_list("output", {})
154 | inventory:set_list("recipe", {})
155 | else
156 | local input = minetest.get_craft_recipe(stack:get_name())
157 | if not input.items or input.type ~= "normal" then return end
158 | local items, width = normalize(input.items), input.width
159 | local item_idx, width_idx = 1, 1
160 | for i = 1, 9 do
161 | if width_idx <= width then
162 | inventory:set_stack("recipe", i, items[item_idx])
163 | item_idx = item_idx + 1
164 | else
165 | inventory:set_stack("recipe", i, ItemStack(""))
166 | end
167 | width_idx = (width_idx < 3) and (width_idx + 1) or 1
168 | end
169 | -- we'll set the output slot in after_recipe_change to the actual result of the new recipe
170 | end
171 | after_recipe_change(pos, inventory)
172 | end
173 |
174 | -- returns false if we shouldn't bother attempting to start the timer again after this
175 | local function update_meta(meta, enabled)
176 | --local state = enabled and "on" or "off"
177 | --meta:set_int("enabled", enabled and 1 or 0)
178 | meta:set_string("formspec",
179 | "size[8,11]"..
180 | "list[context;recipe;0,0;3,3;]"..
181 | "image[3,1;1,1;gui_hb_bg.png^[colorize:#141318:255]"..
182 | "list[context;output;3,1;1,1;]"..
183 | --"image_button[3,2;1,1;pipeworks_button_" .. state .. ".png;" .. state .. ";;;false;pipeworks_button_interm.png]" .. -- rnd disable button
184 | "list[context;src;0,3.5;8,3;]"..
185 | "list[context;dst;4,0;4,3;]"..
186 | default.gui_bg..
187 | default.gui_bg_img..
188 | default.gui_slots..
189 | default.get_hotbar_bg(0,7)..
190 | "list[current_player;main;0,7;8,4;]"..
191 | "listring[context;dst]"..
192 | "listring[current_player;main]"..
193 | "listring[context;src]"..
194 | "listring[current_player;main]"..
195 | "listring[context;recipe]"..
196 | "listring[current_player;main]"
197 | )
198 |
199 | -- toggling the button doesn't quite call for running a recipe change check
200 | -- so instead we run a minimal version for infotext setting only
201 | -- this might be more written code, but actually executes less
202 | local output = meta:get_inventory():get_stack("output", 1)
203 | if output:is_empty() then -- doesn't matter if paused or not
204 | 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).")
205 | return false
206 | end
207 |
208 | local description, name = get_item_info(output)
209 | local infotext = enabled and string.format("'%s' Autocrafter (%s)", description, name)
210 | or string.format("paused '%s' Autocrafter", description)
211 |
212 | meta:set_string("infotext", infotext)
213 | return enabled
214 | end
215 |
216 | -- 1st version of the autocrafter had actual items in the crafting grid
217 | -- the 2nd replaced these with virtual items, dropped the content on update and set "virtual_items" to string "1"
218 | -- the third added an output inventory, changed the formspec and added a button for enabling/disabling
219 | -- so we work out way backwards on this history and update each single case to the newest version
220 | local function upgrade_autocrafter(pos, meta)
221 | local meta = meta or minetest.get_meta(pos)
222 | local inv = meta:get_inventory()
223 |
224 | if inv:get_size("output") == 0 then -- we are version 2 or 1
225 | inv:set_size("output", 1)
226 | -- migrate the old autocrafters into an "enabled" state
227 | update_meta(meta, true)
228 |
229 | if meta:get_string("virtual_items") == "1" then -- we are version 2
230 | -- we allready dropped stuff, so lets remove the metadatasetting (we are not being called again for this node)
231 | meta:set_string("virtual_items", "")
232 | else -- we are version 1
233 | local recipe = inv:get_list("recipe")
234 | if not recipe then return end
235 | for idx, stack in ipairs(recipe) do
236 | if not stack:is_empty() then
237 | minetest.item_drop(stack, "", pos)
238 | stack:set_count(1)
239 | stack:set_wear(0)
240 | inv:set_stack("recipe", idx, stack)
241 | end
242 | end
243 | end
244 |
245 | -- update the recipe, cache, and start the crafter
246 | autocrafterCache[minetest.hash_node_position(pos)] = nil
247 | after_recipe_change(pos, inv)
248 | end
249 | end
250 |
251 | minetest.register_node("basic_machines:autocrafter", {
252 | description = "Autocrafter",
253 | drawtype = "normal",
254 | tiles = {"pipeworks_autocrafter.png"},
255 | groups = {cracky=3},
256 | on_construct = function(pos)
257 | local meta = minetest.get_meta(pos)
258 | local inv = meta:get_inventory()
259 | inv:set_size("src", 3*8)
260 | inv:set_size("recipe", 3*3)
261 | inv:set_size("dst", 4*3)
262 | inv:set_size("output", 1)
263 | update_meta(meta, false)
264 | end,
265 | on_receive_fields = function(pos, formname, fields, sender)
266 | --if not pipeworks.may_configure(pos, sender) then return end
267 | local meta = minetest.get_meta(pos)
268 | if fields.on then
269 | update_meta(meta, false)
270 | --minetest.get_node_timer(pos):stop()
271 | elseif fields.off then
272 | if update_meta(meta, true) then
273 | start_crafter(pos)
274 | end
275 | end
276 | end,
277 | can_dig = function(pos, player)
278 | upgrade_autocrafter(pos)
279 | local meta = minetest.get_meta(pos)
280 | local inv = meta:get_inventory()
281 | return (inv:is_empty("src") and inv:is_empty("dst"))
282 | end,
283 | after_place_node = function(pos, placer) -- rnd : set owner
284 | local meta = minetest.get_meta(pos);
285 | meta:set_string("owner", placer:get_player_name());
286 | end,
287 | --after_place_node = pipeworks.scan_for_tube_objects,
288 | --after_dig_node = function(pos)
289 | --pipeworks.scan_for_tube_objects(pos)
290 | --end,
291 | on_destruct = function(pos)
292 | autocrafterCache[minetest.hash_node_position(pos)] = nil
293 | end,
294 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
295 | --if not pipeworks.may_configure(pos, player) then return 0 end
296 | local meta = minetest.get_meta(pos);if meta:get_string("owner")~=player:get_player_name() then return 0 end -- rnd
297 |
298 | upgrade_autocrafter(pos)
299 | local inv = minetest.get_meta(pos):get_inventory()
300 | if listname == "recipe" then
301 | stack:set_count(1)
302 | inv:set_stack(listname, index, stack)
303 | after_recipe_change(pos, inv)
304 | return 0
305 | elseif listname == "output" then
306 | on_output_change(pos, inv, stack)
307 | return 0
308 | end
309 | after_inventory_change(pos)
310 | return stack:get_count()
311 | end,
312 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
313 | --if not pipeworks.may_configure(pos, player) then
314 | -- minetest.log("action", string.format("%s attempted to take from autocrafter at %s", player:get_player_name(), minetest.pos_to_string(pos)))
315 | -- return 0
316 | -- end
317 | local meta = minetest.get_meta(pos);if meta:get_string("owner")~=player:get_player_name() then return 0 end -- rnd
318 |
319 | upgrade_autocrafter(pos)
320 | local inv = minetest.get_meta(pos):get_inventory()
321 | if listname == "recipe" then
322 | inv:set_stack(listname, index, ItemStack(""))
323 | after_recipe_change(pos, inv)
324 | return 0
325 | elseif listname == "output" then
326 | on_output_change(pos, inv, nil)
327 | return 0
328 | end
329 | after_inventory_change(pos)
330 | return stack:get_count()
331 | end,
332 | allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
333 | return 0; -- no internal inventory moves!
334 | end,
335 |
336 | effector = { -- rnd: run machine when activated by signal
337 | action_on = function (pos, node,ttl)
338 | if type(ttl)~="number" then ttl = 1 end
339 | if ttl<0 then return end -- machines_TTL prevents infinite recursion
340 | run_autocrafter(pos, craft_time);
341 | end,
342 |
343 | can_dig = function(pos)
344 | local meta = minetest.get_meta(pos);
345 | local inv = meta:get_inventory();
346 |
347 | if not (inv:is_empty("src")) or not (inv:is_empty("dst")) then return false end -- all inv must be empty to be dug
348 |
349 | return true
350 |
351 | end
352 |
353 | }
354 |
355 | --on_timer = run_autocrafter -- rnd
356 | })
357 |
358 | -- minetest.register_craft( {
359 | -- output = "basic_machines:autocrafter",
360 | -- recipe = {
361 | -- { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" },
362 | -- { "default:diamondblock", "default:steel_ingot", "default:diamondblock" },
363 | -- { "default:steel_ingot", "default:mese_crystal", "default:steel_ingot" }
364 | -- },
365 | -- })
--------------------------------------------------------------------------------
/ball.lua:
--------------------------------------------------------------------------------
1 | -- BALL: energy ball that flies around, can bounce and activate stuff
2 | -- rnd 2016:
3 |
4 | -- 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
5 |
6 | -- SETTINGS
7 |
8 | basic_machines.ball = {};
9 | basic_machines.ball.maxdamage = 10; -- player health 20
10 | 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
11 | ["default:wood"]=1,
12 | ["xpanes:bar_2"]=1,
13 | ["xpanes:bar_10"]=1,
14 | ["darkage:iron_bars"]=1,
15 | ["default:glass"] = 2,
16 | };
17 |
18 | -- END OF SETTINGS
19 |
20 | local ballcount = {};
21 | local function round(x)
22 | if x < 0 then
23 | return -math.floor(-x+0.5);
24 | else
25 | return math.floor(x+0.5);
26 | end
27 | end
28 |
29 |
30 | local ball_spawner_update_form = function (pos)
31 |
32 | local meta = minetest.get_meta(pos);
33 | local x0,y0,z0;
34 | x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0"); -- direction of velocity
35 |
36 | local energy,bounce,g,puncheable, gravity,hp,hurt,solid;
37 | local speed = meta:get_float("speed"); -- if positive sets initial ball speed
38 | energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
39 | bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
40 | gravity = meta:get_float("gravity"); -- gravity
41 | hp = meta:get_float("hp");
42 | hurt = meta:get_float("hurt");
43 | puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
44 | solid = meta:get_int("solid"); -- if 1 then entity is solid - cant be walked on
45 |
46 | local texture = meta:get_string("texture") or "basic_machines_ball.png";
47 | local visual = meta:get_string("visual") or "sprite";
48 | local scale = meta:get_int("scale");
49 |
50 | local form =
51 | "size[4.25,4.75]" .. -- width, height
52 | "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.."]"..
53 | "field[3.25,0.5;1,1;speed;speed;"..speed.."]"..
54 | --speed, jump, gravity,sneak
55 | "field[0.25,1.5;1,1;energy;energy;"..energy.."]"..
56 | "field[1.25,1.5;1,1;bounce;bounce;".. bounce.."]"..
57 | "field[2.25,1.5;1,1;gravity;gravity;"..gravity.."]"..
58 | "field[3.25,1.5;1,1;puncheable;puncheable;"..puncheable.."]"..
59 | "field[3.25,2.5;1,1;solid;solid;"..solid.."]"..
60 | "field[0.25,2.5;1,1;hp;hp;"..hp.."]".."field[1.25,2.5;1,1;hurt;hurt;"..hurt.."]"..
61 | "field[0.25,3.5;4,1;texture;texture;"..minetest.formspec_escape(texture).."]"..
62 | "field[0.25,4.5;1,1;scale;scale;"..scale.."]".."field[1.25,4.5;1,1;visual;visual;"..visual.."]"..
63 | "button_exit[3.25,4.25;1,1;OK;OK]";
64 |
65 |
66 |
67 | if meta:get_int("admin")==1 then
68 | local lifetime = meta:get_int("lifetime");
69 | if lifetime <= 0 then lifetime = 20 end
70 | form = form .. "field[2.25,2.5;1,1;lifetime;lifetime;"..lifetime.."]"
71 | end
72 |
73 | meta:set_string("formspec",form);
74 |
75 | end
76 |
77 |
78 |
79 | minetest.register_entity("basic_machines:ball",{
80 | timer = 0,
81 | lifetime = 20, -- how long it exists before disappearing
82 | energy = 0, -- if negative it will deactivate stuff, positive will activate, 0 wont do anything
83 | puncheable = 1, -- can be punched by players in protection
84 | bounce = 0, -- 0: absorbs in block, 1 = proper bounce=lag buggy, -- to do: 2 = line of sight bounce
85 | gravity = 0,
86 | speed = 5, -- velocity when punched
87 | hurt = 0, -- how much damage it does to target entity, if 0 damage disabled
88 | owner = "",
89 | state = false,
90 | origin = {x=0,y=0,z=0},
91 | lastpos = {x=0,y=0,z=0}, -- last not-colliding position
92 | hp_max = 100,
93 | elasticity = 0.9, -- speed gets multiplied by this after bounce
94 | visual="sprite",
95 | visual_size={x=.6,y=.6},
96 | collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
97 | physical=false,
98 |
99 | --textures={"basic_machines_ball"},
100 |
101 | on_activate = function(self, staticdata)
102 | self.object:set_properties({textures={"basic_machines_ball.png"}})
103 | self.object:set_properties({visual_size = {x=1, y=1}});
104 | self.timer = 0;self.owner = "";
105 | self.origin = self.object:getpos();
106 | self.lifetime = 20;
107 | end,
108 |
109 | get_staticdata = function(self) -- this gets called before object put in world and before it hides
110 | if not self.state then return nil end
111 | self.object:remove();
112 | return nil
113 | end,
114 |
115 |
116 | on_punch = function (self, puncher, time_from_last_punch, tool_capabilities, dir)
117 | if self.puncheable == 0 then return end
118 | if self.puncheable == 1 then -- only those in protection
119 | local name = puncher:get_player_name();
120 | local pos = self.object:getpos();
121 | if minetest.is_protected(pos,name) then return end
122 | end
123 | --minetest.chat_send_all(minetest.pos_to_string(dir))
124 | if time_from_last_punch<0.5 then return end
125 | local v = self.speed or 1;
126 |
127 | local velocity = dir;
128 | velocity.x = velocity.x*v;velocity.y = velocity.y*v;velocity.z = velocity.z*v;
129 | self.object:setvelocity(velocity)
130 | end,
131 |
132 | on_step = function(self, dtime)
133 | self.timer=self.timer+dtime
134 | if self.timer>self.lifetime then
135 | local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
136 | self.object:remove()
137 | return
138 | end
139 |
140 | if not self.state then self.state = true end
141 | local pos=self.object:getpos()
142 |
143 | local origin = self.origin;
144 |
145 | local r = 30;-- maximal distance when balls disappear
146 | local dist = math.max(math.abs(pos.x-origin.x), math.abs(pos.y-origin.y), math.abs(pos.z-origin.z));
147 | if dist>r then -- remove if it goes too far
148 | local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
149 | self.object:remove()
150 | return
151 | end
152 |
153 | local nodename = minetest.get_node(pos).name;
154 | local walkable = false;
155 | if nodename ~= "air" then
156 | walkable = minetest.registered_nodes[nodename].walkable;
157 | if nodename == "basic_machines:ball_spawner" and dist>0.5 then walkable = true end -- ball can activate spawner, just not originating one
158 | end
159 | if not walkable then
160 | self.lastpos = pos
161 | if self.hurt~=0 then -- check for coliding nearby objects
162 | local objects = minetest.get_objects_inside_radius(pos,2);
163 | if #objects>1 then
164 | for _, obj in pairs(objects) do
165 | local p = obj:getpos();
166 | local d = math.sqrt((p.x-pos.x)^2+(p.y-pos.y)^2+(p.z-pos.z)^2);
167 | if d>0 then
168 |
169 | --if minetest.is_protected(p,self.owner) then return end
170 | 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
171 |
172 | if obj:is_player() then --player
173 | if obj:get_player_name()==self.owner then break end -- dont hurt owner
174 |
175 | local hp = obj:get_hp()
176 | local newhp = hp-self.hurt;
177 | if newhp<=0 and boneworld and boneworld.killxp then
178 | local killxp = boneworld.killxp[self.owner];
179 | if killxp then
180 | boneworld.killxp[self.owner] = killxp + 0.01;
181 | end
182 | end
183 | obj:set_hp(newhp)
184 | else -- non player
185 | local lua_entity = obj:get_luaentity();
186 | if lua_entity and lua_entity.itemstring then
187 | local entname = lua_entity.itemstring;
188 | if entname == "robot" then
189 | self.object:remove()
190 | return;
191 | end
192 | end
193 | local hp = obj:get_hp()
194 | local newhp = hp-self.hurt;
195 | minetest.chat_send_player(self.owner,"#ball: target hp " .. newhp)
196 | if newhp<=0 then obj:remove() else obj:set_hp(newhp) end
197 | end
198 |
199 |
200 |
201 |
202 | local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
203 | self.object:remove();
204 | return
205 | end
206 | end
207 | end
208 | end
209 | end
210 |
211 |
212 | if walkable then -- we hit a node
213 | --minetest.chat_send_all(" hit node at " .. minetest.pos_to_string(pos))
214 |
215 |
216 | local node = minetest.get_node(pos);
217 | local table = minetest.registered_nodes[node.name];
218 | if table and table.effector then -- activate target
219 |
220 | local energy = self.energy;
221 | if energy~=0 then
222 | if minetest.is_protected(pos,self.owner) then return end
223 | end
224 | local effector = table.effector;
225 |
226 | local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
227 | self.object:remove();
228 |
229 | if energy>0 then
230 | if not effector.action_on then return end
231 | effector.action_on(pos,node,16);
232 | elseif energy<0 then
233 | if not effector.action_off then return end
234 | effector.action_off(pos,node,16);
235 | end
236 |
237 |
238 | else -- bounce ( copyright rnd, 2016 )
239 | local bounce = self.bounce;
240 | if self.bounce == 0 then
241 | local count = ballcount[self.owner] or 1; count=count-1; ballcount[self.owner] = count;
242 | self.object:remove()
243 | return end
244 |
245 | local n = {x=0,y=0,z=0}; -- this will be bounce normal
246 | local v = self.object:getvelocity();
247 | local opos = {x=round(pos.x),y=round(pos.y), z=round(pos.z)}; -- obstacle
248 | local bpos ={ x=(pos.x-opos.x),y=(pos.y-opos.y),z=(pos.z-opos.z)}; -- boundary position on cube, approximate
249 |
250 | if bounce == 2 then -- uses special blocks for non buggy lag proof bouncing: by default it bounces in y direction
251 | local bounce_direction = basic_machines.ball.bounce_materials[node.name] or 0;
252 |
253 | if bounce_direction == 0 then
254 | if v.y>=0 then n.y = -1 else n.y = 1 end
255 | elseif bounce_direction == 1 then
256 | if v.x>=0 then n.x = -1 else n.x = 1 end
257 | n.y = 0;
258 | elseif bounce_direction == 2 then
259 | if v.z>=0 then n.z = -1 else n.z = 1 end
260 | n.y = 0;
261 | end
262 |
263 | else -- algorithm to determine bounce direction - problem: with lag its impossible to determine reliable which node was hit and which face ..
264 |
265 | if v.x<=0 then n.x = 1 else n.x = -1 end -- possible bounce directions
266 | if v.y<=0 then n.y = 1 else n.y = -1 end
267 | if v.z<=0 then n.z = 1 else n.z = -1 end
268 |
269 | local dpos = {};
270 |
271 | dpos.x = 0.5*n.x; dpos.y = 0; dpos.z = 0; -- calculate distance to bounding surface midpoints
272 |
273 | local d1 = (bpos.x-dpos.x)^2 + (bpos.y)^2 + (bpos.z)^2;
274 | dpos.x = 0; dpos.y = 0.5*n.y; dpos.z = 0;
275 | local d2 = (bpos.x)^2 + (bpos.y-dpos.y)^2 + (bpos.z)^2;
276 | dpos.x = 0; dpos.y = 0; dpos.z = 0.5*n.z;
277 | local d3 = (bpos.x)^2 + (bpos.y)^2 + (bpos.z-dpos.z)^2;
278 | local d = math.min(d1,d2,d3); -- we obtain bounce direction from minimal distance
279 |
280 | if d1==d then --x
281 | n.y=0;n.z=0
282 | elseif d2==d then --y
283 | n.x=0;n.z=0
284 | elseif d3==d then --z
285 | n.x=0;n.y=0
286 | end
287 |
288 |
289 | nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
290 | walkable = nodename ~= "air";
291 | if walkable then -- problem, nonempty node - incorrect normal, fix it
292 | if n.x ~=0 then -- x direction is wrong, try something else
293 | n.x=0;
294 | if v.y>=0 then n.y = -1 else n.y = 1 end -- try y
295 | nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
296 | walkable = nodename ~= "air";
297 | if walkable then -- still problem, only remaining is z
298 | n.y=0;
299 | if v.z>=0 then n.z = -1 else n.z = 1 end
300 | nodename=minetest.get_node({x=opos.x+n.x,y=opos.y+n.y,z=opos.z+n.z}).name -- verify normal
301 | walkable = nodename ~= "air";
302 | if walkable then -- messed up, just remove the ball
303 | self.object:remove()
304 | return
305 | end
306 |
307 | end
308 |
309 | end
310 | end
311 |
312 | end
313 |
314 | local elasticity = self.elasticity;
315 |
316 | -- bounce
317 | if n.x~=0 then
318 | v.x=-elasticity*v.x
319 | elseif n.y~=0 then
320 | v.y=-elasticity*v.y
321 | elseif n.z~=0 then
322 | v.z=-elasticity*v.z
323 | end
324 |
325 | local r = 0.2
326 | 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
327 | self.object:setpos(bpos) -- place object at last known outside point
328 |
329 | self.object:setvelocity(v);
330 |
331 | minetest.sound_play("default_dig_cracky", {pos=pos,gain=1.0,max_hear_distance = 8,})
332 |
333 | end
334 | end
335 | return
336 | end,
337 | })
338 |
339 |
340 | minetest.register_node("basic_machines:ball_spawner", {
341 | description = "Spawns energy ball one block above",
342 | tiles = {"basic_machines_ball.png"},
343 | groups = {cracky=3},
344 | drawtype = "allfaces",
345 | paramtype = "light",
346 | param1=1,
347 | walkable = false,
348 | sounds = default.node_sound_wood_defaults(),
349 | after_place_node = function(pos, placer)
350 | local meta = minetest.env:get_meta(pos)
351 | meta:set_string("owner", placer:get_player_name());
352 | local privs = minetest.get_player_privs(placer:get_player_name()); if privs.privs then meta:set_int("admin",1) end
353 |
354 | if privs.machines then meta:set_int("machines",1) end
355 |
356 | meta:set_float("hurt",0);
357 | meta:set_string("texture", "basic_machines_ball.png");
358 | meta:set_float("hp",100);
359 | meta:set_float("speed",5); -- if positive sets initial ball speed
360 | meta:set_float("energy",1); -- if positive activates, negative deactivates, 0 does nothing
361 | meta:set_int("bounce",0); -- if nonzero bounces when hit obstacle, 0 gets absorbed
362 | meta:set_float("gravity",0); -- gravity
363 | 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
364 | meta:set_int("scale",100);
365 | meta:set_string("visual","sprite"); -- sprite/cube OR particle
366 | ball_spawner_update_form(pos);
367 |
368 | end,
369 |
370 | effector = {
371 | action_on = function (pos, node,ttl)
372 | if type(ttl)~="number" then ttl = 1 end
373 | if ttl<0 then return end
374 |
375 | local meta = minetest.get_meta(pos);
376 | local t0 = meta:get_int("t");
377 | local t1 = minetest.get_gametime();
378 | local T = meta:get_int("T"); -- temperature
379 |
380 | if t0>t1-2 then -- activated before natural time
381 | T=T+1;
382 | else
383 | if T>0 then
384 | T=T-1
385 | if t1-t0>5 then T = 0 end
386 | end
387 | end
388 | meta:set_int("T",T);
389 | meta:set_int("t",t1); -- update last activation time
390 |
391 | if T > 2 then -- overheat
392 | minetest.sound_play("default_cool_lava",{pos = pos, max_hear_distance = 16, gain = 0.25})
393 | meta:set_string("infotext","overheat: temperature ".. T)
394 | return
395 | end
396 |
397 | if meta:get_int("machines")~=1 then -- no machines priv, limit ball count
398 | local owner = meta:get_string("owner");
399 | local count = ballcount[owner];
400 | if not count or count<0 then count = 0 end
401 |
402 | if count>=2 then
403 | if t1-t0>10 then count = 0
404 | else return
405 | end
406 | end
407 |
408 | count = count + 1;
409 | ballcount[owner]=count;
410 | --minetest.chat_send_all("count " .. count);
411 | end
412 |
413 | pos.x = round(pos.x);pos.y = round(pos.y);pos.z = round(pos.z);
414 | local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
415 | local luaent = obj:get_luaentity();
416 | local meta = minetest.get_meta(pos);
417 |
418 | local speed,energy,bounce,gravity,puncheable,solid;
419 | speed = meta:get_float("speed");
420 | energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
421 | bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
422 | gravity = meta:get_float("gravity"); -- gravity
423 | puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
424 | solid = meta:get_int("solid");
425 |
426 | if energy<0 then
427 | obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
428 | end
429 |
430 | luaent.bounce = bounce;
431 | luaent.energy = energy;
432 | if gravity>0 then
433 | obj:setacceleration({x=0,y=-gravity,z=0});
434 | end
435 | luaent.puncheable = puncheable;
436 | luaent.owner = meta:get_string("owner");
437 | luaent.hurt = meta:get_float("hurt");
438 | if solid==1 then
439 | luaent.physical = true
440 | end
441 |
442 | obj:set_hp( meta:get_float("hp") );
443 |
444 | local x0,y0,z0;
445 | if speed>0 then luaent.speed = speed end
446 |
447 | x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0"); -- direction of velocity
448 | if speed~=0 and (x0~=0 or y0~=0 or z0~=0) then -- set velocity direction
449 | local velocity = {x=x0,y=y0,z=z0};
450 | local v = math.sqrt(velocity.x^2+velocity.y^2+velocity.z^2); if v == 0 then v = 1 end
451 | v = v / speed;
452 | velocity.x=velocity.x/v;velocity.y=velocity.y/v;velocity.z=velocity.z/v;
453 | obj:setvelocity(velocity);
454 | end
455 |
456 | if meta:get_int("admin")==1 then
457 | luaent.lifetime = meta:get_float("lifetime");
458 | end
459 |
460 |
461 | local visual = meta:get_string("visual")
462 | obj:set_properties({visual=visual});
463 | local texture = meta:get_string("texture");
464 | if visual=="sprite" then
465 | obj:set_properties({textures={texture}})
466 | elseif visual == "cube" then
467 | obj:set_properties({textures={texture,texture,texture,texture,texture,texture}})
468 | end
469 | local scale = meta:get_int("scale");if scale<=0 then scale = 1 else scale = scale/100 end
470 | obj:set_properties({visual_size = {x=scale, y=scale}});
471 |
472 |
473 |
474 | end,
475 |
476 | action_off = function (pos, node,ttl)
477 | if type(ttl)~="number" then ttl = 1 end
478 | if ttl<0 then return end
479 | pos.x = round(pos.x);pos.y = round(pos.y);pos.z = round(pos.z);
480 | local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
481 | local luaent = obj:get_luaentity();
482 | luaent.energy = -1;
483 | obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
484 | end
485 | },
486 |
487 | on_receive_fields = function(pos, formname, fields, sender)
488 |
489 | local name = sender:get_player_name();if minetest.is_protected(pos,name) then return end
490 |
491 | if fields.OK then
492 | local privs = minetest.get_player_privs(sender:get_player_name());
493 | local meta = minetest.get_meta(pos);
494 | local x0=0; local y0=0; local z0=0;
495 | --minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
496 | if fields.x0 then x0 = tonumber(fields.x0) or 0 end
497 | if fields.y0 then y0 = tonumber(fields.y0) or 0 end
498 | if fields.z0 then z0 = tonumber(fields.z0) or 0 end
499 | if not privs.privs and (math.abs(x0)>10 or math.abs(y0)>10 or math.abs(z0) > 10) then return end
500 |
501 | meta:set_int("x0",x0);meta:set_int("y0",y0);meta:set_int("z0",z0);
502 |
503 | local speed,energy,bounce,gravity,puncheable,solid;
504 | energy = meta:get_float("energy"); -- if positive activates, negative deactivates, 0 does nothing
505 | bounce = meta:get_int("bounce"); -- if nonzero bounces when hit obstacle, 0 gets absorbed
506 | gravity = meta:get_float("gravity"); -- gravity
507 | puncheable = meta:get_int("puncheable"); -- if 1 can be punched by players in protection, if 2 can be punched by anyone
508 | solid = meta:get_int("solid");
509 |
510 |
511 | if fields.speed then
512 | local speed = tonumber(fields.speed) or 0;
513 | if (speed > 10 or speed < 0) and not privs.privs then return end
514 | meta:set_float("speed", speed)
515 | end
516 |
517 | if fields.energy then
518 | local energy = tonumber(fields.energy) or 1;
519 | meta:set_float("energy", energy)
520 | end
521 |
522 | if fields.bounce then
523 | local bounce = tonumber(fields.bounce) or 1;
524 | meta:set_int("bounce",bounce)
525 | end
526 |
527 | if fields.gravity then
528 | local gravity = tonumber(fields.gravity) or 1;
529 | if (gravity<0 or gravity>30) and not privs.privs then return end
530 | meta:set_float("gravity", gravity)
531 | end
532 | if fields.puncheable then
533 | meta:set_int("puncheable", tonumber(fields.puncheable) or 0)
534 | end
535 |
536 | if fields.solid then
537 | meta:set_int("solid", tonumber(fields.solid) or 0)
538 | end
539 |
540 | if fields.lifetime then
541 | meta:set_int("lifetime", tonumber(fields.lifetime) or 0)
542 | end
543 |
544 | if fields.hurt then
545 | meta:set_float("hurt", tonumber(fields.hurt) or 0)
546 | end
547 |
548 | if fields.hp then
549 | meta:set_float("hp", math.abs(tonumber(fields.hp) or 0))
550 | end
551 |
552 | if fields.texture then
553 | meta:set_string ("texture", fields.texture);
554 | end
555 |
556 | if fields.scale then
557 | local scale = math.abs(tonumber(fields.scale) or 100);
558 | if scale>1000 and not privs.privs then scale = 1000 end
559 | meta:set_int("scale", scale)
560 | end
561 |
562 | if fields.visual then
563 | local visual = fields.visual or "";
564 | if visual~="sprite" and visual~="cube" then return end
565 | meta:set_string ("visual", fields.visual);
566 | end
567 |
568 | ball_spawner_update_form(pos);
569 | end
570 | end,
571 |
572 | after_dig_node = function(pos, oldnode, oldmetadata, digger)
573 | local name = digger:get_player_name();
574 | local inv = digger:get_inventory();
575 | inv:remove_item("main", ItemStack("basic_machines:ball_spawner"));
576 | local stack = ItemStack("basic_machines:ball_spell");
577 | local meta = oldmetadata["fields"];
578 | meta["formspec"]=nil;
579 | stack:set_metadata(minetest.serialize(meta));
580 | inv:add_item("main",stack);
581 | end
582 |
583 | })
584 |
585 |
586 | local spelltime = {};
587 |
588 | -- ball as magic spell user can cast
589 | minetest.register_tool("basic_machines:ball_spell", {
590 | description = "ball spawner",
591 | inventory_image = "basic_machines_ball.png",
592 | tool_capabilities = {
593 | full_punch_interval = 2,
594 | max_drop_level=0,
595 | },
596 | on_use = function(itemstack, user, pointed_thing)
597 |
598 | local pos = user:getpos();pos.y=pos.y+1;
599 | local meta = minetest.deserialize(itemstack:get_metadata());
600 | if not meta then return end
601 | local owner = meta["owner"] or "";
602 |
603 | --if minetest.is_protected(pos,owner) then return end
604 |
605 | local t0 = spelltime[owner] or 0;
606 | local t1 = minetest.get_gametime();
607 | if t1-t0<2 then return end -- too soon
608 | spelltime[owner]=t1;
609 |
610 |
611 | local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "basic_machines:ball");
612 | local luaent = obj:get_luaentity();
613 |
614 |
615 | local speed,energy,bounce,gravity,puncheable;
616 | speed = tonumber(meta["speed"]) or 0;
617 | energy = tonumber(meta["energy"]) or 0; -- if positive activates, negative deactivates, 0 does nothing
618 | bounce = tonumber(meta["bounce"]) or 0; -- if nonzero bounces when hit obstacle, 0 gets absorbed
619 | gravity = tonumber(meta["gravity"]) or 0; -- gravity
620 | puncheable = tonumber(meta["puncheable"]) or 0; -- if 1 can be punched by players in protection, if 2 can be punched by anyone
621 |
622 | if energy<0 then
623 | obj:set_properties({textures={"basic_machines_ball.png^[colorize:blue:120"}})
624 | end
625 |
626 | luaent.bounce = bounce;
627 | luaent.energy = energy;
628 | if gravity>0 then
629 | obj:setacceleration({x=0,y=-gravity,z=0});
630 | end
631 | luaent.puncheable = puncheable;
632 | luaent.owner = meta["owner"];
633 | luaent.hurt = math.min(tonumber(meta["hurt"]),basic_machines.ball.maxdamage);
634 |
635 | obj:set_hp( tonumber(meta["hp"]) );
636 |
637 | local x0,y0,z0;
638 | if speed>0 then luaent.speed = speed end
639 |
640 |
641 |
642 | local v = user:get_look_dir();
643 | v.x=v.x*speed;v.y=v.y*speed;v.z=v.z*speed;
644 | obj:setvelocity(v);
645 |
646 |
647 | if tonumber(meta["admin"])==1 then
648 | luaent.lifetime = tonumber(meta["lifetime"]);
649 | end
650 |
651 |
652 | obj:set_properties({textures={meta["texture"]}})
653 |
654 |
655 | end,
656 |
657 |
658 | })
659 |
660 |
661 |
662 | -- minetest.register_craft({
663 | -- output = "basic_machines:ball_spawner",
664 | -- recipe = {
665 | -- {"basic_machines:power_cell"},
666 | -- {"basic_machines:keypad"}
667 | -- }
668 | -- })
--------------------------------------------------------------------------------
/constructor.lua:
--------------------------------------------------------------------------------
1 | -- rnd 2016:
2 |
3 | -- CONSTRUCTOR machine: used to make all other basic_machines
4 |
5 | basic_machines.craft_recipes = {
6 | ["keypad"] = {item = "basic_machines:keypad", description = "Turns on/off lights and activates machines or opens doors", craft = {"default:wood","default:stick"}, tex = "keypad"},
7 | ["light"]={item = "basic_machines:light_on", description = "Light in darkness", craft = {"default:torch 4"}, tex = "light"},
8 | ["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"},
9 |
10 | ["detector"] = {item = "basic_machines:detector", description = "Detect and measure players, objects,blocks,light level", craft = {"default:mese_crystal 4","basic_machines:keypad"}, tex = "detector"},
11 |
12 | ["distributor"]= {item = "basic_machines:distributor", description = "Organize your circuits better", craft = {"default:steel_ingot","default:mese_crystal", "basic_machines:keypad"}, tex = "distributor"},
13 |
14 | ["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"},
15 |
16 | ["recycler"]= {item = "basic_machines:recycler", description = "Recycle old tools", craft = {"default:mese_crystal 8","default:diamondblock"}, tex = "recycler"},
17 |
18 | ["enviroment"] = {item = "basic_machines:enviro", description = "Change gravity and more", craft = {"basic_machines:generator 8","basic_machines:clockgen"}, tex = "enviro"},
19 |
20 | ["ball_spawner"]={item = "basic_machines:ball_spawner", description = "Spawn moving energy balls", craft = {"basic_machines:power_cell","basic_machines:keypad"}, tex = "basic_machines_ball"},
21 |
22 | ["battery"]={item = "basic_machines:battery_0", description = "Power for machines", craft = {"default:bronzeblock 2","default:mese","default:diamond"}, tex = "basic_machine_battery"},
23 |
24 | ["generator"]={item = "basic_machines:generator", description = "Generate power crystals", craft = {"default:diamondblock 5","basic_machines:battery 5","default:goldblock 5"}, tex = "basic_machine_generator"},
25 |
26 | ["autocrafter"] = {item = "basic_machines:autocrafter", description = "Automate crafting", craft = { "default:steel_ingot 5", "default:mese_crystal 2", "default:diamondblock 2"}, tex = "pipeworks_autocrafter"},
27 |
28 | ["grinder"] = {item = "basic_machines:grinder", description = "Makes dusts and grinds materials", craft = {"default:diamond 13","default:mese 4"}, tex = "grinder"},
29 |
30 | ["power_block"] = {item = "basic_machines:power_block 5", description = "Energy cell, contains 11 energy units", craft = {"basic_machines:power_rod"}, tex = "power_block"},
31 |
32 | ["power_cell"] = {item = "basic_machines:power_cell 5", description = "Energy cell, contains 1 energy unit", craft = {"basic_machines:power_block"}, tex = "power_cell"},
33 |
34 | ["coal_lump"] = {item = "default:coal_lump", description = "Coal lump, contains 1 energy unit", craft = {"basic_machines:power_cell 2"}, tex = "default_coal_lump"},
35 |
36 | }
37 |
38 |
39 | basic_machines.craft_recipe_order = { -- order in which nodes appear
40 | "keypad","light","grinder","mover", "battery","generator","detector", "distributor", "clock_generator","recycler","autocrafter","ball_spawner", "enviroment", "power_block", "power_cell", "coal_lump",
41 | }
42 |
43 |
44 | local constructor_process = function(pos)
45 |
46 | local meta = minetest.get_meta(pos);
47 | local craft = basic_machines.craft_recipes[meta:get_string("craft")];
48 | if not craft then return end
49 | local item = craft.item;
50 | local craftlist = craft.craft;
51 |
52 | local inv = meta:get_inventory();
53 | for _,v in pairs(craftlist) do
54 | if not inv:contains_item("main", ItemStack(v)) then
55 | meta:set_string("infotext", "#CRAFTING: you need " .. v .. " to craft " .. craft.item)
56 | return
57 | end
58 | end
59 |
60 | for _,v in pairs(craftlist) do
61 | inv:remove_item("main", ItemStack(v));
62 | end
63 | inv:add_item("main", ItemStack(item));
64 |
65 | end
66 |
67 | local constructor_update_meta = function(pos)
68 | local meta = minetest.get_meta(pos);
69 | local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
70 | local craft = meta:get_string("craft");
71 |
72 | local description = basic_machines.craft_recipes[craft];
73 | local tex;
74 |
75 | if description then
76 | tex = description.tex;
77 | local i = 0;
78 | local itex;
79 |
80 | local inv = meta:get_inventory(); -- set up craft list
81 | for _,v in pairs(description.craft) do
82 | i=i+1;
83 | inv:set_stack("recipe", i, ItemStack(v))
84 | end
85 |
86 | for j = i+1,6 do
87 | inv:set_stack("recipe", j, ItemStack(""))
88 | end
89 |
90 | description = description.description
91 |
92 | else
93 | description = ""
94 | tex = ""
95 | end
96 |
97 |
98 | local textlist = " ";
99 |
100 | local selected = meta:get_int("selected") or 1;
101 | for _,v in ipairs(basic_machines.craft_recipe_order) do
102 | textlist = textlist .. v .. ", ";
103 |
104 | end
105 |
106 | local form =
107 | "size[8,10]"..
108 | "textlist[0,0;3,1.5;craft;" .. textlist .. ";" .. selected .."]"..
109 | "button[3.5,1;1.25,0.75;CRAFT;CRAFT]"..
110 | "image[3.65,0;1,1;".. tex .. ".png]"..
111 | "label[0,1.85;".. description .. "]"..
112 | "list[context;recipe;5,0;3,2;]"..
113 | "label[0,2.3;Put crafting materials here]"..
114 | "list[context;main;0,2.7;8,3;]"..
115 | --"list[context;dst;5,0;3,2;]"..
116 | "label[0,5.5;player inventory]"..
117 | "list[current_player;main;0,6;8,4;]"..
118 | "listring[context;main]"..
119 | "listring[current_player;main]";
120 | meta:set_string("formspec", form);
121 | end
122 |
123 |
124 | minetest.register_node("basic_machines:constructor", {
125 | description = "Constructor: used to make machines",
126 | tiles = {"constructor.png"},
127 | groups = {cracky=3},
128 | sounds = default.node_sound_wood_defaults(),
129 | after_place_node = function(pos, placer)
130 | local meta = minetest.get_meta(pos);
131 | meta:set_string("infotext", "Constructor: To operate it insert materials, select item to make and click craft button.")
132 | meta:set_string("owner", placer:get_player_name());
133 | meta:set_string("craft","keypad")
134 | meta:set_int("selected",1);
135 | local inv = meta:get_inventory();inv:set_size("main", 24);--inv:set_size("dst",6);
136 | inv:set_size("recipe",8);
137 | end,
138 |
139 | on_rightclick = function(pos, node, player, itemstack, pointed_thing)
140 | local meta = minetest.get_meta(pos);
141 | local privs = minetest.get_player_privs(player:get_player_name());
142 | if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
143 | constructor_update_meta(pos);
144 | end,
145 |
146 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
147 | if listname == "recipe" then return 0 end
148 | local meta = minetest.get_meta(pos);
149 | local privs = minetest.get_player_privs(player:get_player_name());
150 | if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
151 | return stack:get_count();
152 | end,
153 |
154 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
155 | if listname == "recipe" then return 0 end
156 | local privs = minetest.get_player_privs(player:get_player_name());
157 | if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return 0 end
158 | return stack:get_count();
159 | end,
160 |
161 | on_metadata_inventory_put = function(pos, listname, index, stack, player)
162 | if listname == "recipe" then return 0 end
163 | local privs = minetest.get_player_privs(player:get_player_name());
164 | if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return 0 end
165 | return stack:get_count();
166 | end,
167 |
168 | allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
169 | return 0;
170 | end,
171 |
172 | effector = {
173 | action_on = function (pos, node,ttl)
174 | if type(ttl)~="number" then ttl = 1 end
175 | if ttl<0 then return end -- machines_TTL prevents infinite recursion
176 | constructor_process(pos);
177 | end
178 | },
179 |
180 | on_receive_fields = function(pos, formname, fields, sender)
181 |
182 | if minetest.is_protected(pos, sender:get_player_name()) then return end
183 | local meta = minetest.get_meta(pos);
184 |
185 | if fields.craft then
186 | if string.sub(fields.craft,1,3)=="CHG" then
187 | local sel = tonumber(string.sub(fields.craft,5)) or 1
188 | meta:set_int("selected",sel);
189 |
190 | local i = 0;
191 | for _,v in ipairs(basic_machines.craft_recipe_order) do
192 | i=i+1;
193 | if i == sel then meta:set_string("craft",v); break; end
194 | end
195 | else
196 | return
197 | end
198 | end
199 |
200 | if fields.CRAFT then
201 | constructor_process(pos);
202 | end
203 |
204 | constructor_update_meta(pos);
205 | end,
206 |
207 | can_dig = function(pos)
208 | local meta = minetest.get_meta(pos);
209 | local inv = meta:get_inventory();
210 |
211 | if not (inv:is_empty("main")) then return false end -- main inv must be empty to be dug
212 |
213 | return true
214 |
215 | end
216 |
217 |
218 | })
219 |
220 |
221 | minetest.register_craft({
222 | output = "basic_machines:constructor",
223 | recipe = {
224 | {"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
225 | {"default:steel_ingot","default:copperblock","default:steel_ingot"},
226 | {"default:steel_ingot","default:steel_ingot","default:steel_ingot"},
227 |
228 | }
229 | })
--------------------------------------------------------------------------------
/depends.txt:
--------------------------------------------------------------------------------
1 | default
2 | protector?
3 | doors?
4 | areas?
5 | boneworld?
6 | moreores?
7 | mesecons?
--------------------------------------------------------------------------------
/enviro.lua:
--------------------------------------------------------------------------------
1 | -- ENVIRO block: change physics and skybox for players
2 | -- note: nonadmin players are limited in changes ( cant change skybox and have limits on other allowed changes)
3 |
4 | -- rnd 2016:
5 |
6 | local enviro = {};
7 | enviro.skyboxes = {
8 | ["default"]={type = "regular", textures = {}},
9 | ["space"]={type="skybox", clouds = false,textures={"basic_machines_stars.png","basic_machines_stars.png","basic_machines_stars.png","basic_machines_stars.png","basic_machines_stars.png","basic_machines_stars.png",}}, -- need textures installed!
10 | ["caves"]={type = "cavebox", textures = {"black.png","black.png","black.png","black.png","black.png","black.png",}},
11 | };
12 |
13 | local space_start = 1100;
14 | local exclusion_height = 6666; -- above all players without privs die and get teleported to spawn
15 |
16 | local ENABLE_SPACE_EFFECTS = false -- enable damage outside protected areas
17 |
18 | local enviro_update_form = function (pos)
19 |
20 | local meta = minetest.get_meta(pos);
21 |
22 | local x0,y0,z0;
23 | x0=meta:get_int("x0");y0=meta:get_int("y0");z0=meta:get_int("z0");
24 |
25 | local skybox = meta:get_string("skybox");
26 | local skylist = "";
27 | local sky_ind,j;
28 | j=1;sky_ind = 3;
29 | for i,_ in pairs(enviro.skyboxes) do
30 | if i == skybox then sky_ind = j end
31 | skylist = skylist .. i .. ",";
32 | j=j+1;
33 | end
34 | local r = meta:get_int("r");
35 | local speed,jump, g, sneak;
36 | speed = meta:get_float("speed");jump = meta:get_float("jump");
37 | g = meta:get_float("g"); sneak = meta:get_int("sneak");
38 | local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z;
39 |
40 | local form =
41 | "size[8,8.5]".. -- width, height
42 | "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.."]"..
43 | "field[3.25,0.5;1,1;r;radius;"..r.."]"..
44 | --speed, jump, gravity,sneak
45 | "field[0.25,1.5;1,1;speed;speed;"..speed.."]"..
46 | "field[1.25,1.5;1,1;jump;jump;"..jump.."]"..
47 | "field[2.25,1.5;1,1;g;gravity;"..g.."]"..
48 | "field[3.25,1.5;1,1;sneak;sneak;"..sneak.."]"..
49 | "label[0.,3.0;Skybox selection]"..
50 | "dropdown[0.,3.35;3,1;skybox;"..skylist..";"..sky_ind.."]"..
51 | "button_exit[3.25,3.25;1,1;OK;OK]"..
52 | "list["..list_name..";fuel;3.25,2.25;1,1;]"..
53 | "list[current_player;main;0,4.5;8,4;]"..
54 | "listring[current_player;main]"..
55 | "listring["..list_name..";fuel]"..
56 | "listring[current_player;main]"
57 | meta:set_string("formspec",form)
58 | end
59 |
60 | -- enviroment changer
61 | minetest.register_node("basic_machines:enviro", {
62 | description = "Changes enviroment for players around target location",
63 | tiles = {"enviro.png"},
64 | drawtype = "allfaces",
65 | paramtype = "light",
66 | param1=1,
67 | groups = {cracky=3},
68 | sounds = default.node_sound_wood_defaults(),
69 | after_place_node = function(pos, placer)
70 | local meta = minetest.env:get_meta(pos)
71 | meta:set_string("infotext", "Right click to set it. Activate by signal.")
72 | meta:set_string("owner", placer:get_player_name()); meta:set_int("public",1);
73 | meta:set_int("x0",0);meta:set_int("y0",0);meta:set_int("z0",0); -- target
74 | meta:set_int("r",5); meta:set_string("skybox","default");
75 | meta:set_float("speed",1);
76 | meta:set_float("jump",1);
77 | meta:set_float("g",1);
78 | meta:set_int("sneak",1);
79 | meta:set_int("admin",0);
80 | local name = placer:get_player_name();
81 | meta:set_string("owner",name);
82 | local privs = minetest.get_player_privs(name);
83 | if privs.privs then meta:set_int("admin",1) end
84 | if privs.machines then meta:set_int("machines",1) end
85 |
86 | local inv = meta:get_inventory();
87 | inv:set_size("fuel",1*1);
88 |
89 | enviro_update_form(pos);
90 | end,
91 |
92 | effector = {
93 | action_on = function (pos, node,ttl)
94 | local meta = minetest.get_meta(pos);
95 | local machines = meta:get_int("machines");
96 | if not machines == 1 then meta:set_string("infotext","Error. You need machines privs.") return end
97 |
98 | local admin = meta:get_int("admin");
99 |
100 | local inv = meta:get_inventory(); local stack = ItemStack("default:diamond 1");
101 |
102 | if inv:contains_item("fuel", stack) then
103 | inv:remove_item("fuel", stack);
104 | else
105 | meta:set_string("infotext","Error. Insert diamond in fuel inventory")
106 | return
107 | end
108 |
109 | local x0,y0,z0,r,skybox,speed,jump,g,sneak;
110 | x0=meta:get_int("x0"); y0=meta:get_int("y0");z0=meta:get_int("z0"); -- target
111 | r= meta:get_int("r",5); skybox=meta:get_string("skybox");
112 | speed=meta:get_float("speed");jump= meta:get_float("jump");
113 | g=meta:get_float("g");sneak=meta:get_int("sneak"); if sneak~=0 then sneak = true else sneak = false end
114 |
115 | local players = minetest.get_connected_players();
116 | for _,player in pairs(players) do
117 | local pos1 = player:get_pos();
118 | local dist = math.sqrt((pos1.x-pos.x)^2 + (pos1.y-pos.y)^2 + (pos1.z-pos.z)^2 );
119 | if dist<=r then
120 |
121 | player:set_physics_override({speed=speed,jump=jump,gravity=g,sneak=sneak})
122 |
123 | if admin == 1 then -- only admin can change skybox
124 | local sky = enviro.skyboxes[skybox];
125 | player:set_sky(sky);
126 | end
127 | end
128 | end
129 |
130 | -- attempt to set acceleration to balls, if any around
131 | local objects = minetest.get_objects_inside_radius(pos, r)
132 |
133 | for _,obj in pairs(objects) do
134 | if obj:get_luaentity() then
135 | local obj_name = obj:get_luaentity().name or ""
136 | if obj_name == "basic_machines:ball" then
137 | obj:setacceleration({x=0,y=-g,z=0});
138 | end
139 | end
140 |
141 | end
142 |
143 |
144 |
145 |
146 | end
147 | },
148 |
149 |
150 | on_receive_fields = function(pos, formname, fields, sender)
151 |
152 | local name = sender:get_player_name();if minetest.is_protected(pos,name) then return end
153 |
154 | if fields.OK then
155 | local privs = minetest.get_player_privs(sender:get_player_name());
156 | local meta = minetest.get_meta(pos);
157 | local x0=0; local y0=0; local z0=0;
158 | --minetest.chat_send_all("form at " .. dump(pos) .. " fields " .. dump(fields))
159 | if fields.x0 then x0 = tonumber(fields.x0) or 0 end
160 | if fields.y0 then y0 = tonumber(fields.y0) or 0 end
161 | if fields.z0 then z0 = tonumber(fields.z0) or 0 end
162 | if not privs.privs and (math.abs(x0)>10 or math.abs(y0)>10 or math.abs(z0) > 10) then return end
163 |
164 | meta:set_int("x0",x0);meta:set_int("y0",y0);meta:set_int("z0",z0);
165 | if privs.privs then -- only admin can set sky
166 | if fields.skybox then meta:set_string("skybox", fields.skybox) end
167 | end
168 | if fields.r then
169 | local r = tonumber(fields.r) or 0;
170 | if r > 10 and not privs.privs then return end
171 | meta:set_int("r", r)
172 | end
173 | if fields.g then
174 | local g = tonumber(fields.g) or 1;
175 | if (g<0.1 or g>40) and not privs.privs then return end
176 | meta:set_float("g", g)
177 | end
178 | if fields.speed then
179 | local speed = tonumber(fields.speed) or 1;
180 | if (speed>1 or speed < 0) and not privs.privs then return end
181 | meta:set_float("speed", speed)
182 | end
183 | if fields.jump then
184 | local jump = tonumber(fields.jump) or 1;
185 | if (jump<0 or jump>2) and not privs.privs then return end
186 | meta:set_float("jump", jump)
187 | end
188 | if fields.sneak then
189 | meta:set_int("sneak", tonumber(fields.sneak) or 0)
190 | end
191 |
192 |
193 | enviro_update_form(pos);
194 | end
195 | end,
196 |
197 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
198 | local meta = minetest.get_meta(pos);
199 | local privs = minetest.get_player_privs(player:get_player_name());
200 | if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
201 | return stack:get_count();
202 | end,
203 |
204 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
205 | local meta = minetest.get_meta(pos);
206 | local privs = minetest.get_player_privs(player:get_player_name());
207 | if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
208 | return stack:get_count();
209 | end,
210 |
211 | can_dig = function(pos, player) -- dont dig if fuel is inside, cause it will be destroyed
212 | local meta = minetest.get_meta(pos);
213 | local inv = meta:get_inventory();
214 | return inv:is_empty("fuel")
215 | end,
216 |
217 | })
218 |
219 |
220 | -- DEFAULT (SPAWN) PHYSICS VALUE/SKYBOX
221 |
222 | local reset_player_physics = function(player)
223 | if player then
224 | player:set_physics_override({speed=1,jump=1,gravity=1}) -- value set for extreme test space spawn
225 | local skybox = enviro.skyboxes["default"]; -- default skybox is "default"
226 | player:set_sky(skybox);
227 | end
228 | end
229 |
230 | -- globally available function
231 | enviro_adjust_physics = function(player) -- adjust players physics/skybox 1 second after various events
232 | minetest.after(1, function()
233 | if player then
234 | local pos = player:get_pos(); if not pos then return end
235 | if pos.y > space_start then -- is player in space or not?
236 | player:set_physics_override({speed=1,jump=0.5,gravity=0.1}) -- value set for extreme test space spawn
237 | local skybox = enviro.skyboxes["space"];
238 | player:set_sky(skybox);
239 | else
240 | player:set_physics_override({speed=1,jump=1,gravity=1}) -- value set for extreme test space spawn
241 | local skybox = enviro.skyboxes["default"];
242 | player:set_sky(skybox);
243 | end
244 | end
245 | end)
246 | end
247 |
248 |
249 | -- restore default values/skybox on respawn of player
250 | minetest.register_on_respawnplayer(reset_player_physics)
251 |
252 | -- when player joins, check where he is and adjust settings
253 | minetest.register_on_joinplayer(enviro_adjust_physics)
254 |
255 |
256 | -- SERVER GLOBAL SPACE CODE: uncomment to enable it
257 |
258 | local round = math.floor;
259 | local protector_position = function(pos)
260 | local r = 20;
261 | local ry = 2*r;
262 | return {x=round(pos.x/r+0.5)*r,y=round(pos.y/ry+0.5)*ry,z=round(pos.z/r+0.5)*r};
263 | end
264 |
265 | local stimer = 0
266 | local enviro_space = {};
267 | local exclusion_zone = {};
268 | local moderator = {};
269 |
270 | minetest.register_globalstep(function(dtime)
271 | stimer = stimer + dtime;
272 | if stimer >= 5 then
273 | stimer = 0;
274 | local players = minetest.get_connected_players();
275 | for _,player in pairs(players) do
276 | local name = player:get_player_name();
277 | local pos = player:get_pos();
278 | local inspace=0;
279 | if pos.y>space_start then
280 | inspace = 1
281 | if pos.y > exclusion_height then
282 | local exclude = exclusion_zone[name];
283 | if exclude == nil then
284 | exclusion_zone[name] = not minetest.get_player_privs(name).include;
285 | exclude = exclusion_zone[name]
286 | end
287 | if exclude then
288 | minetest.chat_send_all("exclusion zone alert: " .. name .. " " .. pos.x .. " " .. pos.y .. " " .. pos.z )
289 | minetest.log("exclusion zone alert: " .. name .. " " .. pos.x .. " " .. pos.y .. " " .. pos.z )
290 | player:set_pos({x=0,y=-100,z=0})
291 | end
292 | end
293 | end
294 | local inspace0=enviro_space[name];
295 | if inspace~=inspace0 then -- only adjust player enviroment ONLY if change occured ( earth->space or space->earth !)
296 | enviro_space[name] = inspace;
297 | enviro_adjust_physics(player);
298 | end
299 |
300 | if ENABLE_SPACE_EFFECTS and inspace==1 then -- special space code
301 |
302 |
303 | if pos.y<1500 and pos.y>1120 then
304 | local hp = player:get_hp();
305 |
306 | if hp>0 then
307 | minetest.chat_send_player(name,"WARNING: you entered DEADLY RADIATION ZONE.");
308 | local privs = minetest.get_player_privs(name)
309 | if not privs.kick then player:set_hp(hp-15) end
310 | end
311 | return
312 | else
313 |
314 | local ppos = protector_position(pos);
315 | local populated = (minetest.get_node(ppos).name=="basic_protect:protector");
316 | if populated then
317 | if minetest.get_meta(ppos):get_int("space") == 1 then populated = false end
318 | end
319 |
320 | if not populated then -- do damage if player found not close to protectors
321 | local hp = player:get_hp();
322 | local privs = minetest.get_player_privs(name);
323 | if hp>0 and not privs.kick then
324 | player:set_hp(hp-10); -- dead in 20/10 = 2 events
325 | minetest.chat_send_player(name,"WARNING: in space you must stay close to spawn or protected areas");
326 | end
327 | end
328 | end
329 |
330 | end
331 | end
332 | end
333 | end)
334 |
335 | -- END OF SPACE CODE
336 |
337 |
338 | -- AIR EXPERIMENT
339 | -- minetest.register_node("basic_machines:air", {
340 | -- description = "enables breathing in space",
341 | -- drawtype = "liquid",
342 | -- tiles = {"default_water_source_animated.png"},
343 |
344 | -- drawtype = "glasslike",
345 | -- paramtype = "light",
346 | -- sunlight_propagates = true, -- Sunlight shines through
347 | -- walkable = false, -- Would make the player collide with the air node
348 | -- pointable = false, -- You can't select the node
349 | -- diggable = false, -- You can't dig the node
350 | -- buildable_to = true,
351 | -- drop = "",
352 | -- groups = {not_in_creative_inventory=1},
353 | -- after_place_node = function(pos, placer, itemstack, pointed_thing)
354 | -- local r = 3;
355 | -- for i = -r,r do
356 | -- for j = -r,r do
357 | -- for k = -r,r do
358 | -- local p = {x=pos.x+i,y=pos.y+j,z=pos.z+k};
359 | -- if minetest.get_node(p).name == "air" then
360 | -- minetest.set_node(p,{name = "basic_machines:air"})
361 | -- end
362 | -- end
363 | -- end
364 | -- end
365 | -- end
366 |
367 | -- })
368 |
369 | -- minetest.register_abm({
370 | -- nodenames = {"basic_machines:air"},
371 | -- neighbors = {"air"},
372 | -- interval = 10,
373 | -- chance = 1,
374 | -- action = function(pos, node, active_object_count, active_object_count_wider)
375 | -- minetest.set_node(pos,{name = "air"})
376 | -- end
377 | -- });
378 |
379 |
380 | minetest.register_on_punchplayer( -- bring gravity closer to normal with each punch
381 | function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
382 |
383 | if player:get_physics_override() == nil then return end
384 | local pos = player:get_pos(); if pos.y>= space_start then return end
385 |
386 | local gravity = player:get_physics_override().gravity;
387 | if gravity<1 then
388 | gravity = 1;
389 | player:set_physics_override({gravity=gravity})
390 | end
391 | end
392 |
393 | )
394 |
395 | minetest.register_privilege("include", {
396 | description = "allow player to move in exclusion zone",
397 | })
398 |
399 |
400 | -- RECIPE: extremely expensive
401 |
402 | -- minetest.register_craft({
403 | -- output = "basic_machines:enviro",
404 | -- recipe = {
405 | -- {"basic_machines:generator", "basic_machines:clockgen","basic_machines:generator"},
406 | -- {"basic_machines:generator", "basic_machines:generator","basic_machines:generator"},
407 | -- {"basic_machines:generator", "basic_machines:generator", "basic_machines:generator"}
408 | -- }
409 | -- })
--------------------------------------------------------------------------------
/grinder.lua:
--------------------------------------------------------------------------------
1 | -- There is a certain fuel cost to operate
2 |
3 | -- recipe list: [in] ={fuel cost, out, quantity of material required for processing}
4 | basic_machines.grinder_recipes = {
5 | ["default:stone"] = {2,"default:sand",1},
6 | ["default:desert_stone"] = {2,"default:desert_sand 4",1},
7 | ["default:cobble"] = {1,"default:gravel",1},
8 | ["default:gravel"] = {0.5,"default:dirt",1},
9 | ["default:dirt"] = {0.5,"default:clay_lump 4",1},
10 | ["default:obsidian_shard"] = {199,"default:lava_source",1},
11 | ["gloopblocks:basalt"] = {1, "default:cobble",1}, -- enable coble farms with gloopblocks mod
12 | ["default:ice"] = {1, "default:snow 4",1},
13 | ["darkage:silt_lump"]={1,"darkage:chalk_powder",1},
14 | };
15 |
16 |
17 | local grinder_process = function(pos)
18 |
19 | local node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
20 | local meta = minetest.get_meta(pos);local inv = meta:get_inventory();
21 |
22 | -- activation limiter: 1/s
23 | local t0 = meta:get_int("t")
24 | local t1 = minetest.get_gametime();
25 |
26 | if t1-t0>0 then
27 | meta:set_int("t",t1)
28 | else
29 | return
30 | end
31 |
32 | -- PROCESS: check out inserted items
33 | local stack = inv:get_stack("src",1);
34 | if stack:is_empty() then return end; -- nothing to do
35 |
36 | local src_item = stack:to_string();
37 | 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
38 |
39 | local def = basic_machines.grinder_recipes[src_item];
40 | if not def then
41 | meta:set_string("infotext", "please insert valid materials"); return
42 | end-- unknown node
43 |
44 | local steps = math.floor(stack:get_count() / def[3]) -- how many steps to process inserted stack
45 |
46 | if steps<1 then
47 | meta:set_string("infotext", "Recipe requires at least " .. def[3] .. " " .. src_item);
48 | return
49 | end
50 |
51 | local upgrade = meta:get_int("upgrade")+1
52 | if steps>upgrade then steps = upgrade end
53 |
54 | -- FUEL CHECK
55 | local fuel = meta:get_float("fuel");
56 | local fuel_req = def[1]*steps;
57 |
58 | if fuel-fuel_req <0 then -- we need new fuel, check chest below
59 | local fuellist = inv:get_list("fuel")
60 | if not fuellist then return end
61 |
62 | local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
63 |
64 | local supply=0;
65 | if fueladd.time == 0 then -- no fuel inserted, try look for outlet
66 | -- No valid fuel in fuel list
67 | supply = basic_machines.check_power({x=pos.x,y=pos.y-1,z=pos.z} , fuel_req) or 0; -- tweaked so 1 coal = 1 energy
68 | if supply>0 then
69 | fueladd.time = supply -- same as 10 coal
70 | else
71 | meta:set_string("infotext", "Please insert fuel");
72 | return;
73 | end
74 | else
75 | if supply==0 then -- Take fuel from fuel list if no supply available
76 | inv:set_stack("fuel",1,afterfuel.items[1])
77 | fueladd.time=fueladd.time*0.1/4 -- thats 1 for coal
78 | end
79 | end
80 | if fueladd.time>0 then
81 | fuel=fuel + fueladd.time
82 | meta:set_float("fuel",fuel);
83 | meta:set_string("infotext", "added fuel furnace burn time " .. fueladd.time .. ", fuel status " .. fuel);
84 | end
85 | if fuel-fuel_req<0 then
86 | meta:set_string("infotext", "need at least " .. fuel_req-fuel .. " fuel to complete operation "); return
87 | end
88 |
89 | end
90 |
91 | -- process items
92 | local addstack = ItemStack(def[2]);
93 | if steps>1 then -- multiply stack
94 | local count = addstack:get_count();
95 | addstack:set_count(count*steps)
96 | end
97 | if inv:room_for_item("dst", addstack) then
98 | inv:add_item("dst",addstack);
99 | else return
100 | end
101 |
102 | --take 'steps' items from src inventory for each activation
103 | stack=stack:take_item(steps); inv:remove_item("src", stack)
104 |
105 | minetest.sound_play("grinder", {pos=pos,gain=0.5,max_hear_distance = 16,})
106 |
107 | fuel = fuel-fuel_req; -- burn fuel
108 | meta:set_float("fuel",fuel);
109 | meta:set_string("infotext", "fuel " .. fuel);
110 |
111 | end
112 |
113 |
114 | local grinder_update_meta = function(pos)
115 | local meta = minetest.get_meta(pos);
116 | local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
117 | local form =
118 | "size[8,8]".. -- width, height
119 | --"size[6,10]".. -- width, height
120 | "label[0,0;IN] label[1,0;OUT] label[0,2;FUEL] label[5,0;UPGRADE]"..
121 | "list["..list_name..";src;0.,0.5;1,1;]"..
122 | "list["..list_name..";dst;1.,0.5;3,3;]"..
123 | "list["..list_name..";fuel;0.,2.5;1,1;]"..
124 | "list["..list_name..";upgrade;5.,0.5;2,1;]"..
125 | "list[current_player;main;0,4;8,4;]"..
126 | "button[7,0.5;1,1;OK;OK]"..
127 | "button[7,1.5;1,1;help;help]"..
128 | "listring["..list_name..";dst]"..
129 | "listring[current_player;main]"..
130 | "listring["..list_name..";src]"..
131 | "listring[current_player;main]"..
132 | "listring["..list_name..";fuel]"..
133 | "listring[current_player;main]"
134 | meta:set_string("formspec", form)
135 | end
136 |
137 | local upgrade_grinder = function(meta)
138 | local inv = meta:get_inventory();
139 | local stack = inv:get_stack("upgrade", 1); local item = stack:get_name(); local count = stack:get_count();
140 | if item ~= "basic_machines:grinder" then count = 0 end; meta:set_int("upgrade", count)
141 | end
142 |
143 | minetest.register_node("basic_machines:grinder", {
144 | description = "Grinder",
145 | tiles = {"grinder.png"},
146 | groups = {cracky=3, mesecon_effector_on = 1},
147 | sounds = default.node_sound_wood_defaults(),
148 | after_place_node = function(pos, placer)
149 | local meta = minetest.get_meta(pos);
150 | meta:set_string("infotext", "Grinder: To operate it insert fuel, then insert item to grind or use keypad to activate it.")
151 | meta:set_string("owner", placer:get_player_name());
152 | meta:set_float("fuel",0);
153 | local inv = meta:get_inventory();inv:set_size("src", 1);inv:set_size("dst",9);inv:set_size("fuel",1);
154 | inv:set_size("upgrade",1);
155 | end,
156 |
157 | on_rightclick = function(pos, node, player, itemstack, pointed_thing)
158 | local meta = minetest.get_meta(pos);
159 | local privs = minetest.get_player_privs(player:get_player_name());
160 | if minetest.is_protected(pos, player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
161 | grinder_update_meta(pos);
162 | end,
163 |
164 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
165 | local meta = minetest.get_meta(pos);
166 | local privs = minetest.get_player_privs(player:get_player_name());
167 | if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
168 | return stack:get_count();
169 | end,
170 |
171 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
172 | local meta = minetest.get_meta(pos);
173 | local privs = minetest.get_player_privs(player:get_player_name());
174 | if meta:get_string("owner")~=player:get_player_name() and not privs.privs then return 0 end
175 | return stack:get_count();
176 | end,
177 |
178 | on_metadata_inventory_take = function(pos, listname, index, stack, player)
179 | if listname == "upgrade" then upgrade_grinder(minetest.get_meta(pos)) end
180 | end,
181 |
182 | on_metadata_inventory_put = function(pos, listname, index, stack, player)
183 | if listname =="dst" then return end
184 | if listname == "upgrade" then upgrade_grinder(minetest.get_meta(pos)) end
185 | grinder_process(pos);
186 | end,
187 |
188 | allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
189 | return 0;
190 | end,
191 |
192 | effector = {
193 | action_on = function (pos, node,ttl)
194 | if type(ttl)~="number" then ttl = 1 end
195 | if ttl<0 then return end -- machines_TTL prevents infinite recursion
196 | grinder_process(pos);
197 | end
198 | },
199 |
200 | on_receive_fields = function(pos, formname, fields, sender)
201 | if fields.quit then return end
202 | local meta = minetest.get_meta(pos);
203 |
204 | if fields.help then
205 | --recipe list: [in] ={fuel cost, out, quantity of material required for processing}
206 | --basic_machines.grinder_recipes
207 | local text = "HELP & RECIPES\n\nTo upgrade grinder put grinders in upgrade slot. Each upgrade adds ability to process additional materials.\n\n";
208 | for key,v in pairs(basic_machines.grinder_recipes) do
209 | text = text .. "INPUT ".. key .. " " .. v[3] .. " OUTPUT " .. v[2] .. "\n"
210 | end
211 |
212 | local form = "size [6,7] textarea[0,0;6.5,8.5;grinderhelp;GRINDER RECIPES;".. text.."]"
213 | minetest.show_formspec(sender:get_player_name(), "grinderhelp", form)
214 |
215 | end
216 | grinder_update_meta(pos);
217 | end,
218 |
219 | can_dig = function(pos)
220 | local meta = minetest.get_meta(pos);
221 | local inv = meta:get_inventory();
222 |
223 | if not (inv:is_empty("fuel")) or not (inv:is_empty("src")) or not (inv:is_empty("dst")) then return false end -- all inv must be empty to be dug
224 |
225 | return true
226 |
227 | end
228 |
229 | })
230 |
231 |
232 | -- minetest.register_craft({
233 | -- output = "basic_machines:grinder",
234 | -- recipe = {
235 | -- {"default:diamond","default:mese","default:diamond"},
236 | -- {"default:mese","default:diamondblock","default:mese"},
237 | -- {"default:diamond","default:mese","default:diamond"},
238 |
239 | -- }
240 | -- })
241 |
242 |
243 |
244 |
245 | -- REGISTER DUSTS
246 | -- dust_00 (mix)-> extractor (smelt) -> dust_33 (smelt) -> dust_66 (smelt) -> ingot
247 |
248 | local function register_dust(name,input_node_name,ingot,grindcost,cooktime,R,G,B)
249 |
250 | if not R then R = "FF" end
251 | if not G then G = "FF" end
252 | if not B then B = "FF" end
253 |
254 | local purity_table = {"00","33","66"};
255 |
256 | for i = 1,#purity_table do
257 | local purity = purity_table[i];
258 | minetest.register_craftitem("basic_machines:"..name.."_dust_".. purity, {
259 | description = name.. " dust purity " .. purity .. "%" .. (purity=="00" and " (combine with chemicals to create " .. name .. " extractor )" or " (smelt to increase purity)") ,
260 | inventory_image = "basic_machines_dust.png^[colorize:#"..R..G..B..":180",
261 | })
262 | end
263 |
264 | basic_machines.grinder_recipes[input_node_name] = {grindcost,"basic_machines:"..name.."_dust_".. purity_table[1].." 2",1} -- register grinder recipe
265 |
266 | if ingot~="" then
267 |
268 | for i = 2,#purity_table-1 do -- all dusts but first one are cookable
269 | minetest.register_craft({
270 | type = "cooking",
271 | recipe = "basic_machines:"..name.."_dust_".. purity_table[i],
272 | output = "basic_machines:"..name.."_dust_".. purity_table[i+1],
273 | cooktime = cooktime
274 | })
275 | end
276 |
277 | minetest.register_craft({
278 | type = "cooking",
279 | recipe = "basic_machines:"..name.."_dust_".. purity_table[#purity_table],
280 | groups = {not_in_creative_inventory=1},
281 | output = ingot,
282 | cooktime = cooktime
283 | })
284 |
285 | end
286 | end
287 |
288 |
289 | register_dust("iron","default:iron_lump","default:steel_ingot",4,8,"99","99","99")
290 | register_dust("copper","default:copper_lump","default:copper_ingot",4,8,"C8","80","0D") --c8800d
291 | register_dust("tin","default:tin_lump","default:tin_ingot",4,8,"9F","9F","9F")
292 | register_dust("gold","default:gold_lump","default:gold_ingot",6,25,"FF","FF","00")
293 |
294 | -- grinding ingots gives dust too
295 | basic_machines.grinder_recipes["default:steel_ingot"] = {4,"basic_machines:iron_dust_00 2",1};
296 | basic_machines.grinder_recipes["default:copper_ingot"] = {4,"basic_machines:copper_dust_00 2",1};
297 | basic_machines.grinder_recipes["default:gold_ingot"] = {6,"basic_machines:gold_dust_00 2",1};
298 | basic_machines.grinder_recipes["default:tin_ingot"] = {4,"basic_machines:tin_dust_00 2",1};
299 |
300 | -- are moreores (tin, silver, mithril) present?
301 |
302 | local table = minetest.registered_items["moreores:tin_lump"]; if table then
303 | --register_dust("tin","moreores:tin_lump","moreores:tin_ingot",4,8,"FF","FF","FF")
304 | register_dust("silver","moreores:silver_lump","moreores:silver_ingot",5,15,"BB","BB","BB")
305 | register_dust("mithril","moreores:mithril_lump","moreores:mithril_ingot",16,750,"00","00","FF")
306 |
307 | basic_machines.grinder_recipes["moreores:tin_ingot"] = {4,"basic_machines:tin_dust_00 2",1};
308 | basic_machines.grinder_recipes["moreores:silver_ingot"] = {5,"basic_machines:silver_dust_33 2",1}; -- silver doesnt need extractor yet
309 | basic_machines.grinder_recipes["moreores:mithril_ingot"] = {16,"basic_machines:mithril_dust_00 2",1};
310 | end
311 |
312 |
313 | register_dust("mese","default:mese_crystal","default:mese_crystal",8,250,"CC","CC","00")
314 | register_dust("diamond","default:diamond","default:diamond",16,500,"00","EE","FF") -- 0.3hr cooking time to make diamond!
315 |
316 | -- darkage recipes and ice
317 | minetest.register_craft({
318 | type = "cooking",
319 | recipe = "default:ice",
320 | output = "default:water_flowing",
321 | cooktime = 4
322 | })
323 |
324 | minetest.register_craft({
325 | type = "cooking",
326 | recipe = "default:stone",
327 | output = "darkage:basalt",
328 | cooktime = 60
329 | })
330 |
331 | minetest.register_craft({
332 | type = "cooking",
333 | recipe = "darkage:slate",
334 | output = "darkage:schist",
335 | cooktime = 20
336 | })
337 |
338 | -- dark age recipe: cook schist to get gneiss
339 |
340 | minetest.register_craft({
341 | type = "cooking",
342 | recipe = "darkage:gneiss",
343 | output = "darkage:marble",
344 | cooktime = 20
345 | })
346 |
347 |
348 | minetest.register_craft({
349 | output = "darkage:serpentine",
350 | recipe = {
351 | {"darkage:marble","default:cactus"}
352 | }
353 | })
354 |
355 | minetest.register_craft({
356 | output = "darkage:mud",
357 | recipe = {
358 | {"default:dirt","default:water_flowing"}
359 | }
360 | })
361 |
362 |
363 | -- EXTRACTORS, their recipes and smelting recipes
364 |
365 | local function register_extractor(name, R,G,B)
366 |
367 | if not R then R = "FF" end
368 | if not G then G = "FF" end
369 | if not B then B = "FF" end
370 |
371 | minetest.register_craftitem("basic_machines:"..name.."_extractor", {
372 | description = "smelt to get " .. name ,
373 | inventory_image = "ore_extractor.png^[colorize:#"..R..G..B..":180",
374 | })
375 |
376 |
377 | end
378 |
379 | register_extractor("iron","99","99","99")
380 | register_extractor("copper","C8","80","0D")
381 | register_extractor("tin","C8","9F","9F")
382 | register_extractor("gold","FF","FF","00")
383 | register_extractor("mese","CC","CC","00")
384 | register_extractor("diamond","00","EE","FF")
385 | register_extractor("mithril","00","00","FF")
386 |
387 | minetest.register_craft({
388 | output = 'basic_machines:iron_extractor',
389 | recipe = {
390 | {'default:leaves','default:leaves','basic_machines:iron_dust_00'},
391 | }
392 | })
393 |
394 | -- extractor smelts to dust_33
395 |
396 | minetest.register_craft({
397 | type = "cooking",
398 | recipe = "basic_machines:iron_extractor",
399 | output = "basic_machines:iron_dust_33",
400 | cooktime = 10
401 | })
402 |
403 | minetest.register_craft({
404 | output = 'basic_machines:copper_extractor',
405 | recipe = {
406 | {'default:papyrus','default:papyrus','basic_machines:copper_dust_00'},
407 | }
408 | })
409 |
410 | minetest.register_craft({
411 | type = "cooking",
412 | recipe = "basic_machines:copper_extractor",
413 | output = "basic_machines:copper_dust_33",
414 | cooktime = 10
415 | })
416 |
417 | minetest.register_craft({
418 | output = 'basic_machines:tin_extractor',
419 | recipe = {
420 | {'farming:cocoa_beans','farming:cocoa_beans','basic_machines:tin_dust_00'},
421 | }
422 | })
423 |
424 | minetest.register_craft({
425 | type = "cooking",
426 | recipe = "basic_machines:tin_extractor",
427 | output = "basic_machines:tin_dust_33",
428 | cooktime = 10
429 | })
430 |
431 | minetest.register_craft({
432 | output = 'basic_machines:gold_extractor',
433 | recipe = {
434 | {'basic_machines:tin_extractor','basic_machines:copper_extractor','basic_machines:gold_dust_00'},
435 | }
436 | })
437 |
438 | minetest.register_craft({
439 | type = "cooking",
440 | recipe = "basic_machines:gold_extractor",
441 | output = "basic_machines:gold_dust_33",
442 | cooktime = 10
443 | })
444 |
445 | minetest.register_craft({
446 | output = 'basic_machines:mese_extractor',
447 | recipe = {
448 | {'farming:rhubarb','farming:rhubarb', 'basic_machines:mese_dust_00'},
449 | }
450 | })
451 |
452 | minetest.register_craft({
453 | type = "cooking",
454 | recipe = "basic_machines:mese_extractor",
455 | output = "basic_machines:mese_dust_33",
456 | cooktime = 10
457 | })
458 |
459 | minetest.register_craft({
460 | output = 'basic_machines:diamond_extractor',
461 | recipe = {
462 | {'farming:wheat','farming:cotton', 'basic_machines:diamond_dust_00'},
463 | }
464 | })
465 |
466 | minetest.register_craft({
467 | type = "cooking",
468 | recipe = "basic_machines:diamond_extractor",
469 | output = "basic_machines:diamond_dust_33",
470 | cooktime = 10
471 | })
472 |
473 | minetest.register_craft({
474 | output = 'basic_machines:mithril_extractor',
475 | recipe = {
476 | {'flowers:geranium','flowers:geranium', 'basic_machines:mithril_dust_00'}, -- blue flowers
477 | }
478 | })
479 |
480 |
481 | minetest.register_craft({
482 | type = "cooking",
483 | recipe = "basic_machines:mithril_extractor",
484 | output = "basic_machines:mithril_dust_33",
485 | cooktime = 10
486 | })
--------------------------------------------------------------------------------
/init.lua:
--------------------------------------------------------------------------------
1 | -- BASIC_MACHINES: lightweight automation mod for minetest
2 | -- minetest 0.4.14
3 | -- (c) 2015-2016 rnd
4 |
5 | -- This program is free software: you can redistribute it and/or modify
6 | -- it under the terms of the GNU General Public License as published by
7 | -- the Free Software Foundation, either version 3 of the License, or
8 | -- (at your option) any later version.
9 |
10 | -- This program is distributed in the hope that it will be useful,
11 | -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | -- GNU General Public License for more details.
14 |
15 | -- You should have received a copy of the GNU General Public License
16 | -- along with this program. If not, see .
17 |
18 |
19 | basic_machines = {};
20 |
21 |
22 |
23 | dofile(minetest.get_modpath("basic_machines").."/mark.lua") -- used for markings, borrowed and adapted from worldedit mod
24 | dofile(minetest.get_modpath("basic_machines").."/mover.lua") -- mover, detector, keypad, distributor
25 | dofile(minetest.get_modpath("basic_machines").."/technic_power.lua") -- technic power for mover
26 | dofile(minetest.get_modpath("basic_machines").."/recycler.lua") -- recycle old used tools
27 | dofile(minetest.get_modpath("basic_machines").."/grinder.lua") -- grind materials into dusts
28 | dofile(minetest.get_modpath("basic_machines").."/autocrafter.lua") -- borrowed and adapted from pipeworks mod
29 | dofile(minetest.get_modpath("basic_machines").."/constructor.lua") -- enable crafting of all machines
30 |
31 | dofile(minetest.get_modpath("basic_machines").."/protect.lua") -- enable interaction with players, adds local on protect/chat event handling
32 |
33 | -- MESECON functionality
34 | if mesecon then -- DO NOT REMOVE THIS CHECK or it wont work with mesecons
35 | dofile(minetest.get_modpath("basic_machines").."/mesecon_adapter.lua")
36 | basic_machines.craft_recipes["mesecon_adapter"] = {item = "basic_machines:mesecon_adapter", description = "interface between machines and mesecons", craft = {"default:mese_crystal_fragment"}, tex = "jeija_luacontroller_top"}
37 | basic_machines.craft_recipe_order[1+#basic_machines.craft_recipe_order] = "mesecon_adapter"
38 | end
39 | -- OPTIONAL ADDITIONAL STUFF ( comment to disable )
40 |
41 | dofile(minetest.get_modpath("basic_machines").."/ball.lua") -- interactive flying ball, can activate blocks or be used as a weapon
42 | 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
43 | 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
44 | minetest.after(0, function()
45 | dofile(minetest.get_modpath("basic_machines").."/mesecon_lights.lua") -- adds ability for other light blocks to toggle light
46 | end)
47 |
48 |
49 | -- MACHINE PRIVILEGE
50 | minetest.register_privilege("machines", {
51 | description = "Player is expert basic_machine user: his machines work while not present on server, can spawn more than 2 balls at once",
52 | })
53 |
54 | -- machines fuel related recipes
55 | -- CHARCOAL
56 |
57 | minetest.register_craftitem("basic_machines:charcoal", {
58 | description = "Wood charcoal",
59 | inventory_image = "charcoal.png",
60 | })
61 |
62 |
63 | minetest.register_craft({
64 | type = 'cooking',
65 | recipe = "default:tree",
66 | cooktime = 30,
67 | output = "basic_machines:charcoal",
68 | })
69 |
70 | minetest.register_craft({
71 | output = "default:coal_lump",
72 | recipe = {
73 | {"basic_machines:charcoal"},
74 | {"basic_machines:charcoal"},
75 | }
76 | })
77 |
78 | minetest.register_craft({
79 | type = "fuel",
80 | recipe = "basic_machines:charcoal",
81 | -- note: to make it you need to use 1 tree block for fuel + 1 tree block, thats 2, caloric value 2*30=60
82 | burntime = 40, -- coal lump has 40, tree block 30, coal block 370 (9*40=360!)
83 | })
84 |
85 | -- add since minetest doesnt have moreores tin ingot recipe
86 | minetest.register_craft({
87 | output = "default:tin_ingot",
88 | recipe = {
89 | {"moreores:tin_ingot"},
90 | }
91 | })
92 |
93 | -- COMPATIBILITY
94 | minetest.register_alias("basic_machines:battery", "basic_machines:battery_0")
95 |
96 |
97 | print("[MOD] basic_machines " .. basic_machines.version .. " loaded.")
--------------------------------------------------------------------------------
/mark.lua:
--------------------------------------------------------------------------------
1 | -- rnd: code borrowed from machines, mark.lua
2 |
3 | -- need for marking
4 | machines = {};
5 |
6 | machines.pos1 = {};machines.pos11 = {}; machines.pos2 = {};
7 | machines.marker1 = {}
8 | machines.marker11 = {}
9 | machines.marker2 = {}
10 | machines.marker_region = {}
11 |
12 |
13 | --marks machines region position 1
14 | machines.mark_pos1 = function(name)
15 | local pos1, pos2 = machines.pos1[name], machines.pos2[name]
16 |
17 | if pos1 ~= nil then
18 | --make area stay loaded
19 | local manip = minetest.get_voxel_manip()
20 | manip:read_from_map(pos1, pos1)
21 | end
22 |
23 | if not machines[name] then machines[name]={} end
24 | machines[name].timer = 10;
25 | if machines.marker1[name] ~= nil then --marker already exists
26 | machines.marker1[name]:remove() --remove marker
27 | machines.marker1[name] = nil
28 | end
29 | if pos1 ~= nil then
30 | --add marker
31 | machines.marker1[name] = minetest.add_entity(pos1, "machines:pos1")
32 | if machines.marker1[name] ~= nil then
33 | machines.marker1[name]:get_luaentity().name = name
34 | end
35 | end
36 | end
37 |
38 | --marks machines region position 1
39 | machines.mark_pos11 = function(name)
40 | local pos11 = machines.pos11[name];
41 |
42 | if pos11 ~= nil then
43 | --make area stay loaded
44 | local manip = minetest.get_voxel_manip()
45 | manip:read_from_map(pos11, pos11)
46 | end
47 |
48 | if not machines[name] then machines[name]={} end
49 | machines[name].timer = 10;
50 | if machines.marker11[name] ~= nil then --marker already exists
51 | machines.marker11[name]:remove() --remove marker
52 | machines.marker11[name] = nil
53 | end
54 | if pos11 ~= nil then
55 | --add marker
56 | machines.marker11[name] = minetest.add_entity(pos11, "machines:pos11")
57 | if machines.marker11[name] ~= nil then
58 | machines.marker11[name]:get_luaentity().name = name
59 | end
60 | end
61 | end
62 |
63 | --marks machines region position 2
64 | machines.mark_pos2 = function(name)
65 | local pos1, pos2 = machines.pos1[name], machines.pos2[name]
66 |
67 | if pos2 ~= nil then
68 | --make area stay loaded
69 | local manip = minetest.get_voxel_manip()
70 | manip:read_from_map(pos2, pos2)
71 | end
72 |
73 | if not machines[name] then machines[name]={} end
74 | machines[name].timer = 10;
75 | if machines.marker2[name] ~= nil then --marker already exists
76 | machines.marker2[name]:remove() --remove marker
77 | machines.marker2[name] = nil
78 | end
79 | if pos2 ~= nil then
80 | --add marker
81 | machines.marker2[name] = minetest.add_entity(pos2, "machines:pos2")
82 | if machines.marker2[name] ~= nil then
83 | machines.marker2[name]:get_luaentity().name = name
84 | end
85 | end
86 | end
87 |
88 |
89 |
90 | minetest.register_entity(":machines:pos1", {
91 | initial_properties = {
92 | visual = "cube",
93 | visual_size = {x=1.1, y=1.1},
94 | textures = {"machines_pos1.png", "machines_pos1.png",
95 | "machines_pos1.png", "machines_pos1.png",
96 | "machines_pos1.png", "machines_pos1.png"},
97 | collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
98 | physical = false,
99 | },
100 | on_step = function(self, dtime)
101 | if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
102 | machines[self.name].timer = machines[self.name].timer - dtime
103 | if machines[self.name].timer<=0 or machines.marker1[self.name] == nil then
104 | self.object:remove()
105 | end
106 | end,
107 | on_punch = function(self, hitter)
108 | self.object:remove()
109 | machines.marker1[self.name] = nil
110 | machines[self.name].timer = 10
111 | end,
112 | })
113 |
114 | minetest.register_entity(":machines:pos11", {
115 | initial_properties = {
116 | visual = "cube",
117 | visual_size = {x=1.1, y=1.1},
118 | textures = {"machines_pos11.png", "machines_pos11.png",
119 | "machines_pos11.png", "machines_pos11.png",
120 | "machines_pos11.png", "machines_pos11.png"},
121 | collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
122 | physical = false,
123 | },
124 | on_step = function(self, dtime)
125 | if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
126 | machines[self.name].timer = machines[self.name].timer - dtime
127 | if machines[self.name].timer<=0 or machines.marker11[self.name] == nil then
128 | self.object:remove()
129 | end
130 | end,
131 | on_punch = function(self, hitter)
132 | self.object:remove()
133 | machines.marker11[self.name] = nil
134 | machines[self.name].timer = 10
135 | end,
136 | })
137 |
138 | minetest.register_entity(":machines:pos2", {
139 | initial_properties = {
140 | visual = "cube",
141 | visual_size = {x=1.1, y=1.1},
142 | textures = {"machines_pos2.png", "machines_pos2.png",
143 | "machines_pos2.png", "machines_pos2.png",
144 | "machines_pos2.png", "machines_pos2.png"},
145 | collisionbox = {-0.55, -0.55, -0.55, 0.55, 0.55, 0.55},
146 | physical = false,
147 | },
148 | on_step = function(self, dtime)
149 | if not machines[self.name] then machines[self.name]={}; machines[self.name].timer = 10 end
150 | if machines[self.name].timer<=0 or machines.marker2[self.name] == nil then
151 | self.object:remove()
152 | end
153 | end,
154 | })
155 |
--------------------------------------------------------------------------------
/mesecon_adapter.lua:
--------------------------------------------------------------------------------
1 |
2 | -- block that can be activated/activate mesecon blocks
3 |
4 | local adapter_effector = {
5 | action_on = function (pos, node,ttl)
6 | if type(ttl)~="number" then ttl = 2 end
7 | if not(ttl>0) then return end
8 |
9 | pos.y=pos.y+1;
10 | local node = minetest.get_node(pos);
11 | if not node.name then return end -- error
12 | local table = minetest.registered_nodes[node.name];
13 | if not table then return end
14 | if table.effector and table.effector.action_on then -- activate basic_machine
15 | local effector=table.effector;
16 | effector.action_on(pos,node,ttl);
17 | else -- table.mesecons and table.mesecons.effector then -- activate mesecons
18 | pos.y=pos.y-1
19 | mesecon.receptor_on(pos, mesecon.rules.buttonlike_get(node))
20 | --local effector=table.mesecons.effector;
21 | --effector.action_on(pos,node);
22 | end
23 | end,
24 |
25 | action_off = function (pos, node,ttl)
26 | if type(ttl)~="number" then ttl = 2 end
27 | if not(ttl>0) then return end
28 |
29 | pos.y=pos.y+1;
30 | local node = minetest.get_node(pos);
31 | if not node.name then return end -- error
32 | local table = minetest.registered_nodes[node.name];
33 | if not table then return end
34 | if table.effector and table.effector.action_off then -- activate basic_machine
35 | local effector=table.effector;
36 | effector.action_off(pos,node,ttl);
37 | else -- table.mesecons and table.mesecons.effector then -- activate mesecons
38 | pos.y=pos.y-1
39 | mesecon.receptor_off(pos, mesecon.rules.buttonlike_get(node))
40 | --local effector=table.mesecons.effector;
41 | --effector.action_off(pos,node);
42 | end
43 | end,
44 | }
45 |
46 | minetest.register_node("basic_machines:mesecon_adapter", {
47 | description = "interface between machines and mesecons - place block to be activated on top of it.",
48 | tiles = {"basic_machine_clock_generator.png","basic_machine_clock_generator.png",
49 | "jeija_luacontroller_top.png","jeija_luacontroller_top.png","jeija_luacontroller_top.png","jeija_luacontroller_top.png"
50 | },
51 | groups = {cracky=3,mesecon_effector_on = 1,mesecon_effector_off=1,mesecon_needs_receiver = 1,},
52 | sounds = default.node_sound_wood_defaults(),
53 |
54 |
55 | effector = adapter_effector,
56 | mesecons = {
57 | effector = adapter_effector,
58 | receptor = {
59 | rules = mesecon.rules.buttonlike_get,
60 | state = mesecon.state.off
61 | },
62 | },
63 |
64 | })
--------------------------------------------------------------------------------
/mesecon_doors.lua:
--------------------------------------------------------------------------------
1 | -- make doors open/close with signal
2 |
3 | tablecopy = function(a)
4 | local b = {};
5 | for k,v in pairs(a) do
6 | if type(v) == "table" then
7 | b[k] = tablecopy(v)
8 | else
9 | b[k]=v
10 | end
11 | end
12 | return b
13 | end
14 |
15 | local function door_signal_overwrite(name)
16 |
17 | local table = minetest.registered_nodes[name]; if not table then return end
18 | --if table.mesecons then return end -- already exists, don't change
19 | local door_on_rightclick = table.on_rightclick;
20 |
21 | minetest.override_item(name,
22 | {
23 | effector = {
24 | action_on = function(pos,node)
25 | local meta = minetest.get_meta(pos);local name = meta:get_string("owner");
26 | -- create virtual player
27 | local clicker = {};
28 | function clicker:get_wielded_item()
29 | local item = {}
30 | function item:get_name() return "" end
31 | return item
32 | end
33 | 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
34 | function clicker:is_player() return true end; -- method needed for mods that check this: like denaid areas mod
35 | if door_on_rightclick then door_on_rightclick(pos, nil, clicker,ItemStack(""),{}) end -- safety if it doesnt exist
36 | --minetest.swap_node(pos, {name = "protector:trapdoor", param1 = node.param1, param2 = node.param2}) -- more direct approach?, need to set param2 then too
37 | end
38 | }
39 | }
40 | )
41 |
42 | end
43 |
44 | door_signal_overwrite("doors:door_wood");door_signal_overwrite("doors:door_steel")
45 | door_signal_overwrite("doors:door_wood_a");door_signal_overwrite("doors:door_wood_b");
46 | door_signal_overwrite("doors:door_steel_a");door_signal_overwrite("doors:door_steel_b");
47 | door_signal_overwrite("doors:door_glass_a");door_signal_overwrite("doors:door_glass_b");
48 | door_signal_overwrite("doors:door_obsidian_glass_a");door_signal_overwrite("doors:door_obsidian_glass_b");
49 |
50 | door_signal_overwrite("doors:trapdoor");door_signal_overwrite("doors:trapdoor_open");
51 | door_signal_overwrite("doors:trapdoor_steel");door_signal_overwrite("doors:trapdoor_steel_open");
52 |
53 | local function make_it_noclip(name)
54 | minetest.override_item(name,{walkable = false}); -- cant be walked on
55 | end
56 |
57 | make_it_noclip("doors:trapdoor_open");
58 | make_it_noclip("doors:trapdoor_steel_open");
59 |
60 | -- minetest bug: using override_item to change group.level = 99 does nothing - door still diggable
61 | -- using minetest.register_node(":"..name, table2) with table2.group.level = 99 does work. why?
62 |
63 | --[[
64 |
65 | local function make_it_nondiggable_but_removable(name, dropname)
66 |
67 | local table = minetest.registered_nodes[name]; if not table then return end
68 | local table2 = tablecopy(table.groups);
69 |
70 | table2.level = 99; -- cant be digged, but it can be removed by owner or if not protected
71 |
72 | minetest.override_item(name,
73 | {
74 | on_punch = function(pos, node, puncher, pointed_thing) -- remove node if owner repeatedly punches it 3x
75 | local pname = puncher:get_player_name();
76 | local meta = minetest.get_meta(pos);
77 | local owner = meta:get_string("doors_owner")
78 | if pname==owner or not minetest.is_protected(pos,pname) then -- can be dug by owner or if unprotected
79 | local t0 = meta:get_int("punchtime");local count = meta:get_int("punchcount");
80 | local t = minetest.get_gametime();
81 |
82 | if t-t0<2 then count = (count +1 ) % 3 else count = 0 end
83 |
84 | if count == 1 then
85 | minetest.chat_send_player(pname, "#steel door: punch me one more time to remove me");
86 | end
87 | if count == 2 then -- remove steel door and drop it
88 | minetest.set_node(pos, {name = "air"});
89 | local stack = ItemStack(dropname);minetest.add_item(pos,stack)
90 | end
91 |
92 | meta:set_int("punchcount",count);meta:set_int("punchtime",t);
93 | --minetest.chat_send_all("punch by "..name .. " count " .. count)
94 | end
95 | end
96 | })
97 |
98 | minetest.override_item(name, {diggable = false})
99 |
100 | --minetest.register_node(":"..name, table2)
101 | end
102 |
103 | --minetest.after(0,function()
104 | make_it_nondiggable_but_removable("doors:door_steel_a","doors:door_steel");
105 | make_it_nondiggable_but_removable("doors:door_steel_b","doors:door_steel");
106 |
107 | make_it_nondiggable_but_removable("doors:trapdoor_steel","doors:trapdoor_steel");
108 | make_it_nondiggable_but_removable("doors:trapdoor_steel_open","doors:trapdoor_steel");
109 | --end);
110 | --]]
--------------------------------------------------------------------------------
/mesecon_lights.lua:
--------------------------------------------------------------------------------
1 | -- make other light blocks work with mesecon signals - can toggle on/off
2 |
3 | local function enable_toggle_light(name)
4 |
5 | local table = minetest.registered_nodes[name]; if not table then return end
6 | local table2 = {}
7 | for i,v in pairs(table) do table2[i] = v end
8 |
9 | if table2.mesecons then return end -- we dont want to overwrite existing stuff!
10 |
11 | local offname = "basic_machines:"..string.gsub(name, ":", "_").. "_OFF";
12 |
13 | table2.effector = { -- action to toggle light off
14 | action_off = function (pos,node,ttl)
15 | minetest.swap_node(pos,{name = offname});
16 | end
17 | };
18 |
19 |
20 | minetest.register_node(":"..name, table2) -- redefine item
21 |
22 | -- 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!???
23 | -- STRANGE BUG2: if you dont make new table3.. original node automatically changes to OFF node when placed ????
24 |
25 | local table3 = {}
26 | for i,v in pairs(table) do
27 | table3[i] = v
28 | end
29 |
30 | table3.light_source = 0; -- off block has light off
31 | table3.effector = {
32 | action_on = function (pos,node,ttl)
33 | minetest.swap_node(pos,{name = name});
34 | end
35 | };
36 |
37 | -- REGISTER OFF BLOCK
38 | minetest.register_node(":"..offname, table3);
39 |
40 | end
41 |
42 |
43 | enable_toggle_light("xdecor:wooden_lightbox");
44 | enable_toggle_light("xdecor:iron_lightbox");
45 | enable_toggle_light("moreblocks:slab_meselamp_1");
46 | enable_toggle_light("moreblocks:slab_super_glow_glass");
47 |
48 | enable_toggle_light("darkage:lamp");
--------------------------------------------------------------------------------
/mod.conf:
--------------------------------------------------------------------------------
1 | name = basic_machines
2 | depends = default
3 | optional_depends = protector,doors,areas,boneworld,moreores,mesecons
4 | description = automate gameplay with machines. build logic mechanisms.
--------------------------------------------------------------------------------
/plans.txt:
--------------------------------------------------------------------------------
1 | grinder: creates dust_0, must be mixed with extractor chemical to get dust_33
--------------------------------------------------------------------------------
/protect.lua:
--------------------------------------------------------------------------------
1 | -- adds event handler for attempt to dig in protected area
2 |
3 | -- tries to activate specially configured nearby distributor at points with coordinates of form 20i, registers dig attempts in radius 10 around
4 | -- distributor must have first target filter set to 0 ( disabled ) to handle dig events
5 |
6 | local old_is_protected = minetest.is_protected
7 | local round = math.floor;
8 | local machines_TTL = basic_machines.machines_TTL or 16
9 |
10 | function minetest.is_protected(pos, digger)
11 |
12 | local is_protected = old_is_protected(pos, digger);
13 | if is_protected then -- only if protected
14 | 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}
15 | 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
16 | local meta = minetest.get_meta(p);
17 | if meta:get_int("active1") == 0 then -- first output is disabled, indicating ready to be used as event handler
18 | if meta:get_int("x1") ~= 0 then -- trigger protection event
19 | meta:set_string("infotext",digger); -- record diggers name onto distributor
20 | local table = minetest.registered_nodes["basic_machines:distributor"];
21 | local effector=table.effector;
22 | local node = nil;
23 | effector.action_on(p,node,machines_TTL);
24 | end
25 | end
26 | end
27 | end
28 | return is_protected;
29 |
30 | end
31 |
32 | minetest.register_on_chat_message(function(name, message)
33 | local player = minetest.get_player_by_name(name);
34 | if not player then return end
35 | local pos = player:get_pos();
36 | 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}
37 | --minetest.chat_send_all(minetest.pos_to_string(p))
38 | if minetest.get_node(p).name == "basic_machines:distributor" then -- attempt to activate distributor at special grid location: coordinates of the form 20*i
39 | local meta = minetest.get_meta(p);
40 | if meta:get_int("active1") == 0 then -- first output is disabled, indicating ready to be used as event handler
41 | local y1 = meta:get_int("y1");
42 | if y1 ~= 0 then -- chat event, positive relays message, negative drops it
43 | meta:set_string("infotext",message); -- record diggers message
44 | local table = minetest.registered_nodes["basic_machines:distributor"];
45 | local effector=table.mesecons.effector;
46 | local node = nil;
47 | effector.action_on(p,node,machines_TTL);
48 | if y1<0 then return true
49 | end
50 | end
51 | end
52 | end
53 | end
54 | )
--------------------------------------------------------------------------------
/recycler.lua:
--------------------------------------------------------------------------------
1 | -- rnd 2015:
2 |
3 | -- 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.
4 | -- There is a fuel cost to recycle
5 |
6 | -- prevent unrealistic recyclings
7 | local no_recycle_list = {
8 | ["default:steel_ingot"]=1,["default:copper_ingot"]=1,["default:bronze_ingot"]=1,["default:gold_ingot"]=1,
9 | ["dye:white"]=1,["dye:grey"]=1,["dye:dark_grey"]=1,["dye:black"]=1,
10 | ["dye:violet"]=1,["dye:blue"]=1,["dye:cyan"]=1,["dye:dark_green"]=1,
11 | ["dye:green"]=1,["dye:yellow"]=1,["dye:brown"]=1,["dye:orange"]=1,
12 | ["dye:red"]=1,["dye:magenta"]=1,["dye:pink"]=1,["default:mossycobble"]=1,
13 | }
14 |
15 |
16 | local recycler_process = function(pos)
17 |
18 | local node = minetest.get_node({x=pos.x,y=pos.y-1,z=pos.z}).name;
19 | local meta = minetest.get_meta(pos);local inv = meta:get_inventory();
20 |
21 | -- FUEL CHECK
22 | local fuel = meta:get_float("fuel");
23 |
24 | if fuel-1<0 then -- we need new fuel, check chest below
25 | local fuellist = inv:get_list("fuel")
26 | if not fuellist then return end
27 |
28 | local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
29 |
30 | local supply=0;
31 | if fueladd.time == 0 then -- no fuel inserted, try look for outlet
32 | -- No valid fuel in fuel list
33 | supply = basic_machines.check_power({x=pos.x,y=pos.y-1,z=pos.z},1) or 0;
34 | if supply>0 then
35 | fueladd.time = 40*supply -- same as 10 coal
36 | else
37 | meta:set_string("infotext", "Please insert fuel.");
38 | return;
39 | end
40 | else
41 | if supply==0 then -- Take fuel from fuel list if no supply available
42 | inv:set_stack("fuel", 1, afterfuel.items[1])
43 | fueladd.time = fueladd.time*0.1; -- thats 4 for coal
44 | end
45 | end
46 | if fueladd.time>0 then
47 | fuel=fuel + fueladd.time
48 | meta:set_float("fuel",fuel);
49 | meta:set_string("infotext", "added fuel furnace burn time " .. fueladd.time .. ", fuel status " .. fuel);
50 | end
51 | if fuel-1<0 then return end
52 | end
53 |
54 |
55 |
56 | -- RECYCLING: check out inserted items
57 | local stack = inv:get_stack("src",1);
58 | if stack:is_empty() then return end; -- nothing to do
59 |
60 | local src_item = stack:to_string();
61 | 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
62 |
63 | -- look if we already handled this item
64 | local known_recipe=true;
65 | if src_item~=meta:get_string("node") then-- did we already handle this? if yes read from cache
66 | meta:set_string("node",src_item);
67 | meta:set_string("itemlist","{}");
68 | meta:set_int("reqcount",0);
69 | known_recipe=false;
70 | end
71 |
72 | local itemlist, reqcount;
73 | reqcount = 1; -- needed count of materials for recycle to work
74 |
75 | if not known_recipe then
76 |
77 | if no_recycle_list[src_item] then meta:set_string("node","") return end -- dont allow recycling of forbidden items
78 |
79 | local recipe = minetest.get_all_craft_recipes( src_item );
80 | local recipe_id = tonumber(meta:get_int("recipe")) or 1;
81 |
82 | if not recipe then
83 | return
84 | else
85 | itemlist = recipe[recipe_id];
86 | if not itemlist then meta:set_string("node","") return end;
87 | itemlist=itemlist.items;
88 | end
89 | local output = recipe[recipe_id].output or "";
90 | if string.find(output," ") then
91 | local par = string.find(output," ");
92 | --if (tonumber(string.sub(output, par)) or 0)>1 then itemlist = {} end
93 |
94 | if par then
95 | reqcount = tonumber(string.sub(output, par)) or 1;
96 | end
97 |
98 | end
99 |
100 | meta:set_string("itemlist",minetest.serialize(itemlist)); -- read cached itemlist
101 | meta:set_int("reqcount",reqcount);
102 | else
103 | itemlist=minetest.deserialize(meta:get_string("itemlist")) or {};
104 | reqcount = meta:get_int("reqcount") or 1;
105 | end
106 |
107 | if stack:get_count()0 then
73 | if pos.y>1500 then add_energy=2*add_energy end -- in space recharge is more efficient
74 | crystal = true;
75 | if add_energy<=capacity then
76 | stack:take_item(1);
77 | inv:set_stack("fuel", 1, stack)
78 | else
79 | meta:set_string("infotext", "recharge problem: capacity " .. capacity .. ", needed " .. energy+add_energy)
80 | return energy
81 | end
82 | else -- try do determine caloric value of fuel inside battery
83 | local fuellist = inv:get_list("fuel");if not fuellist then return energy end
84 | local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
85 | if fueladd.time > 0 then
86 | add_energy = fueladd.time/40;
87 | if energy+add_energy<=capacity then
88 | inv:set_stack("fuel", 1, afterfuel.items[1]);
89 | else
90 | meta:set_string("infotext", "recharge problem: capacity " .. capacity .. ", needed " .. energy+add_energy)
91 | return energy
92 | end
93 | end
94 | end
95 |
96 | if add_energy>0 then
97 | energy=energy+add_energy
98 | if energy<0 then energy = 0 end
99 | if energy>capacity then energy = capacity end -- excess energy is wasted
100 | meta:set_float("energy",energy);
101 | meta:set_string("infotext", "(R) energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
102 | minetest.sound_play("electric_zap", {pos=pos,gain=0.05,max_hear_distance = 8,})
103 | end
104 |
105 | local full_coef = math.floor(energy/capacity*3);
106 | if capacity == 0 then full_coef = 0 end
107 | if full_coef > 2 then full_coef = 2 end
108 | minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef}) -- graphic energy
109 |
110 | return energy; -- new battery energy level
111 | end
112 |
113 | battery_upgrade = function(pos)
114 | local meta = minetest.get_meta(pos);
115 | local inv = meta:get_inventory();
116 | local count1,count2;count1=0;count2=0;
117 | local stack,item,count;
118 | for i=1,4 do
119 | stack = inv:get_stack("upgrade", i);item = stack:get_name();count= stack:get_count();
120 | if item == "default:mese" then
121 | count1=count1+count
122 | elseif item == "default:diamondblock" then
123 | count2=count2+count
124 | end
125 | end
126 | --if count11500 then count1 = 2*count1; count2=2*count2 end -- space increases efficiency
129 |
130 |
131 | meta:set_int("upgrade",count2); -- diamond for power
132 | -- adjust capacity
133 | --yyy
134 | local capacity = 3+3*count1; -- mese for capacity
135 | local maxpower = 1+count2*2; -- old 99 upgrade -> 200 power
136 |
137 | capacity = math.ceil(capacity*10)/10;
138 | local energy = 0;
139 | meta:set_float("capacity",capacity)
140 | meta:set_float("maxpower",maxpower)
141 | meta:set_float("energy",0)
142 | meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
143 | end
144 |
145 | local machines_activate_furnace = minetest.registered_nodes["default:furnace"].on_metadata_inventory_put; -- this function will activate furnace
146 |
147 | minetest.register_node("basic_machines:battery_0", {
148 | description = "battery - stores energy, generates energy from fuel, can power nearby machines, or accelerate/run furnace above it. Its upgradeable.",
149 | tiles = {"basic_machine_outlet.png","basic_machine_battery.png","basic_machine_battery_0.png"},
150 | groups = {cracky=3},
151 | sounds = default.node_sound_wood_defaults(),
152 |
153 | after_place_node = function(pos, placer)
154 | local meta = minetest.get_meta(pos);
155 | 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");
156 | meta:set_string("owner",placer:get_player_name());
157 | local inv = meta:get_inventory();inv:set_size("fuel", 1*1); -- place to put crystals
158 | inv:set_size("upgrade", 2*2);
159 | meta:set_int("upgrade",0); -- upgrade level determines energy storage capacity and max energy output
160 | meta:set_float("capacity",3);meta:set_float("maxpower",1);
161 | meta:set_float("energy",0);
162 | end,
163 |
164 | effector = {
165 | action_on = function (pos, node,ttl)
166 | if type(ttl)~="number" then ttl = 1 end
167 | if ttl<0 then return end -- machines_TTL prevents infinite recursion
168 |
169 | local meta = minetest.get_meta(pos);
170 | local energy = meta:get_float("energy");
171 | local capacity = meta:get_float("capacity");
172 | local full_coef = math.floor(energy/capacity*3);
173 |
174 | -- try to power furnace on top of it
175 | if energy>=1 then -- need at least 1 energy
176 | pos.y=pos.y+1; local node = minetest.get_node(pos).name;
177 |
178 | if node== "default:furnace" or node=="default:furnace_active" then
179 | local fmeta = minetest.get_meta(pos);
180 | local fuel_totaltime = fmeta:get_float("fuel_totaltime") or 0;
181 | local fuel_time = fmeta:get_float("fuel_time") or 0;
182 | local t0 = meta:get_int("ftime"); -- furnace time
183 | local t1 = minetest.get_gametime();
184 |
185 | if t1-t04 then -- accelerated cooking
193 | local src_time = fmeta:get_float("src_time") or 0
194 | energy = energy - 0.25*upgrade; -- use energy to accelerate burning
195 |
196 |
197 | if fuel_time>40 or fuel_totaltime == 0 or node=="default:furnace" then -- to add burn time: must burn for at least 40 secs or furnace out of fuel
198 |
199 | fmeta:set_float("fuel_totaltime",60);fmeta:set_float("fuel_time",0) -- add 60 second burn time to furnace
200 | energy=energy-0.5; -- use up energy to add fuel
201 |
202 | -- make furnace start if not already started
203 | if node~="default:furnace_active" and machines_activate_furnace then machines_activate_furnace(pos) end
204 | -- update energy display
205 | end
206 |
207 |
208 | if energy<0 then
209 | energy = 0
210 | else -- only accelerate if we had enough energy, note: upgrade*0.1*0.25=1 then -- no need to recharge yet, will still work next time
219 | local full_coef_new = math.floor(energy/capacity*3); if full_coef_new>2 then full_coef_new = 2 end
220 | if capacity == 0 then full_coef_new = 0 end
221 | pos.y = pos.y-1;
222 | if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end
223 | return
224 | else
225 | local infotext = meta:get_string("infotext");
226 | local new_infotext = "furnace needs at least 1 energy";
227 | if new_infotext~=infotext then -- dont update unnecesarilly
228 | meta:set_string("infotext", new_infotext);
229 | pos.y=pos.y-1; -- so that it points to battery again!
230 | end
231 | end
232 | else
233 | pos.y=pos.y-1;
234 | end
235 |
236 | end
237 |
238 | -- try to recharge by converting inserted fuel/power cells into energy
239 |
240 | if energy2 then full_coef_new = 2 end
246 | if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end
247 |
248 | end
249 | },
250 |
251 | on_rightclick = function(pos, node, player, itemstack, pointed_thing)
252 | local meta = minetest.get_meta(pos);
253 | local privs = minetest.get_player_privs(player:get_player_name());
254 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
255 | battery_update_meta(pos);
256 | end,
257 |
258 | on_receive_fields = function(pos, formname, fields, sender)
259 | if fields.quit then return end
260 | local meta = minetest.get_meta(pos);
261 |
262 |
263 | if fields.OK then battery_update_meta(pos) return end
264 | if fields.help then
265 | local name = sender:get_player_name();
266 | local text = "Battery provides power to machines or furnace. It can either "..
267 | "use power cells or convert ordinary furnace fuels into energy. 1 coal lump gives 1 energy.\n\n"..
268 | "UPGRADE with diamondblocks for more available power output or with "..
269 | "meseblocks for more power storage capacity"
270 |
271 | local form = "size [6,7] textarea[0,0;6.5,8.5;help;BATTERY HELP;".. text.."]"
272 | minetest.show_formspec(name, "basic_machines:help_battery", form)
273 | end
274 | end,
275 |
276 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
277 | local meta = minetest.get_meta(pos);
278 | local privs = minetest.get_player_privs(player:get_player_name());
279 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
280 | return stack:get_count();
281 | end,
282 |
283 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
284 | local meta = minetest.get_meta(pos);
285 | local privs = minetest.get_player_privs(player:get_player_name());
286 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
287 | return stack:get_count();
288 | end,
289 |
290 | on_metadata_inventory_put = function(pos, listname, index, stack, player)
291 | if listname=="fuel" then
292 | battery_recharge(pos);
293 | battery_update_meta(pos);
294 | elseif listname == "upgrade" then
295 | battery_upgrade(pos);
296 | battery_update_meta(pos);
297 | end
298 | return stack:get_count();
299 | end,
300 |
301 | on_metadata_inventory_take = function(pos, listname, index, stack, player)
302 | if listname == "upgrade" then
303 | battery_upgrade(pos);
304 | battery_update_meta(pos);
305 | end
306 | return stack:get_count();
307 | end,
308 |
309 | allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
310 | return 0;
311 | end,
312 |
313 | can_dig = function(pos)
314 | local meta = minetest.get_meta(pos);
315 | local inv = meta:get_inventory();
316 |
317 | if not (inv:is_empty("fuel")) or not (inv:is_empty("upgrade")) then return false end -- fuel AND upgrade inv must be empty to be dug
318 |
319 | return true
320 |
321 | end
322 |
323 | })
324 |
325 |
326 |
327 | -- GENERATOR
328 |
329 | local generator_update_meta = function(pos)
330 | local meta = minetest.get_meta(pos);
331 | local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
332 |
333 | local form =
334 | "size[8,6.5]" .. -- width, height
335 | "label[0,0;POWER CRYSTALS] ".."label[6,0;UPGRADE] "..
336 | "label[1,1;UPGRADE LEVEL ".. meta:get_int("upgrade").." (generator)]"..
337 | "list["..list_name..";fuel;0.,0.5;1,1;]"..
338 | "list["..list_name..";upgrade;6.,0.5;2,1;]"..
339 | "list[current_player;main;0,2.5;8,4;]"..
340 | "button[4.5,1.5;1.5,1;OK;REFRESH]"..
341 | "button[6,1.5;1.5,1;help;help]"..
342 | "listring["..list_name..";fuel]"..
343 | "listring[current_player;main]"..
344 | "listring["..list_name..";upgrade]"..
345 | "listring[current_player;main]"
346 | meta:set_string("formspec", form)
347 | end
348 |
349 |
350 |
351 | generator_upgrade = function(pos)
352 | local meta = minetest.get_meta(pos);
353 | local inv = meta:get_inventory();
354 | local stack,item,count;
355 | count = 0
356 | for i=1,2 do
357 | stack = inv:get_stack("upgrade", i);item = stack:get_name();
358 | if item == "basic_machines:generator" then
359 | count= count + stack:get_count();
360 | end
361 | end
362 | meta:set_int("upgrade",count);
363 | end
364 |
365 | --local genstat = {}; -- generator statistics for each player
366 | minetest.register_node("basic_machines:generator", {
367 | description = "Generator - very expensive, generates power crystals that provide power. Its upgradeable.",
368 | tiles = {"basic_machine_generator.png"},
369 | groups = {cracky=3},
370 | sounds = default.node_sound_wood_defaults(),
371 | after_place_node = function(pos, placer)
372 |
373 | --check to prevent too many generators being placed at one place
374 | if minetest.find_node_near(pos, 15, {"basic_machines:generator"}) then
375 | minetest.set_node(pos,{name="air"})
376 | minetest.add_item(pos,"basic_machines:generator")
377 | minetest.chat_send_player(placer:get_player_name(),"#generator: interference from nearby generator detected.")
378 | return
379 | end
380 |
381 | local meta = minetest.get_meta(pos);
382 | meta:set_string("infotext","generator - generates power crystals that provide power. Upgrade with up to 50 generators.");
383 | meta:set_string("owner",placer:get_player_name());
384 | local inv = meta:get_inventory();
385 | inv:set_size("fuel", 1*1); -- here generated power crystals are placed
386 | inv:set_size("upgrade", 2*1);
387 | meta:set_int("upgrade",0); -- upgrade level determines quality of produced crystals
388 |
389 | end,
390 |
391 | on_rightclick = function(pos, node, player, itemstack, pointed_thing)
392 | local meta = minetest.get_meta(pos);
393 | local privs = minetest.get_player_privs(player:get_player_name());
394 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
395 | generator_update_meta(pos);
396 | end,
397 |
398 | on_receive_fields = function(pos, formname, fields, sender)
399 | if fields.quit then return end
400 | if fields.help then
401 | local text = "Generator slowly produces power crystals. Those can be used to recharge batteries and come in 3 flavors:\n\n low level (0-4), medium level (5-19) and high level (20+). Upgrading the generator (upgrade with generators) will increase the rate at which the crystals are produced.\n\nYou can automate the process of battery recharging by using mover in inventory mode, taking from inventory \"fuel\"";
402 | local form = "size [6,7] textarea[0,0;6.5,8.5;help;GENERATOR HELP;".. text.."]"
403 | minetest.show_formspec(sender:get_player_name(), "basic_machines:help_mover", form)
404 | return
405 | end
406 | local meta = minetest.get_meta(pos);
407 | generator_update_meta(pos);
408 | end,
409 |
410 | allow_metadata_inventory_put = function(pos, listname, index, stack, player)
411 | local meta = minetest.get_meta(pos);
412 | local privs = minetest.get_player_privs(player:get_player_name());
413 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
414 | return stack:get_count();
415 | end,
416 |
417 | allow_metadata_inventory_take = function(pos, listname, index, stack, player)
418 | local meta = minetest.get_meta(pos);
419 | local privs = minetest.get_player_privs(player:get_player_name());
420 | if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
421 | return stack:get_count();
422 | end,
423 |
424 | on_metadata_inventory_put = function(pos, listname, index, stack, player)
425 | if listname == "upgrade" then
426 | generator_upgrade(pos);
427 | generator_update_meta(pos);
428 | end
429 | return stack:get_count();
430 | end,
431 |
432 | on_metadata_inventory_take = function(pos, listname, index, stack, player)
433 | if listname == "upgrade" then
434 | generator_upgrade(pos);
435 | generator_update_meta(pos);
436 | end
437 | return stack:get_count();
438 | end,
439 |
440 | allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
441 | return 0;
442 | end,
443 |
444 | can_dig = function(pos)
445 | local meta = minetest.get_meta(pos);
446 | local inv = meta:get_inventory();
447 |
448 | if not inv:is_empty("upgrade") then return false end -- fuel inv is not so important as generator generates it
449 |
450 | return true
451 | end,
452 | })
453 |
454 | minetest.register_abm({
455 | nodenames = {"basic_machines:generator"},
456 | neighbors = {},
457 | interval = 19,
458 | chance = 1,
459 | action = function(pos, node, active_object_count, active_object_count_wider)
460 | local meta = minetest.get_meta(pos);
461 |
462 | local upgrade = meta:get_int("upgrade");
463 | local inv = meta:get_inventory();
464 | local stack = inv:get_stack("fuel", 1);
465 | local crystal, text;
466 |
467 | if upgrade > 50 then meta:set_string("infotext","error: max upgrade is 50"); return end
468 |
469 | if upgrade >= 20 then
470 | crystal = "basic_machines:power_rod " .. math.floor(1+(upgrade-20)*9/178)
471 | text = "high upgrade: power rod";
472 | elseif upgrade >=5 then
473 | crystal ="basic_machines:power_block " .. math.floor(1+(upgrade-5)*9/15);
474 | text = "medium upgrade: power block";
475 | else
476 | crystal ="basic_machines:power_cell " .. math.floor(1+2*upgrade);
477 | text = "low upgrade: power cell";
478 | end
479 | local morecrystal = ItemStack(crystal)
480 | stack:add_item(morecrystal);
481 | inv:set_stack("fuel", 1, stack)
482 | meta:set_string("infotext",text)
483 | end
484 | })
485 |
486 |
487 |
488 |
489 | -- API for power distribution
490 | function basic_machines.check_power(pos, power_draw) -- mover checks power source - battery
491 |
492 | local batname = "basic_machines:battery";
493 | if not string.find(minetest.get_node(pos).name,batname) then -- check with hashtables probably faster?
494 | return -1 -- battery not found!
495 | end
496 |
497 | local meta = minetest.get_meta(pos);
498 | local energy = meta:get_float("energy");
499 | local capacity = meta:get_float("capacity");
500 | local maxpower = meta:get_float("maxpower");
501 | local full_coef = math.floor(energy/capacity*3); -- 0,1,2
502 |
503 | if power_draw>maxpower then
504 | meta:set_string("infotext", "Power draw required : " .. power_draw .. " maximum power output " .. maxpower .. ". Please upgrade battery")
505 | return 0;
506 | end
507 |
508 | if power_draw>energy then
509 | energy = battery_recharge(pos); -- try recharge battery and continue operation immidiately
510 | if not energy then return 0 end
511 | end
512 |
513 | energy = energy-power_draw;
514 | if energy<0 then
515 | meta:set_string("infotext", "used fuel provides too little power for current power draw ".. power_draw);
516 | return 0
517 | end -- recharge wasnt enough, needs to be repeated manually, return 0 power available
518 | meta:set_float("energy", energy);
519 | -- update energy display
520 | meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
521 |
522 | local full_coef_new = math.floor(energy/capacity*3); if full_coef_new>2 then full_coef_new = 2 end
523 | if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end -- graphic energy level display
524 |
525 | return power_draw;
526 |
527 | end
528 |
529 | ------------------------
530 | -- CRAFTS
531 | ------------------------
532 |
533 | -- minetest.register_craft({
534 | -- output = "basic_machines:battery",
535 | -- recipe = {
536 | -- {"","default:steel_ingot",""},
537 | -- {"default:steel_ingot","default:mese","default:steel_ingot"},
538 | -- {"","default:diamond",""},
539 |
540 | -- }
541 | -- })
542 |
543 | -- minetest.register_craft({
544 | -- output = "basic_machines:generator",
545 | -- recipe = {
546 | -- {"","",""},
547 | -- {"default:diamondblock","basic_machines:battery","default:diamondblock"},
548 | -- {"default:diamondblock","default:diamondblock","default:diamondblock"}
549 |
550 | -- }
551 | -- })
552 |
553 | minetest.register_craftitem("basic_machines:power_cell", {
554 | description = "Power cell - provides 1 power",
555 | inventory_image = "power_cell.png",
556 | stack_max = 25
557 | })
558 |
559 | minetest.register_craftitem("basic_machines:power_block", {
560 | description = "Power block - provides 11 power",
561 | inventory_image = "power_block.png",
562 | stack_max = 25
563 | })
564 |
565 | minetest.register_craftitem("basic_machines:power_rod", {
566 | description = "Power rod - provides 100 power",
567 | inventory_image = "power_rod.png",
568 | stack_max = 25
569 | })
570 |
571 | -- various battery levels: 0,1,2 (2 >= 66%, 1 >= 33%,0>=0%)
572 | local batdef = {};
573 | for k,v in pairs(minetest.registered_nodes["basic_machines:battery_0"]) do batdef[k] = v end
574 |
575 | for i = 1,2 do
576 | batdef.tiles[3] = "basic_machine_battery_" .. i ..".png"
577 | minetest.register_node("basic_machines:battery_"..i, batdef)
578 | end
579 |
--------------------------------------------------------------------------------
/textures/basic_machine_battery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_battery.png
--------------------------------------------------------------------------------
/textures/basic_machine_battery_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_battery_0.png
--------------------------------------------------------------------------------
/textures/basic_machine_battery_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_battery_1.png
--------------------------------------------------------------------------------
/textures/basic_machine_battery_2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_battery_2.png
--------------------------------------------------------------------------------
/textures/basic_machine_clock_generator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_clock_generator.png
--------------------------------------------------------------------------------
/textures/basic_machine_generator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_generator.png
--------------------------------------------------------------------------------
/textures/basic_machine_mover_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_mover_side.png
--------------------------------------------------------------------------------
/textures/basic_machine_outlet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_outlet.png
--------------------------------------------------------------------------------
/textures/basic_machine_side.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machine_side.png
--------------------------------------------------------------------------------
/textures/basic_machines_ball.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machines_ball.png
--------------------------------------------------------------------------------
/textures/basic_machines_dust.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machines_dust.png
--------------------------------------------------------------------------------
/textures/basic_machines_stars.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/basic_machines_stars.png
--------------------------------------------------------------------------------
/textures/charcoal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/charcoal.png
--------------------------------------------------------------------------------
/textures/compass_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/compass_top.png
--------------------------------------------------------------------------------
/textures/constructor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/constructor.png
--------------------------------------------------------------------------------
/textures/detector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/detector.png
--------------------------------------------------------------------------------
/textures/distributor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/distributor.png
--------------------------------------------------------------------------------
/textures/enviro.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/enviro.png
--------------------------------------------------------------------------------
/textures/grinder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/grinder.png
--------------------------------------------------------------------------------
/textures/keypad.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/keypad.png
--------------------------------------------------------------------------------
/textures/light.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/light.png
--------------------------------------------------------------------------------
/textures/light_off.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/light_off.png
--------------------------------------------------------------------------------
/textures/machines_pos1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/machines_pos1.png
--------------------------------------------------------------------------------
/textures/machines_pos11.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/machines_pos11.png
--------------------------------------------------------------------------------
/textures/machines_pos2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/machines_pos2.png
--------------------------------------------------------------------------------
/textures/ore_extractor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/ore_extractor.png
--------------------------------------------------------------------------------
/textures/pipeworks_autocrafter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/pipeworks_autocrafter.png
--------------------------------------------------------------------------------
/textures/power_block.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/power_block.png
--------------------------------------------------------------------------------
/textures/power_cell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/power_cell.png
--------------------------------------------------------------------------------
/textures/power_rod.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/power_rod.png
--------------------------------------------------------------------------------
/textures/recycler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ac-minetest/basic_machines/56164fb61a20a5ed0314feb18c69cbf0a172a37b/textures/recycler.png
--------------------------------------------------------------------------------