From ebccc240ae5682250e1e1d899cab23bf2fa67fe0 Mon Sep 17 00:00:00 2001 From: Joachim Stolberg Date: Sat, 11 May 2019 01:21:03 +0200 Subject: [PATCH] further nodes added --- basic_machines/autocrafter.lua | 9 + basic_machines/chest.lua | 6 + basic_machines/distributor.lua | 9 + basic_machines/electronic_fab.lua | 15 +- basic_machines/gravelrinser.lua | 327 ++++++++++++++++++ basic_machines/gravelsieve.lua | 9 + basic_machines/grinder.lua | 9 + basic_machines/pusher.lua | 9 + basis/gravel_lib.lua | 1 - basis/junction.lua | 30 +- basis/power.lua | 16 +- coal_power_station/boiler_base.lua | 43 +-- coal_power_station/boiler_top.lua | 1 - coal_power_station/cooler.lua | 34 +- coal_power_station/firebox.lua | 13 +- coal_power_station/generator.lua | 29 +- coal_power_station/help.lua | 54 +++ init.lua | 16 +- iron_age/coalburner.lua | 63 ++-- iron_age/lighter.lua | 6 +- nodes/usmium.lua | 19 + power/biogas_pipe.lua | 1 + power/drive_axle.lua | 3 +- power/electric_cable.lua | 33 +- power/steam_pipe.lua | 3 +- steam_engine/flywheel.lua | 2 +- steam_engine/help.lua | 4 +- test/consumer.lua | 1 - .../consumer.lua => test/consumer2.lua | 0 test/generator.lua | 5 +- test/lamp.lua | 120 +++++++ test/test.lua | 217 ++++-------- textures/techage_appl_rinser.png | Bin 0 -> 230 bytes textures/techage_appl_rinser4_top.png | Bin 0 -> 2591 bytes textures/techage_appl_rinser_top.png | Bin 0 -> 704 bytes textures/techage_boiler_bottom_ta3.png | Bin 0 -> 5809 bytes textures/techage_boiler_top_ta3.png | Bin 0 -> 6292 bytes textures/techage_cooler.png | Bin 0 -> 1176 bytes textures/techage_end_wrench.png | Bin 0 -> 819 bytes textures/techage_firebox_ta3.png | Bin 0 -> 6078 bytes textures/techage_repairkit.png | Bin 0 -> 649 bytes textures/techage_usmium_nuggets.png | Bin 0 -> 315 bytes textures/techage_wlanchip.png | Bin 0 -> 1052 bytes tools/repairkit.lua | 42 +-- tools/trowel.lua | 13 + 45 files changed, 853 insertions(+), 309 deletions(-) create mode 100644 basic_machines/gravelrinser.lua create mode 100644 coal_power_station/help.lua create mode 100644 nodes/usmium.lua rename steam_engine/consumer.lua => test/consumer2.lua (100%) create mode 100644 test/lamp.lua create mode 100644 textures/techage_appl_rinser.png create mode 100644 textures/techage_appl_rinser4_top.png create mode 100644 textures/techage_appl_rinser_top.png create mode 100644 textures/techage_boiler_bottom_ta3.png create mode 100644 textures/techage_boiler_top_ta3.png create mode 100644 textures/techage_cooler.png create mode 100644 textures/techage_end_wrench.png create mode 100644 textures/techage_firebox_ta3.png create mode 100644 textures/techage_repairkit.png create mode 100644 textures/techage_usmium_nuggets.png create mode 100644 textures/techage_wlanchip.png diff --git a/basic_machines/autocrafter.lua b/basic_machines/autocrafter.lua index b275547..5e85825 100644 --- a/basic_machines/autocrafter.lua +++ b/basic_machines/autocrafter.lua @@ -412,3 +412,12 @@ minetest.register_craft({ {"group:wood", "techage:iron_ingot", "group:wood"}, }, }) + +minetest.register_craft({ + output = node_name_ta3, + recipe = { + {"", "default:diamond", ""}, + {"", node_name_ta2, ""}, + {"", "techage:vacuum_tube", ""}, + }, +}) diff --git a/basic_machines/chest.lua b/basic_machines/chest.lua index 7e16f51..b9dbb43 100644 --- a/basic_machines/chest.lua +++ b/basic_machines/chest.lua @@ -277,3 +277,9 @@ minetest.register_craft({ output = "techage:chest_ta2", recipe = {"default:chest", "techage:tubeS", "techage:iron_ingot"} }) + +minetest.register_craft({ + type = "shapeless", + output = "techage:chest_ta3", + recipe = {"techage:chest_ta2", "techage:tubeS", "techage:vacuum_tube"} +}) diff --git a/basic_machines/distributor.lua b/basic_machines/distributor.lua index 1c57980..b0ab15f 100644 --- a/basic_machines/distributor.lua +++ b/basic_machines/distributor.lua @@ -418,3 +418,12 @@ minetest.register_craft({ {"group:wood", "techage:iron_ingot", "group:wood"}, }, }) + +minetest.register_craft({ + output = node_name_ta3, + recipe = { + {"", "techage:iron_ingot", ""}, + {"", node_name_ta2, ""}, + {"", "techage:vacuum_tube", ""}, + }, +}) diff --git a/basic_machines/electronic_fab.lua b/basic_machines/electronic_fab.lua index 93f8579..6e4d8fb 100644 --- a/basic_machines/electronic_fab.lua +++ b/basic_machines/electronic_fab.lua @@ -34,6 +34,7 @@ local ValidInput = { ["default:glass"] = true, ["basic_materials:copper_wire"] = true, ["basic_materials:plastic_sheet"] = true, + ["techage:usmium_nuggets"] = true, }, {}, -- 3 {}, -- 4 @@ -41,7 +42,7 @@ local ValidInput = { local Input = { {}, -- 1 - {"default:glass", "basic_materials:copper_wire", "basic_materials:plastic_sheet"}, --2 + {"default:glass", "basic_materials:copper_wire", "basic_materials:plastic_sheet", "techage:usmium_nuggets"}, --2 {}, -- 3 {}, -- 4 } @@ -273,6 +274,12 @@ minetest.register_craftitem("techage:vacuum_tube", { inventory_image = "techage_vacuum_tube.png", }) +minetest.register_craftitem("techage:wlanchip", { + description = I("TA4 WLAN Chip"), + inventory_image = "techage_wlanchip.png", +}) + + if minetest.global_exists("unified_inventory") then unified_inventory.register_craft_type("electronic_fab", { description = I("Electronic Fab"), @@ -282,7 +289,11 @@ if minetest.global_exists("unified_inventory") then }) unified_inventory.register_craft({ output = "techage:vacuum_tube", - items = {"default:glass", "basic_materials:copper_wire", "basic_materials:plastic_sheet"}, + items = {"default:glass", "basic_materials:copper_wire", "basic_materials:plastic_sheet", "techage:usmium_nuggets"}, type = "electronic_fab", }) end + +techage.register_help_page(I("TA2 Electronic Fab"), +I([[Used to produce Vacuum Pipes, +needed for TA3 machines.]]), "techage:ta2_electronic_fab_pas") diff --git a/basic_machines/gravelrinser.lua b/basic_machines/gravelrinser.lua new file mode 100644 index 0000000..1e8fdb8 --- /dev/null +++ b/basic_machines/gravelrinser.lua @@ -0,0 +1,327 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + TA2/TA3/TA4 Gravel Rinser, washing sieved gravel to find more ores + +]]-- + +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta +-- Techage Related Data +local TRD = function(pos) return (minetest.registered_nodes[minetest.get_node(pos).name] or {}).techage end + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local I,_ = dofile(MP.."/intllib.lua") + +local STANDBY_TICKS = 10 +local COUNTDOWN_TICKS = 10 +local CYCLE_TIME = 4 + +local function formspec(self, pos, mem) + return "size[8,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[context;src;0,0;3,3;]".. + "item_image[0,0;1,1;default:gravel]".. + "image[0,0;1,1;techage_form_mask.png]".. + "image[3.5,0;1,1;"..techage.get_power_image(pos, mem).."]".. + "image[3.5,1;1,1;techage_form_arrow.png]".. + "image_button[3.5,2;1,1;".. self:get_state_button_image(mem) ..";state_button;]".. + "list[context;dst;5,0;3,3;]".. + "list[current_player;main;0,4;8,4;]".. + "listring[context;dst]".. + "listring[current_player;main]".. + "listring[context;src]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 4) +end + +local function allow_metadata_inventory_put(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + if listname == "src" then + TRD(pos).State:start_if_standby(pos) + return stack:get_count() + elseif listname == "dst" then + return 0 + end +end + +local function allow_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local stack = inv:get_stack(from_list, from_index) + return allow_metadata_inventory_put(pos, to_list, to_index, stack, player) +end + +local function allow_metadata_inventory_take(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + return stack:get_count() +end + + +local function determine_water_dir(pos) + local pos1 = {x=pos.x+1, y=pos.y, z=pos.z} + local pos2 = {x=pos.x-1, y=pos.y, z=pos.z} + local pos3 = {x=pos.x, y=pos.y, z=pos.z+1} + local pos4 = {x=pos.x, y=pos.y, z=pos.z-1} + local node1 = minetest.get_node(pos1) + local node2 = minetest.get_node(pos2) + local node3 = minetest.get_node(pos3) + local node4 = minetest.get_node(pos4) + local ndef1 = minetest.registered_nodes[node1.name] + local ndef2 = minetest.registered_nodes[node2.name] + local ndef3 = minetest.registered_nodes[node3.name] + local ndef4 = minetest.registered_nodes[node4.name] + + if ndef1 and ndef1.liquidtype == "flowing" and ndef2 and ndef2.liquidtype == "flowing" then + if node1.param2 > node2.param2 then + return 4 + elseif node1.param2 < node2.param2 then + return 2 + end + elseif ndef3 and ndef3.liquidtype == "flowing" and ndef4 and ndef4.liquidtype == "flowing" then + if node3.param2 > node4.param2 then + return 3 + elseif node3.param2 < node4.param2 then + return 1 + end + end +end + +local function remove_obj(obj) + if obj then + obj:remove() + end +end + +local function set_velocity(obj, pos, vel) + if obj then + obj:set_velocity(vel) + end +end + +local function add_object(pos, name) + local dir = determine_water_dir(pos) + if dir then + local obj = minetest.add_item(pos, ItemStack(name)) + local vel = vector.multiply(tubelib2.Dir6dToVector[dir], 0.3) + minetest.after(0.8, set_velocity, obj, pos, vel) + minetest.after(20, remove_obj, obj) + end +end + +local function washing(pos, trd, mem, inv) + local src = ItemStack("techage:sieved_gravel") + local dst = ItemStack("default:sand") + if inv:contains_item("src", src) then + if math.random(40) == 1 then + add_object({x=pos.x, y=pos.y+1, z=pos.z}, "techage:usmium_nuggets") + end + else + trd.State:idle(pos, mem) + return + end + if not inv:room_for_item("dst", dst) then + trd.State:idle(pos, mem) + return + end + inv:add_item("dst", dst) + inv:remove_item("src", src) + trd.State:keep_running(pos, mem, COUNTDOWN_TICKS) +end + +local function keep_running(pos, elapsed) + local mem = tubelib2.get_mem(pos) + local trd = TRD(pos) + local inv = M(pos):get_inventory() + washing(pos, trd, mem, inv) + return trd.State:is_active(mem) +end + +local function on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + local mem = tubelib2.get_mem(pos) + TRD(pos).State:state_button_event(pos, mem, fields) +end + +local function can_dig(pos, player) + if minetest.is_protected(pos, player:get_player_name()) then + return false + end + local inv = M(pos):get_inventory() + return inv:is_empty("dst") and inv:is_empty("src") +end + + +local tiles = {} +-- '#' will be replaced by the stage number +-- '{power}' will be replaced by the power PNG +tiles.pas = { + -- up, down, right, left, back, front + "techage_appl_rinser_top.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png", +} +tiles.act = { + -- up, down, right, left, back, front + { + image = "techage_appl_rinser4_top.png^techage_frame4_ta#_top.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0, + }, + }, + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png", +} +tiles.def = { + -- up, down, right, left, back, front + "techage_appl_rinser_top.png^techage_frame_ta#_top.png", + "techage_filling_ta#.png^techage_frame_ta#.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_outp.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_frame_ta#.png^techage_appl_inp.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png^techage_appl_defect.png", + "techage_filling_ta#.png^techage_appl_rinser.png^techage_frame_ta#.png^techage_appl_defect.png", +} + +local tubing = { + on_pull_item = function(pos, in_dir, num) + local meta = minetest.get_meta(pos) + if meta:get_int("pull_dir") == in_dir then + local inv = M(pos):get_inventory() + return techage.get_items(inv, "dst", num) + end + end, + on_push_item = function(pos, in_dir, stack) + local meta = minetest.get_meta(pos) + if meta:get_int("push_dir") == in_dir or in_dir == 5 then + local inv = M(pos):get_inventory() + return techage.put_items(inv, "src", stack) + end + end, + on_unpull_item = function(pos, in_dir, stack) + local meta = minetest.get_meta(pos) + if meta:get_int("pull_dir") == in_dir then + local inv = M(pos):get_inventory() + return techage.put_items(inv, "dst", stack) + end + end, + on_recv_message = function(pos, topic, payload) + local resp = TRD(pos).State:on_receive_message(pos, topic, payload) + if resp then + return resp + else + return "unsupported" + end + end, + on_node_load = function(pos) + TRD(pos).State:on_node_load(pos) + end, + on_node_repair = function(pos) + return TRD(pos).State:on_node_repair(pos) + end, +} + +local node_name_ta2, node_name_ta3, node_name_ta4 = + techage.register_consumer("rinser", I("Gravel Rinser"), tiles, { + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-8/16, -8/16, -8/16, 8/16, 8/16, -6/16}, + {-8/16, -8/16, 6/16, 8/16, 8/16, 8/16}, + {-8/16, -8/16, -8/16, -6/16, 8/16, 8/16}, + { 6/16, -8/16, -8/16, 8/16, 8/16, 8/16}, + {-6/16, -8/16, -6/16, 6/16, 6/16, 6/16}, + {-6/16, 6/16, -1/16, 6/16, 8/16, 1/16}, + {-1/16, 6/16, -6/16, 1/16, 8/16, 6/16}, + }, + }, + selection_box = { + type = "fixed", + fixed = {-8/16, -8/16, -8/16, 8/16, 8/16, 8/16}, + }, + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = true, + aging_factor = 10, + formspec = formspec, + tubing = tubing, + after_place_node = function(pos, placer) + local inv = M(pos):get_inventory() + inv:set_size('src', 9) + inv:set_size('dst', 9) + end, + can_dig = can_dig, + node_timer = keep_running, + on_receive_fields = on_receive_fields, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, + groups = {choppy=2, cracky=2, crumbly=2}, + sounds = default.node_sound_wood_defaults(), + num_items = {0,1,2,4}, + power_consumption = {0,3,4,5}, + }) + +minetest.register_craft({ + output = node_name_ta2, + recipe = { + {"group:wood", "default:mese_crystal", "group:wood"}, + {"techage:tubeS", "techage:sieve", "techage:tubeS"}, + {"group:wood", "default:tin_ingot", "group:wood"}, + }, +}) + + +if minetest.global_exists("unified_inventory") then + unified_inventory.register_craft_type("rinsing", { + description = I("Rinsing"), + icon = "techage_appl_rinser_top.png^techage_frame_ta2_top.png", + width = 2, + height = 2, + }) +end + +function techage.add_rinser_recipe(recipe) + if minetest.global_exists("unified_inventory") then + recipe.items = {recipe.input} + recipe.type = "rinsing" + unified_inventory.register_craft(recipe) + end +end + + +techage.add_rinser_recipe({input="techage:sieved_gravel", output="techage:usmium_nuggets"}) + +techage.register_help_page(I("TA2 Gravel Rinser"), +I([[Used to wash Sieved Gravel to get Usmium Nuggets. +The block has to be placed under flowing water. +The washed-out nuggets must be +sucked in with a Hopper.]]), "techage:ta2_rinser_pas") \ No newline at end of file diff --git a/basic_machines/gravelsieve.lua b/basic_machines/gravelsieve.lua index 9a87b34..8ff7e7a 100644 --- a/basic_machines/gravelsieve.lua +++ b/basic_machines/gravelsieve.lua @@ -247,3 +247,12 @@ minetest.register_craft({ {"group:wood", "techage:iron_ingot", "group:wood"}, }, }) + +minetest.register_craft({ + output = node_name_ta3, + recipe = { + {"", "default:mese_crystal", ""}, + {"", node_name_ta2, ""}, + {"", "techage:vacuum_tube", ""}, + }, +}) diff --git a/basic_machines/grinder.lua b/basic_machines/grinder.lua index 0f7d006..9504af6 100644 --- a/basic_machines/grinder.lua +++ b/basic_machines/grinder.lua @@ -260,6 +260,15 @@ minetest.register_craft({ }, }) +minetest.register_craft({ + output = node_name_ta3, + recipe = { + {"", "default:mese_crystal", ""}, + {"", node_name_ta2, ""}, + {"", "techage:vacuum_tube", ""}, + }, +}) + if minetest.global_exists("unified_inventory") then unified_inventory.register_craft_type("grinding", { description = I("Grinding"), diff --git a/basic_machines/pusher.lua b/basic_machines/pusher.lua index 082938c..3c10cf0 100644 --- a/basic_machines/pusher.lua +++ b/basic_machines/pusher.lua @@ -178,3 +178,12 @@ minetest.register_craft({ {"group:wood", "techage:iron_ingot", "group:wood"}, }, }) + +minetest.register_craft({ + output = node_name_ta3, + recipe = { + {"", "techage:iron_ingot", ""}, + {"", node_name_ta2, ""}, + {"", "techage:vacuum_tube", ""}, + }, +}) diff --git a/basis/gravel_lib.lua b/basis/gravel_lib.lua index cb2c1ad..829d90c 100644 --- a/basis/gravel_lib.lua +++ b/basis/gravel_lib.lua @@ -92,4 +92,3 @@ function techage.gravelsieve_get_random_basalt_ore() return ItemStack("techage:sieved_basalt_gravel") end end - diff --git a/basis/junction.lua b/basis/junction.lua index 143551d..8b1390f 100644 --- a/basis/junction.lua +++ b/basis/junction.lua @@ -50,20 +50,26 @@ end -- 'boxes' is a table with 6 table elements for the 6 possible connection arms -- 'network' is the tubelib2 instance -- 'node' is the node definition with tiles, callback functions, and so on +-- 'techage' is the power network definition function techage.register_junction(name, size, boxes, network, node) for idx = 0,63 do - node.groups.techage_trowel = 1 - node.groups.not_in_creative_inventory = idx - node.drawtype = "nodebox" - node.node_box = get_node_box(idx, size, boxes) - node.paramtype2 = "facedir" - node.on_rotate = screwdriver.disallow - node.paramtype = "light" - node.sunlight_propagates = true - node.is_ground_content = false - node.drop = name.."0" - - minetest.register_node(name..idx, table.copy(node)) + local node1 = table.copy(node) + node1.groups.techage_trowel = 1 + if idx == 0 then + node1.groups.not_in_creative_inventory = 0 + else + node1.groups.not_in_creative_inventory = 1 + end + node1.drawtype = "nodebox" + node1.node_box = get_node_box(idx, size, boxes) + node1.paramtype2 = "facedir" + node1.on_rotate = screwdriver.disallow + node1.paramtype = "light" + node1.sunlight_propagates = true + node1.is_ground_content = false + node1.drop = name.."0" + --node.techage = techage + minetest.register_node(name..idx, node1) network:add_secondary_node_names({name..idx}) end end diff --git a/basis/power.lua b/basis/power.lua index bbacfd3..5aebce4 100644 --- a/basis/power.lua +++ b/basis/power.lua @@ -50,6 +50,14 @@ function techage.get_pos(pos, side) return tubelib2.get_pos(pos, dir) end +-- Both nodes are from the same power network type? +local function matching_nodes(pos, peer_pos) + local tube_type1 = pos and TRD(pos) and TRD(pos).power_network.tube_type + local tube_type2 = peer_pos and TRD(peer_pos) and TRD(peer_pos).power_network.tube_type + print(tube_type1, tube_type2) + return not tube_type1 or not tube_type2 or tube_type1 == tube_type2 +end + local function get_power_dir(pos) local key = minetest.hash_node_position(pos) if not PowerInDir[key] then @@ -152,7 +160,7 @@ function techage.power.start_dedicated_node(pos, out_dir, node_name, sum) if trd and (not trd.valid_power_dir or trd.valid_power_dir(conn.pos, get_power_dir(conn.pos), conn.in_dir)) then if trd.turn_on then - return trd.turn_on(pos, conn.in_dir, sum) + return trd.turn_on(conn.pos, conn.in_dir, sum) end end end @@ -177,7 +185,7 @@ function techage.generator.after_tube_update(node, pos, out_dir, peer_pos, peer_ local mem = tubelib2.get_mem(pos) local pwr_dir = get_power_dir(pos) if tubelib2.Turn180Deg[out_dir] == pwr_dir then - if not peer_in_dir then + if not peer_in_dir or not matching_nodes(pos, peer_pos) then mem.connections = {} -- del connection else -- Generator accept one dir only @@ -230,7 +238,7 @@ end function techage.distributor.after_tube_update(node, pos, out_dir, peer_pos, peer_in_dir) local mem = tubelib2.get_mem(pos) mem.connections = mem.connections or {} - if not peer_in_dir then + if not peer_in_dir or not matching_nodes(pos, peer_pos) then mem.connections[out_dir] = nil -- del connection else mem.connections[out_dir] = {pos = peer_pos, in_dir = peer_in_dir} @@ -269,7 +277,7 @@ function techage.consumer.after_tube_update(node, pos, out_dir, peer_pos, peer_i local trd = TRD(pos) -- Check direction if not trd.valid_power_dir(pos, pwr_dir, tubelib2.Turn180Deg[out_dir]) then return end - if not peer_in_dir then + if not peer_in_dir or not matching_nodes(pos, peer_pos) then mem.connections[out_dir] = nil -- del connection else mem.connections[out_dir] = {pos = peer_pos, in_dir = peer_in_dir} diff --git a/coal_power_station/boiler_base.lua b/coal_power_station/boiler_base.lua index ad29c49..df7c691 100644 --- a/coal_power_station/boiler_base.lua +++ b/coal_power_station/boiler_base.lua @@ -22,8 +22,6 @@ local MP = minetest.get_modpath("techage") local I,_ = dofile(MP.."/intllib.lua") local POWER_CONSUMPTION = 2 -local STANDBY_TICKS = 4 -local CYCLE_TIME = 4 local Pipe = techage.SteamPipe local consumer = techage.consumer @@ -32,39 +30,10 @@ local function valid_power_dir(pos, power_dir, in_dir) return power_dir == in_dir end -local function start_node(pos, mem, state) - consumer.turn_power_on(pos, POWER_CONSUMPTION) -end - -local function stop_node(pos, mem, state) - consumer.turn_power_on(pos, 0) -end - -local State = techage.NodeStates:new({ - node_name_passive = "techage:coalboiler_base", - cycle_time = CYCLE_TIME, - standby_ticks = STANDBY_TICKS, - start_node = start_node, - stop_node = stop_node, -}) - local function turn_on_clbk(pos, in_dir, sum) - local mem = tubelib2.get_mem(pos) - local state = State:get_state(mem) - - if sum > 0 and state == techage.STOPPED then - State:start(pos, mem) - elseif sum <= 0 and state == techage.RUNNING then - State:stop(pos, mem) - end + return true end -local function node_timer(pos, elapsed) - print("node_timer") - local mem = tubelib2.get_mem(pos) - return State:is_active(mem) -end - minetest.register_node("techage:coalboiler_base", { description = I("TA3 Boiler Base"), tiles = {"techage_coal_boiler_mesh_base.png"}, @@ -85,17 +54,11 @@ minetest.register_node("techage:coalboiler_base", { after_place_node = function(pos, placer) local mem = consumer.after_place_node(pos, placer) - State:node_init(pos, mem, "") - State:start(pos, mem) - end, - - after_dig_node = function(pos, oldnode, oldmetadata, digger) - State:after_dig_node(pos, oldnode, oldmetadata, digger) - consumer.after_dig_node(pos, oldnode) + mem.power_consumption = POWER_CONSUMPTION end, after_tube_update = consumer.after_tube_update, - --on_timer = node_timer, + after_dig_node = consumer.after_dig_node, drop = "", paramtype2 = "facedir", diff --git a/coal_power_station/boiler_top.lua b/coal_power_station/boiler_top.lua index 4551cd8..08ec5ee 100644 --- a/coal_power_station/boiler_top.lua +++ b/coal_power_station/boiler_top.lua @@ -249,7 +249,6 @@ minetest.register_node("techage:coalboiler_top", { trigger_boiler = function(pos) local mem = tubelib2.get_mem(pos) mem.fire_trigger = true - print("trigger_boiler") if not minetest.get_node_timer(pos):is_started() then minetest.get_node_timer(pos):start(CYCLE_TIME) end diff --git a/coal_power_station/cooler.lua b/coal_power_station/cooler.lua index b281194..93ff3e5 100644 --- a/coal_power_station/cooler.lua +++ b/coal_power_station/cooler.lua @@ -22,8 +22,6 @@ local MP = minetest.get_modpath("techage") local I,_ = dofile(MP.."/intllib.lua") local POWER_CONSUMPTION = 2 -local STANDBY_TICKS = 4 -local CYCLE_TIME = 4 local Power = techage.SteamPipe local consumer = techage.consumer @@ -43,12 +41,18 @@ local function valid_power_dir(pos, power_dir, in_dir) end -- called from pipe network -local function turn_on(pos, dir, sum) - if sum > 0 then - swap_node(pos, "techage:cooler_on") +local function turn_on(pos, in_dir, sum) + if techage.power.start_dedicated_node(pos, in_dir, "techage:coalboiler_base", sum) then + if sum > 0 then + swap_node(pos, "techage:cooler_on") + else + swap_node(pos, "techage:cooler") + end + return true else swap_node(pos, "techage:cooler") end + return false end minetest.register_node("techage:cooler", { @@ -59,8 +63,8 @@ minetest.register_node("techage:cooler", { "techage_filling_ta3.png^techage_appl_cooler.png^techage_frame_ta3.png", "techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png", "techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png", - "techage_filling_ta3.png^techage_frame_ta3.png", - "techage_filling_ta3.png^techage_frame_ta3.png", + "techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png", + "techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png", }, techage = { turn_on = turn_on, @@ -111,8 +115,8 @@ minetest.register_node("techage:cooler_on", { }, "techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png", "techage_filling_ta3.png^techage_frame_ta3.png^techage_steam_hole.png", - "techage_filling_ta3.png^techage_frame_ta3.png", - "techage_filling_ta3.png^techage_frame_ta3.png", + "techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png", + "techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png", }, techage = { turn_on = turn_on, @@ -134,3 +138,15 @@ minetest.register_node("techage:cooler_on", { }) Power:add_secondary_node_names({"techage:cooler", "techage:cooler_on"}) + + +techage.register_help_page(I("TA3 Cooler"), +I([[Part of the steam engine. +Has to be placed on top of the Firebox +and filled with water. +(see TA2 Steam Engine)]]), "techage:boiler1") + +techage.register_help_page(I("TA2 Boiler Top"), +I([[Part of the steam engine. +Has to be placed on top of TA2 Boiler Base. +(see TA2 Steam Engine)]]), "techage:boiler2") \ No newline at end of file diff --git a/coal_power_station/firebox.lua b/coal_power_station/firebox.lua index 2b5ddf3..06c5ee6 100644 --- a/coal_power_station/firebox.lua +++ b/coal_power_station/firebox.lua @@ -185,7 +185,7 @@ minetest.register_craft({ }, }) -techage.register_node("techage:firebox", {"techage:firebox_on"}, { +techage.register_node("techage:coalfirebox", {}, { on_push_item = function(pos, in_dir, stack) local meta = minetest.get_meta(pos) local inv = meta:get_inventory() @@ -197,3 +197,14 @@ techage.register_node("techage:firebox", {"techage:firebox_on"}, { return false end, }) + +minetest.register_lbm({ + label = "[techage] Steam engine firebox", + name = "techage:steam_engine", + nodenames = {"techage:coalfirebox"}, + run_at_every_load = true, + action = function(pos, node) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end +}) + diff --git a/coal_power_station/generator.lua b/coal_power_station/generator.lua index 41eef87..5613ef6 100644 --- a/coal_power_station/generator.lua +++ b/coal_power_station/generator.lua @@ -43,29 +43,19 @@ local function formspec(self, pos, mem) default.get_hotbar_bg(0, 3) end -local function start_turbine(pos, on, mem) - local pos2 = techage.get_pos(pos, 'L') - local trd = TRD(pos2) - if trd and trd.start_turbine then - return trd.start_turbine(pos2, on, mem) - end - return false +local function turbine_running(pos) + local pos1 = techage.get_pos(pos, 'L') + local node = minetest.get_node(pos1) + return node.name == "techage:turbine_on" end -local function can_start(pos, mem, state) - return start_turbine(pos, true, mem) -end - - local function start_node(pos, mem, state) generator.turn_power_on(pos, POWER_CAPACITY) mem.techage_state = techage.RUNNING - play_sound(pos) end local function stop_node(pos, mem, state) mem.techage_state = techage.STOPPED - start_turbine(pos, false, mem) generator.turn_power_on(pos, 0) end @@ -75,7 +65,7 @@ local State = techage.NodeStates:new({ cycle_time = CYCLE_TIME, standby_ticks = STANDBY_TICKS, formspec_func = formspec, - can_start = can_start, + can_start = turbine_running, start_node = start_node, stop_node = stop_node, }) @@ -85,19 +75,16 @@ local function distibuting(pos, mem) State:keep_running(pos, mem, COUNTDOWN_TICKS) else State:fault(pos, mem) - start_turbine(pos, false, mem) generator.turn_power_on(pos, 0) end end local function node_timer(pos, elapsed) local mem = tubelib2.get_mem(pos) - local pos2 = techage.get_pos(pos, 'L') - if minetest.get_node(pos2).name == "techage:turbine_on" and tubelib2.get_mem(pos2).running then + if turbine_running(pos) then distibuting(pos, mem) else State:fault(pos, mem) - start_turbine(pos, false, mem) generator.turn_power_on(pos, 0) end return State:is_active(mem) @@ -113,7 +100,6 @@ local function turn_power_on(pos, in_dir, sum) mem.power_result = sum if State:is_active(mem) and sum <= 0 then State:fault(pos, mem) - start_turbine(pos, false, mem) -- No automatic turn on mem.power_capacity = 0 end @@ -153,7 +139,6 @@ minetest.register_node("techage:generator", { read_power_consumption = generator.read_power_consumption, power_network = Cable, power_side = "R", - animated_power_network = true, }, after_place_node = function(pos, placer) @@ -214,7 +199,6 @@ minetest.register_node("techage:generator_on", { read_power_consumption = generator.read_power_consumption, power_network = Cable, power_side = "R", - animated_power_network = true, }, after_dig_node = function(pos, oldnode, oldmetadata, digger) @@ -244,6 +228,7 @@ minetest.register_craft({ }, }) +Cable:add_secondary_node_names({"techage:generator", "techage:generator_on"}) techage.register_help_page(I("TA3 Generator"), I([[Part of the Coal Power Station. diff --git a/coal_power_station/help.lua b/coal_power_station/help.lua new file mode 100644 index 0000000..64d363e --- /dev/null +++ b/coal_power_station/help.lua @@ -0,0 +1,54 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + TA3 Coal Power Station Help + +]]-- + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +techage.register_chap_page(S("Electrical Age (TA3)"), S([[The Electrical Age is the third level of the available technic stages. +The goal of TA3 is build a Coal Power Station and machines +to produce ores and chips for smart devices and machines in TA4.]]), "techage:wlanchip") + +local HelpText = S([[1. Build a Coal Power Station according +to the plan with TA3 Firebox, TA3 Boiler, +Steam Pipes, TA3 Cooler, Turbine and Generator. +2. Heat the Firebox with coal/charcoal +3. Fill the boiler with water (more than one bucket is needed) +4. Wait until the water is heated +5. Open the steam ventil +6. Start the Generator +7. Connect the Generator with your machines by means of cables and junction boxes]]) + +local Images = { + + {false, false, false, false, false, false, false}, + {"techage_steam_knee.png", 'techage_steam_pipe.png', 'techage_steam_pipe.png', + 'techage_steam_pipe.png', 'techage_steam_pipe.png', 'techage_steam_pipe.png', "techage_steam_knee.png^[transformR270"}, + {'techage_steam_pipe.png^[transformR90', "techage_boiler_top_ta3.png", 'techage_steam_pipe.png', + 'techage_steam_knee.png^[transformR270', 'techage_steam_knee.png', + "techage_filling_ta3.png^techage_frame_ta3.png^techage_cooler.png", + "techage_steam_knee.png^[transformR180"}, + {"techage_steam_knee.png^[transformR90", "techage_boiler_bottom_ta3.png", false, 'techage_steam_pipe.png^[transformR90', + 'techage_steam_pipe.png^[transformR90'}, + {false, "techage_firebox_ta3.png", false, "techage_steam_knee.png^[transformR90", + "techage_filling_ta3.png^techage_appl_turbine.png^techage_frame_ta3.png", + "techage_filling_ta3.png^techage_frame_ta3.png^techage_appl_generator.png"}, +} + +techage.register_help_page("Coal Power Station", HelpText, nil, Images) + + +techage.register_help_page(S("TA3 Electronic Fab"), +S([[Used to produce WLAN Chips, +needed for TA4 machines.]]), "techage:ta3_electronic_fab_pas") diff --git a/init.lua b/init.lua index 989da92..f17317d 100644 --- a/init.lua +++ b/init.lua @@ -8,6 +8,8 @@ elseif minetest.global_exists("ironage") then minetest.log("error", "[techage] Techage can't be used together with the mod ironage!") elseif minetest.global_exists("techpack") then minetest.log("error", "[techage] Techage can't be used together with the modpack techpack!") +elseif minetest.global_exists("tubelib2") and tubelib2.version < 1.4 then + minetest.log("error", "[techage] Techage requires tubelib2 version 1.4 or newer!") else techage.max_num_forceload_blocks = tonumber(minetest.setting_get("techage_max_num_forceload_blocks")) or 12 techage.basalt_stone_enabled = minetest.setting_get("techage_basalt_stone_enabled") == "true" @@ -34,15 +36,16 @@ else -- Tools dofile(MP.."/tools/trowel.lua") - --dofile(MP.."/tools/repairkit.lua") + dofile(MP.."/tools/repairkit.lua") -- Nodes dofile(MP.."/nodes/baborium.lua") + dofile(MP.."/nodes/usmium.lua") -- Power networks dofile(MP.."/power/drive_axle.lua") dofile(MP.."/power/steam_pipe.lua") - dofile(MP.."/power/biogas_pipe.lua") + --dofile(MP.."/power/biogas_pipe.lua") dofile(MP.."/power/electric_cable.lua") -- Iron Age @@ -77,6 +80,7 @@ else dofile(MP.."/basic_machines/grinder.lua") dofile(MP.."/basic_machines/distributor.lua") dofile(MP.."/basic_machines/gravelsieve.lua") + dofile(MP.."/basic_machines/gravelrinser.lua") dofile(MP.."/basic_machines/chest.lua") dofile(MP.."/basic_machines/autocrafter.lua") dofile(MP.."/basic_machines/mark.lua") @@ -87,6 +91,7 @@ else end -- Coal power station + dofile(MP.."/coal_power_station/help.lua") dofile(MP.."/coal_power_station/firebox.lua") dofile(MP.."/coal_power_station/boiler_base.lua") dofile(MP.."/coal_power_station/boiler_top.lua") @@ -95,11 +100,12 @@ else dofile(MP.."/coal_power_station/cooler.lua") - --dofile(MP.."/test/battery.lua") - --dofile(MP.."/test/test.lua") + dofile(MP.."/test/lamp.lua") dofile(MP.."/test/generator.lua") - --dofile(MP.."/test/consumer.lua") +-- dofile(MP.."/test/consumer.lua") --dofile(MP.."/test/consumer2.lua") + --dofile(MP.."/test/test.lua") + --dofile(MP.."/test/battery.lua") --dofile(MP.."/fermenter/gasflare.lua") diff --git a/iron_age/coalburner.lua b/iron_age/coalburner.lua index 23a145e..83235e1 100644 --- a/iron_age/coalburner.lua +++ b/iron_age/coalburner.lua @@ -72,13 +72,11 @@ local function remove_flame(pos, height) end end -local function calc_num_coal(meta) - local t = minetest.get_gametime() - meta:get_int("ignite") - local num = meta:get_int("height") - t = t - COAL_BURN_TIME - if t > 0 then - local x = (COAL_BURN_TIME * 0.2) / num - num = math.max(num - math.floor(t/x), 0) +local function calc_num_coal(height, burn_time) + local num = height + if burn_time < 0 then + local x = (COAL_BURN_TIME * 0.2) / height + num = math.max(height + math.floor(burn_time/x), 0) end return num end @@ -173,7 +171,8 @@ function techage.start_burner(pos, playername) end if num_cobble(pos, height) == height * 8 then local meta = minetest.get_meta(pos) - meta:set_int("ignite", minetest.get_gametime()) + --meta:set_int("ignite", minetest.get_gametime()) + meta:set_int("burn_time", COAL_BURN_TIME) meta:set_int("height", height) start_burner(pos, height) flame(pos, height, height, true) @@ -196,33 +195,40 @@ function techage.keep_running_burner(pos) minetest.sound_stop(handle) meta:set_int("handle", 0) end - if num_cobble(pos, height) == height * 8 then - local num = calc_num_coal(meta) - if num > 0 then - if num_air(pos) == 0 then - -- pause the burner - meta:set_int("ignite", meta:get_int("ignite") + CYCLE_TIME) - meta:set_int("paused", 1) - return true - end - if meta:get_int("paused") == 1 then - flame(pos, height, num, true) - meta:set_int("paused", 0) + local burn_time = meta:get_int("burn_time") + print("keep_running_burner", burn_time) + -- burner hole is open + if num_air(pos) == 1 then + meta:set_int("burn_time", burn_time - CYCLE_TIME) + -- tower intact + if num_cobble(pos, height) == height * 8 then + local num_coal = calc_num_coal(height, burn_time) + print("num_coal", num_coal) + if num_coal > 0 then + if meta:get_int("paused") == 1 then + flame(pos, height, num_coal, true) + meta:set_int("paused", 0) + else + flame(pos, height, num_coal, false) + end + handle = minetest.sound_play("techage_gasflare", { + pos = {x=pos.x, y=pos.y+height, z=pos.z}, + max_hear_distance = 32, + gain = num_coal/12.0, + loop = true}) + meta:set_int("handle", handle) else - flame(pos, height, num, false) + minetest.swap_node(pos, {name="techage:ash"}) + remove_coal(pos, height) + return false end - handle = minetest.sound_play("techage_gasflare", { - pos = {x=pos.x, y=pos.y+height, z=pos.z}, - max_hear_distance = 32, - gain = num/12.0, - loop = true}) - meta:set_int("handle", handle) else minetest.swap_node(pos, {name="techage:ash"}) remove_coal(pos, height) return false end - return true + else + meta:set_int("paused", 1) end return true end @@ -234,6 +240,7 @@ function techage.stop_burner(pos) remove_coal(pos, height) local handle = meta:get_int("handle") minetest.sound_stop(handle) + meta:set_int("burn_time", 0) end diff --git a/iron_age/lighter.lua b/iron_age/lighter.lua index 01e1660..25efa69 100644 --- a/iron_age/lighter.lua +++ b/iron_age/lighter.lua @@ -34,7 +34,7 @@ minetest.register_node("techage:lighter_burn", { drop = "", light_source = 10, is_ground_content = false, - groups = {crumbly = 2, not_in_creative_inventory=1}, + groups = {crumbly = 1, not_in_creative_inventory=1}, sounds = default.node_sound_dirt_defaults(), }) @@ -58,7 +58,7 @@ minetest.register_node("techage:coal_lighter_burn", { drop = "", light_source = 10, is_ground_content = false, - groups = {not_in_creative_inventory=1}, + groups = {crumbly = 1, not_in_creative_inventory=1}, sounds = default.node_sound_dirt_defaults(), }) @@ -77,7 +77,7 @@ minetest.register_node("techage:lighter", { meta:set_string("playername", placer:get_player_name()) end, is_ground_content = false, - groups = {crumbly = 2, flammable = 2}, + groups = {crumbly = 1, flammable = 2}, sounds = default.node_sound_dirt_defaults(), }) diff --git a/nodes/usmium.lua b/nodes/usmium.lua new file mode 100644 index 0000000..cfecf94 --- /dev/null +++ b/nodes/usmium.lua @@ -0,0 +1,19 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Usminum + +]]-- + +minetest.register_craftitem("techage:usmium_nuggets", { + description = "Usmium Nuggets", + inventory_image = "techage_usmium_nuggets.png", +}) + diff --git a/power/biogas_pipe.lua b/power/biogas_pipe.lua index 1550fc4..01f0f45 100644 --- a/power/biogas_pipe.lua +++ b/power/biogas_pipe.lua @@ -26,6 +26,7 @@ local Pipe = tubelib2.Tube:new({ dirs_to_check = {1,2,3,4,5,6}, max_tube_length = 1000, show_infotext = false, + tube_type = "biogas_pipe", primary_node_names = {"techage:biogas_pipeS", "techage:biogas_pipeA"}, secondary_node_names = {"techage:gasflare", "techage:compressor"}, after_place_tube = function(pos, param2, tube_type, num_tubes, tbl) diff --git a/power/drive_axle.lua b/power/drive_axle.lua index 2aa4eee..2f5502c 100644 --- a/power/drive_axle.lua +++ b/power/drive_axle.lua @@ -24,8 +24,9 @@ local I,_ = dofile(MP.."/intllib.lua") local Axle = tubelib2.Tube:new({ dirs_to_check = {1,2,3,4,5,6}, - max_tube_length = 5, + max_tube_length = 8, show_infotext = false, + tube_type = "axle", primary_node_names = {"techage:axle", "techage:axle_on"}, secondary_node_names = {"techage:flywheel", "techage:flywheel_on", "techage:gearbox", "techage:gearbox_on"}, after_place_tube = function(pos, param2, tube_type, num_tubes, state) diff --git a/power/electric_cable.lua b/power/electric_cable.lua index 09c20fc..379d8b5 100644 --- a/power/electric_cable.lua +++ b/power/electric_cable.lua @@ -26,9 +26,9 @@ local Cable = tubelib2.Tube:new({ max_tube_length = 1000, show_infotext = false, force_to_use_tubes = true, + tube_type = "electric_cable", primary_node_names = {"techage:electric_cableS", "techage:electric_cableA"}, - secondary_node_names = {"techage:lamp", "techage:lamp_on", "techage:power", "techage:generator", - "techage:ele_consumer", "techage:ele_consumer_on"}, + secondary_node_names = {}, after_place_tube = function(pos, param2, tube_type, num_tubes) minetest.swap_node(pos, {name = "techage:electric_cable"..tube_type, param2 = param2 % 32}) M(pos):set_int("tl2_param2", param2) @@ -53,7 +53,7 @@ end) minetest.register_node("techage:electric_cableS", { - description = I("TA4 Electric Cable"), + description = I("TA Electric Cable"), tiles = { -- up, down, right, left, back, front "techage_electric_cable.png", @@ -96,7 +96,7 @@ minetest.register_node("techage:electric_cableS", { }) minetest.register_node("techage:electric_cableA", { - description = I("TA4 Electric Cable"), + description = I("TA Electric Cable"), tiles = { -- up, down, right, left, back, front "techage_electric_cable.png", @@ -147,15 +147,16 @@ local Boxes = { {{-size, -size, -size, size, 0.5, size}}, -- y+ } -techage.register_junction("techage:electric_junction", 2/8, Boxes, techage.ElectricCable, { - description = I("TA4 Electricity Junction Box"), +techage.register_junction("techage:electric_junction", 2/8, Boxes, Cable, { + description = I("TA Electricity Junction Box"), tiles = {"techage_electric_junction.png"}, groups = {snappy = 2, choppy = 2, oddly_breakable_by_hand = 3, techage_trowel = 1}, sounds = default.node_sound_defaults(), techage = { + read_power_consumption = distributor.read_power_consumption, power_network = techage.ElectricCable, + power_consumption = 0, }, - after_place_node = distributor.after_place_node, after_dig_node = distributor.after_dig_node, @@ -165,4 +166,22 @@ techage.register_junction("techage:electric_junction", 2/8, Boxes, techage.Elect local name = "techage:electric_junction"..techage.junction_type(mem.connections) minetest.swap_node(pos, {name = name, param2 = 0}) end, + }) + +minetest.register_craft({ + output = "techage:electric_cableS 6", + recipe = { + {"basic_materials:plastic_sheet", "", ""}, + {"", "default:copper_ingot", ""}, + {"", "", "basic_materials:plastic_sheet"}, + }, +}) + +minetest.register_craft({ + output = "techage:electric_junction0 2", + recipe = { + {"", "basic_materials:plastic_sheet", ""}, + {"basic_materials:plastic_sheet", "default:copper_ingot", "basic_materials:plastic_sheet"}, + {"", "basic_materials:plastic_sheet", ""}, + }, }) diff --git a/power/steam_pipe.lua b/power/steam_pipe.lua index 16d42ec..6067ce2 100644 --- a/power/steam_pipe.lua +++ b/power/steam_pipe.lua @@ -24,9 +24,10 @@ local I,_ = dofile(MP.."/intllib.lua") local Pipe = tubelib2.Tube:new({ dirs_to_check = {1,2,3,4,5,6}, - max_tube_length = 6, + max_tube_length = 12, show_infotext = false, force_to_use_tubes = true, + tube_type = "steam_pipe", primary_node_names = {"techage:steam_pipeS", "techage:steam_pipeA"}, secondary_node_names = {"techage:cylinder", "techage:cylinder_on", "techage:boiler2"}, after_place_tube = function(pos, param2, tube_type, num_tubes) diff --git a/steam_engine/flywheel.lua b/steam_engine/flywheel.lua index 6e96697..913f4e9 100644 --- a/steam_engine/flywheel.lua +++ b/steam_engine/flywheel.lua @@ -26,7 +26,7 @@ local I,_ = dofile(MP.."/intllib.lua") local STANDBY_TICKS = 4 local COUNTDOWN_TICKS = 4 local CYCLE_TIME = 8 -local POWER_CAPACITY = 20 +local POWER_CAPACITY = 25 local Axle = techage.Axle local generator = techage.generator diff --git a/steam_engine/help.lua b/steam_engine/help.lua index 8fb0cb3..9cbfc07 100644 --- a/steam_engine/help.lua +++ b/steam_engine/help.lua @@ -21,7 +21,7 @@ The goal of TA2 is build a steam engine and machines to produce ores and vacuum tubes for the first electronic devices and machines in TA3.]]), "techage:vacuum_tube") -local HelpText = S([[1. Build a steam machine according +local HelpText = S([[1. Build a steam engine according to the plan with TA2 Firebox, TA2 Boiler, Steam Pipes, TA2 Cyclinder and TA2 Flywheel. 2. Heat the Firebox with coal/charcoal @@ -44,6 +44,6 @@ local Images = { "techage_filling_ta2.png^techage_frame_ta2.png^techage_flywheel.png^[transformFX]"}, } -techage.register_help_page("Steam Machine", HelpText, nil, Images) +techage.register_help_page("Steam Engine", HelpText, nil, Images) diff --git a/test/consumer.lua b/test/consumer.lua index 7a94db0..535d341 100644 --- a/test/consumer.lua +++ b/test/consumer.lua @@ -59,7 +59,6 @@ local function lamp_turn_on_clbk(pos, in_dir, sum) end local function node_timer(pos, elapsed) - print("node_timer") local mem = tubelib2.get_mem(pos) return State:is_active(mem) end diff --git a/steam_engine/consumer.lua b/test/consumer2.lua similarity index 100% rename from steam_engine/consumer.lua rename to test/consumer2.lua diff --git a/test/generator.lua b/test/generator.lua index b8e84b2..c64ebff 100644 --- a/test/generator.lua +++ b/test/generator.lua @@ -12,8 +12,8 @@ local COUNTDOWN_TICKS = 4 local CYCLE_TIME = 16 local POWER_CAPACITY = 30 ---local Power = techage.ElectricCable -local Power = techage.SteamPipe +local Power = techage.ElectricCable +--local Power = techage.SteamPipe local generator = techage.generator local function formspec(self, pos, mem) @@ -47,7 +47,6 @@ local State = techage.NodeStates:new({ local function node_timer(pos, elapsed) - print("node_timer") local mem = tubelib2.get_mem(pos) return State:is_active(mem) end diff --git a/test/lamp.lua b/test/lamp.lua new file mode 100644 index 0000000..580d54c --- /dev/null +++ b/test/lamp.lua @@ -0,0 +1,120 @@ +-- for lazy programmers +local S = function(pos) if pos then return minetest.pos_to_string(pos) end end +local P = minetest.string_to_pos +local M = minetest.get_meta + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local I,_ = dofile(MP.."/intllib.lua") + +local POWER_CONSUMPTION = 2 + +local Power = techage.ElectricCable +local consumer = techage.consumer + +local function swap_node(pos, name) + local node = minetest.get_node(pos) + if node.name == name then + return + end + node.name = name + minetest.swap_node(pos, node) +end + +-- called from pipe network +local function valid_power_dir(pos, power_dir, in_dir) + print("valid_power_dir", power_dir, in_dir) + return true +end + +local function lamp_turn_on_clbk(pos, in_dir, sum) + local mem = tubelib2.get_mem(pos) + print("lamp_turn_on_clbk", sum, dump(mem)) + if sum > 0 and mem.running then + swap_node(pos, "techage:test_lamp_on") + else + swap_node(pos, "techage:test_lamp") + end +end + +local function lamp_on_rightclick(pos, node, clicker) + local mem = tubelib2.get_mem(pos) + print("lamp_on_rightclick", dump(mem)) + if not mem.running then + swap_node(pos, "techage:test_lamp_on") + mem.running = true + M(pos):set_string("infotext", "On") + consumer.turn_power_on(pos, POWER_CONSUMPTION) + else + swap_node(pos, "techage:test_lamp") + mem.running = false + M(pos):set_string("infotext", "Off") + consumer.turn_power_on(pos, 0) + end +end + +minetest.register_node("techage:test_lamp", { + description = "TechAge Lamp", + tiles = { + -- up, down, right, left, back, front + 'techage_electric_button.png', + 'techage_electric_button.png', + 'techage_electric_button.png', + 'techage_electric_button.png', + 'techage_electric_button.png', + 'techage_electric_button.png', + }, + techage = { + turn_on = lamp_turn_on_clbk, + read_power_consumption = consumer.read_power_consumption, + power_network = Power, + power_side = "L", + valid_power_dir = valid_power_dir, + }, + + after_place_node = function(pos, placer) + local mem = consumer.after_place_node(pos, placer) + mem.power_consumption = POWER_CONSUMPTION + end, + + after_tube_update = consumer.after_tube_update, + after_dig_node = consumer.after_dig_node, + on_rightclick = lamp_on_rightclick, + + paramtype = "light", + light_source = 0, + sunlight_propagates = true, + paramtype2 = "facedir", + groups = {choppy=2, cracky=2, crumbly=2}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node("techage:test_lamp_on", { + description = "TechAge Lamp", + tiles = { + 'techage_electric_button.png', + }, + techage = { + turn_on = lamp_turn_on_clbk, + read_power_consumption = consumer.read_power_consumption, + power_network = Power, + power_side = "L", + valid_power_dir = valid_power_dir, + }, + + after_tube_update = consumer.after_tube_update, + after_dig_node = consumer.after_dig_node, + on_rightclick = lamp_on_rightclick, + + paramtype = "light", + light_source = LIGHT_MAX, + sunlight_propagates = true, + paramtype2 = "facedir", + drop = "techage:test_lamp", + groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +Power:add_secondary_node_names({"techage:test_lamp", "techage:test_lamp_on"}) diff --git a/test/test.lua b/test/test.lua index 5b2d7c1..794cc43 100644 --- a/test/test.lua +++ b/test/test.lua @@ -3,164 +3,93 @@ local S = function(pos) if pos then return minetest.pos_to_string(pos) end end local P = minetest.string_to_pos local M = minetest.get_meta -local POWER_CONSUMPTION = 2 -local POWER_CAPACITY = 8 - - -local Cable = techage.ElectricCable -local consumer = techage.consumer -local generator = techage.generator - -local function swap_node(pos, name) - local node = minetest.get_node(pos) - if node.name == name then - return +local function determine_water_dir(pos) + local pos1 = {x=pos.x+1, y=pos.y+1, z=pos.z} + local pos2 = {x=pos.x-1, y=pos.y+1, z=pos.z} + local pos3 = {x=pos.x, y=pos.y+1, z=pos.z+1} + local pos4 = {x=pos.x, y=pos.y+1, z=pos.z-1} + local node1 = minetest.get_node(pos1) + local node2 = minetest.get_node(pos2) + local node3 = minetest.get_node(pos3) + local node4 = minetest.get_node(pos4) + if node1.name == "default:water_flowing" and node2.name == "default:water_flowing" then + if node1.param2 > node2.param2 then + return 4 + elseif node1.param2 < node2.param2 then + return 2 + end + elseif node3.name == "default:water_flowing" and node4.name == "default:water_flowing" then + if node3.param2 > node4.param2 then + return 3 + elseif node3.param2 < node4.param2 then + return 1 + end end - node.name = name - minetest.swap_node(pos, node) + return 0 end -local function valid_power_dir(pos, power_dir, in_dir) - --print("valid_power_dir", power_dir, in_dir) +local function remove(obj) + obj:remove() +end + +local function velocity(obj, dir) + obj:set_velocity(vector.multiply(tubelib2.Dir6dToVector[dir], 0.3)) + minetest.after(10, remove, obj) +end + +local function node_timer(pos, elapsed) + local node = minetest.get_node(techage.get_pos(pos, 'U')) + local obj = minetest.add_item({x=pos.x, y=pos.y+1, z=pos.z}, ItemStack("default:gold_lump")) + minetest.after(0.8, velocity, obj, M(pos):get_int("water_dir")) return true end -local function lamp_turn_on_clbk(pos, in_dir, sum) - local mem = tubelib2.get_mem(pos) - if sum > 0 and mem.running then - swap_node(pos, "techage:lamp_on") - else - swap_node(pos, "techage:lamp") - end -end - -local function lamp_on_rightclick(pos, node, clicker) - local mem = tubelib2.get_mem(pos) - if not mem.running then - swap_node(pos, "techage:lamp_on") - mem.running = true - M(pos):set_string("infotext", "On") - consumer.turn_power_on(pos, POWER_CONSUMPTION) - else - swap_node(pos, "techage:lamp") - mem.running = false - M(pos):set_string("infotext", "Off") - consumer.turn_power_on(pos, 0) - end -end - -minetest.register_node("techage:lamp", { - description = "TechAge Lamp", +minetest.register_node("techage:rinser", { + description = "TechAge Rinser", tiles = { -- up, down, right, left, back, front + { + image = "techage_appl_sieve4_top.png^techage_frame4_ta2_top.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 2.0, + }, + }, 'techage_electric_button.png', - 'techage_electric_button.png', - 'techage_electric_button.png', - 'techage_electric_button.png', - 'techage_electric_button.png', - 'techage_electric_button.png', - }, - techage = { - turn_on = lamp_turn_on_clbk, - read_power_consumption = consumer.read_power_consumption, - power_network = Cable, - power_side = "L", - valid_power_dir = valid_power_dir, - }, - - after_place_node = consumer.after_place_node, - after_tube_update = consumer.after_tube_update, - after_dig_node = consumer.after_dig_node, - on_rightclick = lamp_on_rightclick, - - paramtype = "light", - light_source = 0, - sunlight_propagates = true, - paramtype2 = "facedir", - groups = {choppy=2, cracky=2, crumbly=2}, - is_ground_content = false, - sounds = default.node_sound_wood_defaults(), -}) - -minetest.register_node("techage:lamp_on", { - description = "TechAge Lamp", - tiles = { - 'techage_electric_button.png', - }, - techage = { - turn_on = lamp_turn_on_clbk, - read_power_consumption = consumer.read_power_consumption, - power_network = Cable, - valid_power_dir = valid_power_dir, - }, - - after_tube_update = consumer.after_tube_update, - after_dig_node = consumer.after_dig_node, - on_rightclick = lamp_on_rightclick, - - paramtype = "light", - light_source = LIGHT_MAX, - sunlight_propagates = true, - paramtype2 = "facedir", - drop = "techage:lamp", - groups = {choppy=2, cracky=2, crumbly=2, not_in_creative_inventory=1}, - is_ground_content = false, - sounds = default.node_sound_wood_defaults(), -}) - -------------------------------------------------------------------------------- -------------------------------------------------------------------------------- -local function generator_turn_on_clbk(pos, in_dir, sum) - print("generator_turn_on_clbk") - local mem = tubelib2.get_mem(pos) - if sum > 0 then - -- No automatic turn on - elseif mem.running == true then - M(pos):set_string("infotext", "Err: "..sum.." / "..8) - mem.running = false - mem.power_capacity = 0 - end -end - -local function generator_on_rightclick(pos, node, clicker) - local mem = tubelib2.get_mem(pos) - if not mem.running then - mem.running = true - M(pos):set_string("infotext", "On") - generator.turn_power_on(pos, POWER_CAPACITY) - else - generator.turn_power_on(pos, 0) - mem.running = false - M(pos):set_string("infotext", "Off") - end -end - -minetest.register_node("techage:power", { - description = "TechAge Power", - tiles = { - -- up, down, right, left, back, front - 'techage_electric_button.png^techage_electric_power.png', - 'techage_electric_button.png^techage_electric_power.png', - 'techage_electric_button.png^techage_electric_power.png^techage_electric_plug.png', - 'techage_electric_button.png^techage_electric_power.png', - 'techage_electric_button.png^techage_electric_power.png', - 'techage_electric_button.png^techage_electric_power.png', }, paramtype2 = "facedir", groups = {cracky=2, crumbly=2, choppy=2}, on_rotate = screwdriver.disallow, is_ground_content = false, - techage = { - turn_on = generator_turn_on_clbk, - read_power_consumption = generator.read_power_consumption, - power_network = Cable, - power_side = "R", - }, - - after_place_node = generator.after_place_node, - after_tube_update = generator.after_tube_update, - after_dig_node = generator.after_dig_node, - on_rightclick = generator_on_rightclick, + after_place_node = function(pos, placer) + minetest.get_node_timer(pos):start(5) + local dir = determine_water_dir(pos) + M(pos):set_int("water_dir", dir) + end, + + on_timer = node_timer, +}) + +local function remove_objects(pos) + for _, object in pairs(minetest.get_objects_inside_radius(pos, 1)) do + local lua_entity = object:get_luaentity() + if not object:is_player() and lua_entity and lua_entity.name == "__builtin:item" then + object:remove() + end + end +end + +minetest.register_lbm({ + label = "[techage] Rinser update", + name = "techage:update", + nodenames = {"techage:rinser"}, + run_at_every_load = true, + action = function(pos, node) + remove_objects({x=pos.x, y=pos.y+1, z=pos.z}) + end }) diff --git a/textures/techage_appl_rinser.png b/textures/techage_appl_rinser.png new file mode 100644 index 0000000000000000000000000000000000000000..ec8490f12ddd5205ad2fc008d3d3ec87234e3bc8 GIT binary patch literal 230 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnH3?%tPCZz)@mUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIBh0X`wFKADA1PELu5i9msQyM%9o6qN+|1v5B2yO9Rua29w(7Bet#3xhBt z!>lsljp&`(sV7w!2Ef+5@gV78Jo(XSx6xbqmU(?zkbc%uD-!#$8*>5Fp Q18rdNboFyt=akR{0Qko}r~m)} literal 0 HcmV?d00001 diff --git a/textures/techage_appl_rinser4_top.png b/textures/techage_appl_rinser4_top.png new file mode 100644 index 0000000000000000000000000000000000000000..b1dba29a77f341296736d81a2d4f018855dc6248 GIT binary patch literal 2591 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 B>8}6) literal 0 HcmV?d00001 diff --git a/textures/techage_appl_rinser_top.png b/textures/techage_appl_rinser_top.png new file mode 100644 index 0000000000000000000000000000000000000000..12be28f6acdaa2e4f3f9d6dea69723da1b2f1a78 GIT binary patch literal 704 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 KMNUMnLSTZ`tZ$eA literal 0 HcmV?d00001 diff --git a/textures/techage_cooler.png b/textures/techage_cooler.png new file mode 100644 index 0000000000000000000000000000000000000000..686cf30e383be9cf58da169e646f7fb1f17e934d GIT binary patch literal 1176 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 Eg3y8Nxc~qF literal 0 HcmV?d00001 diff --git a/textures/techage_repairkit.png b/textures/techage_repairkit.png new file mode 100644 index 0000000000000000000000000000000000000000..8215c46437776e9d487f135025b9332852873f23 GIT binary patch literal 649 zcmV;40(Sk0P)OrzHT0004WQchC)7y#u37GtOgU;;#FN|6B}cZm)tgi!ne zNI%E`%ml_iSO7T%j6XyZU@2z#jMxDB10}`K_g5wo>u;J!WDKyUTL67;9iaMaIZ*xk zfL`*9eW3a)o!I!}MgZ~WgAf5E{;g#s1;7ncnJ*wukY^%o0JOKV&;ZDkv$LI<20+@8 z(smZsA-yB6HnNSF1=HEi(hmvRMp}s=@cpF&g4lX!8S8l^1o0a+_JKU6)J{Zk0wo3e jP~H2Z`3C@(>#)87YmU*-N6@+M00000NkvXXu0mjf(_#LP literal 0 HcmV?d00001 diff --git a/textures/techage_usmium_nuggets.png b/textures/techage_usmium_nuggets.png new file mode 100644 index 0000000000000000000000000000000000000000..4842189dee083b9344151eb798cd2a23c0d03b10 GIT binary patch literal 315 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnF3?v&v(vJfvmUKs7M+SzC{oH>NS%G}U;vjb? zhIQv;UIIC?nIRD+&iT2ysd*(pE(3#eQEFmIYKlU6W=V#EyQgnJie4%^P@J>CBeIx* zfm;}a85w5HkpK$v2l#}z`eYUYnN|Hul1f?w;&R+Ri4+0(OeH~n!3=ts-a)tvE-Ia@P@z{BK*2h?Q z37*{+71w$}=#}@B-2s~Oww~PY!4Px#NKi~vMNDaNOmp%wGBPG6CdJ3i%+T5e5;Voi*)wDL z&(q>HH8q=?o6gVDX=!Ny0RjI0{sICB3JMB}ii$=?MpRT(Vq#+N@9(g%ussnynE(I) z3UpFVQvfjk|L(41W-&N{BcD0|00Ue}L_t(o!_8NTcH1Bj^aDAnffa}a>Hq(JY5u&{<1>7(%qR3j|<*wze-Xe{2Z)4grErnlXR?vFkw4fuI9H2ZHkQh9O8} zgpC@&eXx=G5M%6nfzVU5q33A(UI8S8VMEXx1Q8oWxj<4XQ=TCaDZ?2+gf~@xAW%w~ zOa?7@hD2!w21@}$S>Dn5lt3A?12e<+iP4`Cyc!1r5yhBG?M3W<^{;bQW-Y(UfB|Hg zS6dvn5JaLY1SIpi63Ft9Tm146Kmg!sSzQtl1Q1bgXF**g2v33^5;0#BF;^l=qG1G{ z#VFp5;@ucE{zq_(;HK&JL}1XMWUZ};+IyuMKdR)N9{fZQy|?mc@D9)QDq`(KS(}r^ zMo)SeoHU9Hfp&fv3<%`elRz@UnTX^^_T;4(X(33y8GSB27*>K$MP%>nU_7~j7lOt! z$r$94IPr166H(%#@PGlhMmjwc@ZhbLc5-Q)TL@S(4BhXKqmdjG8@+GvmGEr# zB}5v}?7tFGDfu#j?gYgpnnv1cE|bDCoKHoJIhBdzEMm^74UupyH!^+|vSJ}fwFYlH zv27Yj-E$9KBuH7BG)?=h)i|ZJ@YLW)z)2?6V08fI4?k1Rj^HqaMqE227DI>&oS|V9 zhYn)sv=VHFuorRkF4CA}Jr!pfv9}PoDDE%|0iDdk+5_*?v<5Z=BfOZ_9&D0oZ6q`l zvrK;xYY%Kw^YKHZqHqt@FdL@`wcIQgOXIg)G zEo{>I)#d!Ph*!6^BH}kT*Y3M#q+?RW0YhCsVCdz5@%9m?64AUACnC