diff --git a/basic_machines/grinder.lua b/basic_machines/grinder.lua index 2f947fa..9a6c161 100644 --- a/basic_machines/grinder.lua +++ b/basic_machines/grinder.lua @@ -263,8 +263,8 @@ if minetest.global_exists("unified_inventory") then unified_inventory.register_craft_type("grinding", { description = I("Grinding"), icon = 'techage_appl_grinder.png', - width = 1, - height = 1, + width = 2, + height = 2, }) end diff --git a/basis/firebox.lua b/basis/firebox.lua new file mode 100644 index 0000000..d41e203 --- /dev/null +++ b/basis/firebox.lua @@ -0,0 +1,110 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Firebox basic functions + +]]-- + +-- 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") + +techage.firebox = {} + +local BURN_TIME_FACTOR = 2 + +techage.firebox.Burntime = { + ["techage:charcoal"] = true, -- will be replaced by burntime + ["default:coal_lump"] = true, + ["default:coalblock"] = true, +} + +local function determine_burntimes() + for k,_ in pairs(techage.firebox.Burntime)do + local fuel,_ = minetest.get_craft_result({method = "fuel", width = 1, items = {k}}) + techage.firebox.Burntime[k] = fuel.time * BURN_TIME_FACTOR + end +end +minetest.after(1, determine_burntimes) + +function techage.firebox.formspec(mem) + local fuel_percent = 0 + if mem.running then + fuel_percent = ((mem.burn_cycles or 1) * 100) / (mem.burn_cycles_total or 1) + end + return "size[8,6]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "list[current_name;fuel;1,0.5;1,1;]".. + "image[3,0.5;1,1;default_furnace_fire_bg.png^[lowpart:".. + fuel_percent..":default_furnace_fire_fg.png]".. + "button[5,0.5;1.8,1;update;"..I("Update").."]".. + "list[current_player;main;0,2;8,4;]".. + "listring[current_name;fuel]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 2) +end + +function techage.firebox.can_dig(pos, player) + local mem = tubelib2.get_mem(pos) + local inv = M(pos):get_inventory() + return inv:is_empty("fuel") and not mem.running +end + +function techage.firebox.allow_metadata_inventory(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then + return 0 + end + if techage.firebox.Burntime[stack:get_name()] then + return stack:get_count() + end + return 0 +end + +function techage.firebox.on_receive_fields(pos, formname, fields, player) + if minetest.is_protected(pos, player:get_player_name()) then + return + end + + if fields.update then + local mem = tubelib2.get_mem(pos) + M(pos):set_string("formspec", techage.firebox.formspec(mem)) + end +end + +function techage.firebox.on_rightclick(pos, node, clicker) + local mem = tubelib2.get_mem(pos) + M(pos):set_string("formspec", techage.firebox.formspec(mem)) +end + +function techage.firebox.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 + +function techage.firebox.get_fuel(pos) + local inv = M(pos):get_inventory() + local items = inv:get_stack("fuel", 1) + if items:get_count() > 0 then + local taken = items:take_item(1) + inv:set_stack("fuel", 1, items) + return taken + end +end + diff --git a/basis/guide.lua b/basis/guide.lua new file mode 100644 index 0000000..cd9e3a4 --- /dev/null +++ b/basis/guide.lua @@ -0,0 +1,557 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Construction Guide + +]]-- + + + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +local SMELTING_TIME = 2 + +local Tabs = S("Manufacture,Construction") + +local Recipes = {} -- registered recipes +local KeyList = {} -- index to Recipes key translation +local NumRecipes = 0 + +-- formspec images +local function plan(images) + local tbl = {} + for y=0,9 do + for x=0,9 do + local img = images[y+1][x+1] or false + if img ~= false then + tbl[#tbl+1] = "item_image["..(x*0.8)..","..(y*0.8)..";0.8,0.8;"..img..".png]" + end + end + end + return table.concat(tbl) +end + +local function formspec_manufacture(idx) + idx = math.min(idx, #KeyList) + local key = KeyList[idx] + local input1 = Recipes[key].input[1] or "" + local input2 = Recipes[key].input[2] or "" + local input3 = Recipes[key].input[3] or "" + local input4 = Recipes[key].input[4] or "" + local num = Recipes[key].number + local output = Recipes[key].output + if num > 1 then + output = output.." "..num + end + return "size[11,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "tabheader[0,0;tab;"..Tabs..";2;;true]".. + "label[1,0.2;"..S("Manufacture Manual").."]".. + + "container[1,1]".. + "item_image_button[0,0;1,1;"..input1..";b1;]".. + "item_image_button[1,0;1,1;"..input2..";b2;]".. + "item_image_button[0,1;1,1;"..input3..";b3;]".. + "item_image_button[1,1;1,1;"..input4..";b4;]".. + "item_image[2.6,0;0.8,0.8;"..Recipes[key].icon.."]".. + "image[2.3,0.6;1.6,1;gui_furnace_arrow_bg.png^[transformR270]".. + "item_image_button[4,0.5;1,1;"..output..";b5;]".. + "label[2,2.2;"..Recipes[key].hints.."]".. + "label[2,4;Recipe "..idx.." of "..NumRecipes.."]".. + "button[2,5.5;0.8,0.8;priv;<<]".. + "button[3,5.5;0.8,0.8;next;>>]".. + "container_end[]" +end + +local function formspec_construction(recipe) + return "size[11,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "tabheader[0,0;tab;"..Tabs..";3;;true]".. + "label[0,0;"..BurnerHelp.."]".. + "label[1,5;"..S("Cross-section")..":]".. + "container[4,4]".. + draw(BurnerImages).. + "container_end[]" +end + +local function on_receive_fields(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + local recipe_idx = meta:get_int("recipe_idx") + if recipe_idx == 0 then recipe_idx = 1 end + if fields.tab == "1" then + meta:set_string("formspec", formspec1) + elseif fields.tab == "2" then + meta:set_string("formspec", formspec2(recipe_idx)) + elseif fields.next == ">>" then + recipe_idx = math.min(recipe_idx + 1, NumRecipes) + meta:set_int("recipe_idx", recipe_idx) + meta:set_string("formspec", formspec2(recipe_idx)) + elseif fields.priv == "<<" then + recipe_idx = math.max(recipe_idx - 1, 1) + meta:set_int("recipe_idx", recipe_idx) + meta:set_string("formspec", formspec2(recipe_idx)) + end +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("dst") and inv:is_empty("src") +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 + 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 + +-- generate an unique key based on the unsorted and +-- variable number of inventory items +local function recipe_key(items) + local tbl = {} + -- remove items which exist more than once + for _,item in ipairs(items) do + tbl[item] = true + end + local names = {} + for key,_ in pairs(tbl) do + names[#names + 1] = key + end + -- bring in a sorted order + table.sort(names) + return table.concat(names, "-") +end + +-- determine recipe based on inventory items +local function get_recipe(inv) + -- collect items + local stacks = {} + local names = {} + for _,stack in ipairs(inv:get_list("src")) do + if not stack:is_empty() then + table.insert(names, stack:get_name()) + table.insert(stacks, stack) + else + table.insert(stacks, ItemStack("")) + end + end + local key = recipe_key(names) + local recipe = Recipes[key] + + if recipe then + return { + input = recipe.input, + stacks = stacks, + output = ItemStack(recipe.output.." "..recipe.number), + heat = recipe.heat, + time = recipe.time, + } + end + return nil +end + +-- prepare recipe and store in cache table for faster access +local function store_recipe_in_cache(pos) + local hash = minetest.hash_node_position(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local recipe = get_recipe(inv) + Cache[hash] = recipe + return recipe +end + +-- read value from the node below +local function get_heat(pos) + local heat = 0 + pos.y = pos.y - 1 + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + pos.y = pos.y + 1 + if minetest.get_item_group(node.name, "techage_flame") > 0 then + heat = meta:get_int("heat") + end + return heat +end + +-- Start melting if heat is ok AND source items available +function techage.switch_to_active(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + local recipe = store_recipe_in_cache(pos) + + if recipe and heat >= recipe.heat then + minetest.swap_node(pos, {name = "techage:meltingpot_active"}) + minetest.registered_nodes["techage:meltingpot_active"].on_construct(pos) + meta:set_string("infotext", S("Melting Pot active (heat=")..heat..")") + minetest.get_node_timer(pos):start(2) + return true + end + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") + return false +end + +function techage.update_heat(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") +end + +local function set_inactive(meta, pos, heat) + minetest.get_node_timer(pos):stop() + minetest.swap_node(pos, {name = "techage:meltingpot"}) + minetest.registered_nodes["techage:meltingpot"].on_construct(pos) + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") +end + +-- Stop melting if heat to low OR no source items available +local function switch_to_inactive(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + local hash = minetest.hash_node_position(pos) + local recipe = Cache[hash] or store_recipe_in_cache(pos) + + if not recipe or heat < recipe.heat then + set_inactive(meta, pos, heat) + return true + end + meta:set_string("infotext", S("Melting Pot active (heat=")..heat..")") + return false +end + + +local function index(list, x) + for idx, v in pairs(list) do + if v == x then return idx end + end + return nil +end + +-- move recipe src items to output inventory +local function process(inv, recipe, heat) + if heat < recipe.heat then + return false + end + local res = false + if inv:room_for_item("dst", recipe.output) then + for _,item in ipairs(recipe.input) do + res = false + for _, stack in ipairs(recipe.stacks) do + if stack:get_count() > 0 and stack:get_name() == item then + stack:take_item(1) + res = true + break + end + end + if res == false then + return false + end + end + inv:add_item("dst", recipe.output) + inv:set_list("src", recipe.stacks) + return true + end + return false +end + +local function smelting(pos, recipe, heat, elapsed) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + elapsed = elapsed + meta:get_int("leftover") + + while elapsed >= recipe.time do + if process(inv, recipe, heat) == false then + meta:set_int("leftover", 0) + set_inactive(meta, pos, heat) + return false + end + elapsed = elapsed - recipe.time + end + meta:set_int("leftover", elapsed) + return true +end + +local function pot_node_timer(pos, elapsed) + if switch_to_inactive(pos) == false then + local hash = minetest.hash_node_position(pos) + local heat = get_heat(pos) + local recipe = Cache[hash] or store_recipe_in_cache(pos) + if recipe then + return smelting(pos, recipe, heat, elapsed) + end + end + return false +end + +minetest.register_node("techage:meltingpot_active", { + description = S("Melting Pot"), + tiles = { + { + image = "techage_meltingpot_top_active.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1, + }, + }, + "default_cobble.png^techage_meltingpot.png", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-10/16, -8/16, -10/16, 10/16, 9/16, -6/16}, + {-10/16, -8/16, 6/16, 10/16, 9/16, 10/16}, + {-10/16, -8/16, -10/16, -6/16, 9/16, 10/16}, + { 6/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + { -6/16, -8/16, -6/16, 6/16, 5/16, 6/16}, + }, + }, + selection_box = { + type = "fixed", + fixed = {-10/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec1) + local inv = meta:get_inventory() + inv:set_size('src', 4) + inv:set_size('dst', 4) + end, + + on_timer = function(pos, elapsed) + return pot_node_timer(pos, elapsed) + end, + + on_receive_fields = function(pos, formname, fields, sender) + on_receive_fields(pos, formname, fields, sender) + end, + + on_metadata_inventory_move = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + on_metadata_inventory_put = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + on_metadata_inventory_take = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + can_dig = can_dig, + + drop = "techage:meltingpot", + is_ground_content = false, + groups = {cracky = 3, not_in_creative_inventory=1}, + sounds = default.node_sound_metal_defaults(), + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, +}) + +minetest.register_node("techage:meltingpot", { + description = S("Melting Pot"), + tiles = { + "default_cobble.png", + "default_cobble.png^techage_meltingpot.png", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-10/16, -8/16, -10/16, 10/16, 9/16, -6/16}, + {-10/16, -8/16, 6/16, 10/16, 9/16, 10/16}, + {-10/16, -8/16, -10/16, -6/16, 9/16, 10/16}, + { 6/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + { -6/16, -8/16, -6/16, 6/16, -4/16, 6/16}, + }, + }, + selection_box = { + type = "fixed", + fixed = {-10/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec1) + meta:set_string("infotext", S("Melting Pot inactive (heat=0)")) + local inv = meta:get_inventory() + inv:set_size('src', 4) + inv:set_size('dst', 4) + end, + + on_metadata_inventory_move = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_metadata_inventory_put = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_metadata_inventory_take = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_receive_fields = function(pos, formname, fields, sender) + on_receive_fields(pos, formname, fields, sender) + end, + + can_dig = can_dig, + + is_ground_content = false, + groups = {cracky = 3}, + sounds = default.node_sound_metal_defaults(), + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, +}) + +minetest.register_craft({ + output = "techage:meltingpot", + recipe = { + {"default:cobble", "default:copper_ingot", "default:cobble"}, + {"default:cobble", "", "default:cobble"}, + {"default:cobble", "default:cobble", "default:cobble"}, + }, +}) + +if minetest.global_exists("unified_inventory") then + unified_inventory.register_craft_type("melting", { + description = S("Melting"), + icon = "default_cobble.png^techage_meltingpot.png", + width = 2, + height = 2, + }) + unified_inventory.register_craft_type("burning", { + description = S("Burning"), + icon = "techage_smoke.png", + width = 1, + height = 1, + }) + unified_inventory.register_craft({ + output = "techage:charcoal", + items = {"group:wood"}, + type = "burning", + }) +end + +function techage.ironage_register_recipe(recipe) + local key = recipe_key(recipe.recipe) + local output = string.split(recipe.output, " ") + local number = tonumber(output[2] or 1) + table.insert(KeyList, key) + Recipes[key] = { + input = recipe.recipe, + output = output[1], + number = number, + heat = math.max(recipe.heat or 3, 2), + time = math.max(recipe.time or 2, 2*number), + } + NumRecipes = NumRecipes + 1 + + if minetest.global_exists("unified_inventory") then + recipe.items = recipe.recipe + recipe.type = "melting" + unified_inventory.register_craft(recipe) + end +end + + +techage.ironage_register_recipe({ + output = "default:obsidian", + recipe = {"default:cobble"}, + heat = 5, + time = 4, +}) + +techage.ironage_register_recipe({ + output = "default:coral_skeleton", + recipe = {"gravelsieve:compressed_gravel"}, + heat = 4, + time = 4, +}) + +techage.ironage_register_recipe({ + output = "default:bronze_ingot 4", + recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"}, + heat = 4, + time = 8, +}) + +local PileHelp = S([[Coal Pile to produce charcoal: +- build a 5x5 block dirt base +- place a lighter in the centre +- build a 3x3x3 wood cube around +- cover all with dirt to a 5x5x5 cube +- keep a hole to the lighter +- ignite the lighter and immediately +- close the pile with one wood and one dirt +- open the pile after the smoke disappeared]]) + +local BurnerHelp = S([[Coal Burner to heat the melting pot: +- build a 3x3xN cobble tower +- more height means more flame heat +- keep a hole open on one side +- put a lighter in +- fill the tower from the top with charcoal +- ignite the lighter +- place the pot in the flame]]) + +local PileImages = { + {"default_dirt", "default_dirt", "default_dirt", "default_dirt", "default_dirt"}, + {"default_dirt", "default_wood", "default_wood", "default_wood", "default_dirt"}, + {"default_dirt", "default_wood", "default_wood", "default_wood", "default_dirt"}, + {"default_dirt", "default_wood", "techage_lighter", "default_wood", "default_dirt"}, + {"default_dirt", "default_dirt", "default_dirt", "default_dirt", "default_dirt"}, +} + +local BurnerImages = { + false, false, "default_cobble", "techage_charcoal", "default_cobble", + false, false, "default_cobble", "techage_charcoal", "default_cobble", + false, false, "default_cobble", "techage_charcoal", "default_cobble", + false, false, false, "techage_lighter", "default_cobble", + false, false, "default_cobble", "default_cobble", "default_cobble", +} diff --git a/steam_engine/steam_pipe.lua b/basis/steam_pipe.lua similarity index 100% rename from steam_engine/steam_pipe.lua rename to basis/steam_pipe.lua diff --git a/coal_power_station/boiler.lua b/coal_power_station/boiler.lua new file mode 100644 index 0000000..74e8ec0 --- /dev/null +++ b/coal_power_station/boiler.lua @@ -0,0 +1,340 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + TA3 Coal Power Station Boiler + +]]-- + +-- 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 CYCLE_TIME = 4 +local STANDBY_TICKS = 2 +local COUNTDOWN_TICKS = 2 +local HEAT_STEP = 10 +local WATER_CONSUMPTION = 0.5 +local MAX_WATER = 10 +local POWER_CAPACITY = 10 + +local Pipe = techage.SteamPipe +local generator = techage.generator + + +local Water = { + ["bucket:bucket_river_water"] = true, + ["bucket:bucket_water"] = true, + ["bucket:bucket_empty"] = true, +} + +local function formspec(self, pos, mem) + local temp = mem.temperature or 20 + return "size[8,7]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "image_button[0,0.2;1,1;techage_form_inventory.png;storage;;true;false;]".. + "list[context;water;1,0.2;1,1;]".. + "image_button[0,1.6;1,1;techage_form_input.png;input;;true;false;]".. + "list[context;input;1,1.6;1,1;]".. + "image[1,1.6;1,1;bucket_water.png]".. + "image[1,1.6;1,1;techage_form_mask.png]".. + "image[2,0.5;1,2;techage_form_temp_bg.png^[lowpart:".. + temp..":techage_form_temp_fg.png]".. + "image[7,0.5;1,2;"..generator.formspec_level(mem, mem.power_result).. + "image_button[6,1;1,1;".. self:get_state_button_image(mem) ..";state_button;]".. + "button[3,1.5;2,1;update;"..I("Update").."]".. + "list[current_player;main;0,3;8,4;]".. + "listring[current_name;water]".. + "listring[current_player;main]".. + default.get_hotbar_bg(0, 3) +end + +local function start_node(pos, mem, state) + generator.turn_power_on(pos, POWER_CAPACITY) +end + +local function stop_node(pos, mem, state) + generator.turn_power_on(pos, 0) +end + +local State = techage.NodeStates:new({ + node_name_passive = "techage:coalboiler1", + cycle_time = CYCLE_TIME, + standby_ticks = STANDBY_TICKS, + has_item_meter = false, + formspec_func = formspec, + start_node = start_node, + stop_node = stop_node, +}) + +local function get_water(pos) + local inv = M(pos):get_inventory() + local items = inv:get_stack("water", 1) + if items:get_count() > 0 then + local taken = items:take_item(1) + inv:set_stack("water", 1, items) + return true + end + return false +end + +local function water_temperature(pos, mem) + mem.temperature = mem.temperature or 20 + if mem.fire_trigger then + mem.temperature = math.min(mem.temperature + HEAT_STEP, 100) + else + mem.temperature = math.max(mem.temperature - HEAT_STEP, 20) + end + mem.fire_trigger = false + + if mem.water_level == 0 then + if get_water(pos) then + mem.water_level = 100 + else + mem.temperature = 20 + end + end + return mem.temperature +end + +local function steaming(pos, mem, temp) + mem.water_level = math.max((mem.water_level or 0) - WATER_CONSUMPTION, 0) + if temp >= 80 then + if mem.power_result > 0 then + State:keep_running(pos, mem, COUNTDOWN_TICKS) + else + State:fault(pos, mem) + end + else + State:stop(pos, mem) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end +end + +local function node_timer(pos, elapsed) + local mem = tubelib2.get_mem(pos) + local temp = water_temperature(pos, mem) + if State:is_active(mem) then + steaming(pos, mem, temp) + end + return mem.temperature > 20 +end + +local function turn_power_on(pos, in_dir, sum) + local mem = tubelib2.get_mem(pos) + -- store result for formspec + mem.power_result = sum + if State:is_active(mem) and sum <= 0 then + State:fault(pos, mem) + -- No automatic turn on + mem.power_capacity = 0 + end + M(pos):set_string("formspec", formspec(State, pos, 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) + State:state_button_event(pos, mem, fields) + + if fields.update then + M(pos):set_string("formspec", formspec(State, pos, mem)) + end +end + + +local function on_rightclick(pos) + local mem = tubelib2.get_mem(pos) + M(pos):set_string("formspec", formspec(State, pos, mem)) +end + +local function can_dig(pos, player) + local inv = M(pos):get_inventory() + local mem = tubelib2.get_mem(pos) + return inv:is_empty("water") and inv:is_empty("input") and not mem.running +end + +local function move_to_water(pos) + local inv = M(pos):get_inventory() + local water_stack = inv:get_stack("water", 1) + local input_stack = inv:get_stack("input", 1) + + if input_stack:get_name() == "bucket:bucket_empty" then + if input_stack:get_count() == 1 then + if water_stack:get_count() > 0 then + water_stack:set_count(water_stack:get_count() - 1) + input_stack = ItemStack("bucket:bucket_water") + inv:set_stack("water", 1, water_stack) + inv:set_stack("input", 1, input_stack) + end + end + elseif water_stack:get_count() < MAX_WATER then + if water_stack:get_count() == 0 then + water_stack = ItemStack("default:water_source") + else + water_stack:set_count(water_stack:get_count() + 1) + end + input_stack = ItemStack("bucket:bucket_empty") + inv:set_stack("water", 1, water_stack) + inv:set_stack("input", 1, input_stack) + end +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 == "input" and Water[stack:get_name()] then + return stack:get_count() + end + return 0 +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 + if listname == "input" then + return stack:get_count() + end + return 0 +end + +minetest.register_node("techage:coalboiler2", { + + + paramtype2 = "facedir", + groups = {cracky=1}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_metal_defaults(), +}) + +minetest.register_node("techage:coalboiler1", { + description = I("TA3 Coal Power Station Firebox"), + inventory_image = "techage_coal_boiler_inv.png", + tiles = {"techage_coal_boiler_mesh.png"}, + drawtype = "mesh", + mesh = "techage_boiler_large.obj", + selection_box = { + type = "fixed", + fixed = {-14/32, -16/32, -14/32, 14/32, 16/32, 14/32}, + }, + + paramtype2 = "facedir", + on_rotate = screwdriver.disallow, + groups = {cracky=2}, + is_ground_content = false, + sounds = default.node_sound_stone_defaults(), + + on_timer = node_timer, + can_dig = can_dig, + allow_metadata_inventory_put = allow_metadata_inventory, + allow_metadata_inventory_take = allow_metadata_inventory, + on_receive_fields = on_receive_fields, + on_rightclick = on_rightclick, + + on_construct = function(pos) + local mem = tubelib2.init_mem(pos) + mem.running = false + mem.burn_cycles = 0 + local meta = M(pos) + meta:set_string("formspec", formspec(mem)) + local inv = meta:get_inventory() + inv:set_size('fuel', 1) + end, + + on_metadata_inventory_put = function(pos) + local mem = tubelib2.init_mem(pos) + mem.running = true + -- activate the formspec fire temporarily + mem.burn_cycles = BURN_CYCLES + M(pos):set_string("formspec", formspec(mem)) + mem.burn_cycles = 0 + swap_node(pos, "techage:firebox_on") + minetest.get_node_timer(pos):start(CYCLE_TIME) + end, +}) + + +-- boiler2: Main part, needed as generator +minetest.register_node("techage:boiler2", { + description = I("TA3 Boiler Top"), + tiles = {"techage_coal_boiler.png"}, + drawtype = "mesh", + mesh = "techage_boiler_large.obj", + selection_box = { + type = "fixed", + fixed = {-10/32, -48/32, -10/32, 10/32, 16/32, 10/32}, + }, + + can_dig = can_dig, + on_timer = node_timer, + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_take = allow_metadata_inventory_take, + on_receive_fields = on_receive_fields, + on_rightclick = on_rightclick, + + techage = { + turn_on = turn_power_on, + read_power_consumption = generator.read_power_consumption, + power_network = Pipe, + trigger_boiler = function(pos) + local mem = tubelib2.get_mem(pos) + mem.fire_trigger = true + if not minetest.get_node_timer(pos):is_started() then + minetest.get_node_timer(pos):start(CYCLE_TIME) + end + end, + power_side = "U", + }, + + on_construct = function(pos) + local inv = M(pos):get_inventory() + inv:set_size('water', 1) + inv:set_size('input', 1) + end, + + after_place_node = function(pos, placer) + local mem = generator.after_place_node(pos) + State:node_init(pos, mem, "") + local node = minetest.get_node({x=pos.x, y=pos.y-1, z=pos.z}) + if node.name == "techage:boiler1" then + on_rightclick(pos) + end + end, + + after_dig_node = function(pos, oldnode, oldmetadata, digger) + State:after_dig_node(pos, oldnode, oldmetadata, digger) + generator.after_dig_node(pos, oldnode) + end, + + after_tube_update = generator.after_tube_update, + + on_metadata_inventory_put = function(pos) + minetest.after(0.5, move_to_water, pos) + end, + + --paramtype2 = "facedir", + groups = {cracky=1}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_metal_defaults(), +}) + diff --git a/coal_power_station/firebox.lua b/coal_power_station/firebox.lua new file mode 100644 index 0000000..9a98560 --- /dev/null +++ b/coal_power_station/firebox.lua @@ -0,0 +1,178 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + TA3 Coal Power Station Firebox + +]]-- + +-- 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 firebox = techage.firebox + +local CYCLE_TIME = 2 + +local function firehole(pos, on) + local param2 = minetest.get_node(pos).param2 + local pos2 = techage.get_pos(pos, 'F') + if on == true then + minetest.swap_node(pos2, {name="techage:coalfirehole_on", param2 = param2}) + elseif on == false then + minetest.swap_node(pos2, {name="techage:coalfirehole", param2 = param2}) + else + minetest.swap_node(pos2, {name="air"}) + end +end + +local function node_timer(pos, elapsed) + local mem = tubelib2.get_mem(pos) + if mem.running then + local trd = TRD({x=pos.x, y=pos.y+2, z=pos.z}) + if trd and trd.trigger_boiler then + trd.trigger_boiler({x=pos.x, y=pos.y+2, z=pos.z}) + end + mem.burn_cycles = (mem.burn_cycles or 0) - 1 + if mem.burn_cycles <= 0 then + local taken = firebox.get_fuel(pos) + if taken then + mem.burn_cycles = firebox.Burntime[taken:get_name()] / CYCLE_TIME + mem.burn_cycles_total = mem.burn_cycles + else + mem.running = false + firehole(pos, false) + M(pos):set_string("formspec", firebox.formspec(mem)) + return false + end + end + return true + end +end + +minetest.register_node("techage:coalfirebox", { + description = I("TA3 Coal Power Station Firebox"), + inventory_image = "techage_coal_boiler_inv.png", + tiles = {"techage_coal_boiler_mesh.png"}, + drawtype = "mesh", + mesh = "techage_boiler_large.obj", + selection_box = { + type = "fixed", + fixed = {-13/32, -16/32, -13/32, 13/32, 16/32, 13/32}, + }, + + paramtype2 = "facedir", + on_rotate = screwdriver.disallow, + groups = {cracky=2}, + is_ground_content = false, + sounds = default.node_sound_stone_defaults(), + + on_timer = node_timer, + can_dig = firebox.can_dig, + allow_metadata_inventory_put = firebox.allow_metadata_inventory, + allow_metadata_inventory_take = firebox.allow_metadata_inventory, + on_receive_fields = firebox.on_receive_fields, + on_rightclick = firebox.on_rightclick, + + on_construct = function(pos) + local mem = tubelib2.init_mem(pos) + mem.running = false + mem.burn_cycles = 0 + local meta = M(pos) + meta:set_string("formspec", firebox.formspec(mem)) + local inv = meta:get_inventory() + inv:set_size('fuel', 1) + firehole(pos, false) + end, + + on_destruct = function(pos) + firehole(pos, nil) + end, + + on_metadata_inventory_put = function(pos, listname, index, stack, player) + local mem = tubelib2.init_mem(pos) + mem.running = true + -- activate the formspec fire temporarily + mem.burn_cycles = firebox.Burntime[stack:get_name()] / CYCLE_TIME + mem.burn_cycles_total = mem.burn_cycles + M(pos):set_string("formspec", firebox.formspec(mem)) + mem.burn_cycles = 0 + firehole(pos, true) + minetest.get_node_timer(pos):start(CYCLE_TIME) + end, +}) + +minetest.register_node("techage:coalfirehole", { + description = I("TA3 Coal Power Station Firebox"), + tiles = { + -- up, down, right, left, back, front + "techage_coal_boiler.png", + "techage_coal_boiler.png", + "techage_coal_boiler.png", + "techage_coal_boiler.png", + "techage_coal_boiler.png", + "techage_coal_boiler.png^techage_appl_firehole.png", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-6/16, -6/16, 6/16, 6/16, 6/16, 12/16}, + }, + }, + + paramtype2 = "facedir", + pointable = false, + diggable = false, + is_ground_content = false, + groups = {not_in_creative_inventory=1}, +}) + +minetest.register_node("techage:coalfirehole_on", { + description = I("TA3 Coal Power Station Firebox"), + tiles = { + -- up, down, right, left, back, front + "techage_coal_boiler.png^[colorize:black:80", + "techage_coal_boiler.png^[colorize:black:80", + "techage_coal_boiler.png^[colorize:black:80", + "techage_coal_boiler.png^[colorize:black:80", + "techage_coal_boiler.png^[colorize:black:80", + { + image = "techage_coal_boiler4.png^[colorize:black:80^techage_appl_firehole4.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 0.4, + }, + }, + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-6/16, -6/16, 6/16, 6/16, 6/16, 12/16}, + }, + }, + paramtype2 = "facedir", + light_source = 8, + pointable = false, + diggable = false, + is_ground_content = false, + groups = {not_in_creative_inventory=1}, +}) + diff --git a/coal_power_station/turbine.lua b/coal_power_station/turbine.lua new file mode 100644 index 0000000..72e0334 --- /dev/null +++ b/coal_power_station/turbine.lua @@ -0,0 +1,149 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + TA2 Steam Engine Cylinder + +]]-- + +-- 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 = 8 + +local Pipe = techage.SteamPipe +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) + return power_dir == in_dir +end + +-- called from pipe network +local function turn_power_on_clbk(pos, in_dir, sum) + local mem = tubelib2.get_mem(pos) + -- Simply store state to be prepared, when flywheel wants to start. + mem.running = sum > 0 +end + +-- called from flywheel +local function start_cylinder(pos, on) + local mem = tubelib2.get_mem(pos) + if on and mem.running then + consumer.turn_power_on(pos, POWER_CONSUMPTION) + swap_node(pos, "techage:cylinder_on") + return true + else + consumer.turn_power_on(pos, 0) + swap_node(pos, "techage:cylinder") + end + return false +end + + +minetest.register_node("techage:cylinder", { + description = I("TA2 Cylinder"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta2.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_appl_open.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_frame_ta2.png^techage_steam_hole.png", + "techage_filling_ta2.png^techage_cylinder.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_cylinder.png^techage_frame_ta2.png", + }, + techage = { + turn_on = turn_power_on_clbk, + read_power_consumption = consumer.read_power_consumption, + power_network = Pipe, + power_side = "L", + valid_power_dir = valid_power_dir, + start_cylinder = start_cylinder, + }, + + after_place_node = function(pos, placer) + local mem = consumer.after_place_node(pos, placer) + mem.power_consume = 0 -- needed power to run + mem.power_supply = false -- power available? + end, + + after_tube_update = consumer.after_tube_update, + after_dig_node = consumer.after_dig_node, + + paramtype2 = "facedir", + groups = {cracky=2, crumbly=2, choppy=2}, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + +minetest.register_node("techage:cylinder_on", { + description = I("TA2 Cylinder"), + tiles = { + -- up, down, right, left, back, front + "techage_filling_ta2.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_appl_open.png^techage_frame_ta2.png", + "techage_filling_ta2.png^techage_frame_ta2.png^techage_steam_hole.png", + { + image = "techage_filling4_ta2.png^techage_cylinder4.png^techage_frame4_ta2.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 0.4, + }, + }, + { + image = "techage_filling4_ta2.png^techage_cylinder4.png^techage_frame4_ta2.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 32, + aspect_h = 32, + length = 0.4, + }, + }, + }, + techage = { + turn_on = turn_power_on_clbk, + read_power_consumption = consumer.read_power_consumption, + power_network = Pipe, + power_side = "L", + valid_power_dir = valid_power_dir, + start_cylinder = start_cylinder, + }, + + after_tube_update = consumer.after_tube_update, + after_dig_node = consumer.after_dig_node, + + paramtype2 = "facedir", + groups = {not_in_creative_inventory=1}, + diggable = false, + on_rotate = screwdriver.disallow, + is_ground_content = false, + sounds = default.node_sound_wood_defaults(), +}) + diff --git a/depends.txt b/depends.txt deleted file mode 100644 index 6bd4325..0000000 --- a/depends.txt +++ /dev/null @@ -1,4 +0,0 @@ -default -tubelib2 -basic_materials - diff --git a/init.lua b/init.lua index 149d58f..baaaa62 100644 --- a/init.lua +++ b/init.lua @@ -14,6 +14,7 @@ local MP = minetest.get_modpath("techage") -- Load support for intllib. dofile(MP.."/basis/intllib.lua") +-- Basis features dofile(MP.."/basis/power.lua") -- power distribution dofile(MP.."/basis/node_states.lua") dofile(MP.."/basis/trowel.lua") -- hidden networks @@ -21,15 +22,23 @@ dofile(MP.."/basis/junction.lua") -- network junction box dofile(MP.."/basis/tubes.lua") -- tubelib replacement dofile(MP.."/basis/command.lua") -- tubelib replacement dofile(MP.."/basis/consumer.lua") -- consumer base model +dofile(MP.."/basis/steam_pipe.lua") +dofile(MP.."/basis/firebox.lua") -- Iron Age +dofile(MP.."/iron_age/main.lua") dofile(MP.."/iron_age/gravelsieve.lua") dofile(MP.."/iron_age/hammer.lua") - +dofile(MP.."/iron_age/lighter.lua") +dofile(MP.."/iron_age/charcoalpile.lua") +dofile(MP.."/iron_age/coalburner.lua") +dofile(MP.."/iron_age/meltingpot.lua") +if minetest.global_exists("wielded_light") then + dofile(MP.."/iron_age/meridium.lua") +end -- Steam Engine dofile(MP.."/steam_engine/drive_axle.lua") -dofile(MP.."/steam_engine/steam_pipe.lua") dofile(MP.."/steam_engine/firebox.lua") dofile(MP.."/steam_engine/boiler.lua") dofile(MP.."/steam_engine/cylinder.lua") @@ -51,6 +60,9 @@ dofile(MP.."/basic_machines/distributor.lua") dofile(MP.."/basic_machines/gravelsieve.lua") dofile(MP.."/basic_machines/chest.lua") +-- Coal power station +dofile(MP.."/coal_power_station/firebox.lua") + --dofile(MP.."/fermenter/biogas_pipe.lua") --dofile(MP.."/fermenter/gasflare.lua") diff --git a/iron_age/charcoalpile.lua b/iron_age/charcoalpile.lua new file mode 100644 index 0000000..a9ca33b --- /dev/null +++ b/iron_age/charcoalpile.lua @@ -0,0 +1,214 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Charcoalpile to produce charcoal + +]]-- + + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +local PILE_BURN_TIME = 1200 +local COAL_BURN_TIME = 700 + +-- determine the number of wood nodes +local function num_wood(pos) + local pos1 = {x=pos.x-1, y=pos.y, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y+2, z=pos.z+1} + local nodes = minetest.find_nodes_in_area(pos1, pos2, "group:wood") + return #nodes +end + +-- determine the number of nodes nodes (around wood) +local function num_dirt(pos) + local pos1 = {x=pos.x-2, y=pos.y-1, z=pos.z-2} + local pos2 = {x=pos.x+2, y=pos.y+3, z=pos.z+2} + local nodes = minetest.find_nodes_in_area(pos1, pos2, {"default:dirt", "default:dirt_with_grass", + "default:dirt_with_dry_grass", "default:dirt_with_snow", "techage:dirt_with_ash"}) + return #nodes +end + +-- replace pile top nodes +local function make_dirt_with_dry_grass(pos) + local pos1 = {x=pos.x-2, y=pos.y+3, z=pos.z-2} + local pos2 = {x=pos.x+2, y=pos.y+3, z=pos.z+2} + for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, "default:dirt_with_grass")) do + minetest.swap_node(p, {name = "default:dirt_with_dry_grass"}) + end +end + +-- replace pile bottom nodes +local function make_dirt_with_ash(pos) + local pos1 = {x=pos.x-1, y=pos.y-1, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y-1, z=pos.z+1} + for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, "default:dirt")) do + minetest.swap_node(p, {name = "techage:dirt_with_ash"}) + end +end + +local function start_smoke(pos) + local meta = minetest.get_meta(pos) + pos = {x=pos.x, y=pos.y+3.6, z=pos.z} + local id = meta:get_int("smoke") + local above = minetest.get_node(pos).name + + if id ~= 0 then + minetest.delete_particlespawner(id) + meta:set_int("smoke", 0) + end + + if above == "air" then + id = minetest.add_particlespawner({ + amount = 4, time = 0, collisiondetection = true, + minpos = {x=pos.x-0.25, y=pos.y+0.1, z=pos.z-0.25}, + maxpos = {x=pos.x+0.25, y=pos.y+5, z=pos.z+0.25}, + minvel = {x=-0.2, y=0.3, z=-0.2}, maxvel = {x=0.2, y=1, z=0.2}, + minacc = {x=0,y=0,z=0}, maxacc = {x=0,y=0.5,z=0}, + minexptime = 1, maxexptime = 3, + minsize = 6, maxsize = 12, + texture = "techage_smoke.png", + }) + meta:set_int("smoke", id) + end +end + +local function stop_smoke(pos) + local meta = minetest.get_meta(pos) + local id = meta:get_int("smoke") + if id ~= 0 then + minetest.delete_particlespawner(id) + end + meta:set_int("smoke", 0) +end + +-- replace wood by burning coal +local function collapse_pile(pos) + local pos1 = {x=pos.x-1, y=pos.y, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y+2, z=pos.z+1} + techage.ironage_swap_nodes(pos1, pos2, "group:wood", "techage:charcoal_burn") + stop_smoke(pos) + make_dirt_with_ash(pos) +end + +-- replace wood by coal +local function convert_to_coal(pos) + local pos1 = {x=pos.x-1, y=pos.y+1, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y+2, z=pos.z+1} + techage.ironage_swap_nodes(pos1, pos2, "group:wood", "air") + pos1 = {x=pos.x-1, y=pos.y+0, z=pos.z-1} + pos2 = {x=pos.x+1, y=pos.y+1, z=pos.z+1} + techage.ironage_swap_nodes(pos1, pos2, "group:wood", "techage:charcoal") + stop_smoke(pos) + minetest.swap_node(pos, {name = "techage:charcoal"}) + make_dirt_with_ash(pos) + make_dirt_with_dry_grass(pos) +end + +function techage.start_pile(pos) + local meta = minetest.get_meta(pos) + meta:set_int("ignite", minetest.get_gametime()) + minetest.get_node_timer(pos):start(20) +end + +-- node timer function +function techage.keep_running_pile(pos) + local meta = minetest.get_meta(pos) + if meta:get_int("running") == 0 then + if num_wood(pos) == 26 and num_dirt(pos) == 98 then + meta:set_int("running", 1) + start_smoke(pos) + elseif minetest.get_gametime() > (meta:get_int("ignite") + 10) then + collapse_pile(pos) + minetest.remove_node(pos) + return false + end + else + if num_wood(pos) ~= 26 or num_dirt(pos) ~= 98 then + collapse_pile(pos) + minetest.remove_node(pos) + return false + elseif minetest.get_gametime() > (meta:get_int("ignite") + PILE_BURN_TIME) then + convert_to_coal(pos) + return false + end + end + return true +end + +function techage.stop_pile(pos) + collapse_pile(pos) +end + + +minetest.register_node("techage:dirt_with_ash", { + description = S("Dirt with Ash"), + tiles = { + "techage_ash.png", + "default_dirt.png", + {name = "default_dirt.png^techage_ash_side.png", + tileable_vertical = false}}, + groups = {crumbly = 3, soil = 1, spreading_dirt_type = 1, not_in_creative_inventory=1}, + drop = 'default:dirt', + sounds = default.node_sound_dirt_defaults({ + footstep = {name = "default_grass_footstep", gain = 0.4}, + }), +}) + + +minetest.register_node("techage:charcoal_burn", { + tiles = {"techage_charcoal_burn.png"}, + after_place_node = function(pos) + minetest.get_node_timer(pos):start(math.random(COAL_BURN_TIME, COAL_BURN_TIME*1.2)) + end, + on_timer = function(pos) + minetest.remove_node(pos) + return false + end, + drop = "", + light_source = 10, + is_ground_content = false, + groups = {crumbly = 2, falling_node = 1, not_in_creative_inventory=1}, + sounds = default.node_sound_dirt_defaults(), +}) + +minetest.register_node("techage:charcoal", { + description = S("Charcoal"), + tiles = {"techage_charcoal.png"}, + on_ignite = function(pos, igniter) + minetest.after(2, minetest.swap_node, pos, {name = "techage:charcoal_burn"}) + minetest.after(COAL_BURN_TIME/2, minetest.remove_node, pos) + end, + is_ground_content = false, + groups = {crumbly = 2, falling_node = 1}, + sounds = default.node_sound_dirt_defaults(), +}) + + +minetest.register_craft({ + type = "fuel", + recipe = "techage:charcoal", + burntime = 370, +}) + +minetest.register_lbm({ + label = "[techage] Lighter update", + name = "techage:update", + nodenames = {"techage:lighter_burn"}, + run_at_every_load = true, + action = function(pos, node) + local meta = minetest.get_meta(pos) + if meta:get_int("running") == 1 then + start_smoke(pos) + end + end +}) + diff --git a/iron_age/coalburner.lua b/iron_age/coalburner.lua new file mode 100644 index 0000000..9b3974f --- /dev/null +++ b/iron_age/coalburner.lua @@ -0,0 +1,191 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Coalburner as heater for the Meltingpot + +]]-- + + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +local function num_coal(pos) + local pos1 = {x=pos.x, y=pos.y+1, z=pos.z} + local pos2 = {x=pos.x, y=pos.y+32, z=pos.z} + local nodes = minetest.find_nodes_in_area(pos1, pos2, {"techage:charcoal", "techage:charcoal_burn"}) + return #nodes +end + +local function num_cobble(pos, height) + local pos1 = {x=pos.x-1, y=pos.y+1, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y+height, z=pos.z+1} + local nodes = minetest.find_nodes_in_area(pos1, pos2, {"default:cobble", "default:desert_cobble"}) + return #nodes +end + +local function start_burner(pos, height) + local pos1 = {x=pos.x-1, y=pos.y+1, z=pos.z-1} + local pos2 = {x=pos.x+1, y=pos.y+height, z=pos.z+1} + techage.ironage_swap_nodes(pos1, pos2, "techage:charcoal", "techage:charcoal_burn") +end + +local function remove_flame(pos, height) + local idx + pos = {x=pos.x, y=pos.y+height, z=pos.z} + for idx=height,1,-1 do + pos = {x=pos.x, y=pos.y+1, z=pos.z} + local node = minetest.get_node(pos) + if string.find(node.name, "techage:flame") then + minetest.remove_node(pos) + elseif node.name == "techage:meltingpot" then + techage.update_heat(pos) + end + end +end + +local function flame(pos, height, heat, first_time) + local idx + pos = {x=pos.x, y=pos.y+height, z=pos.z} + for idx=heat,1,-1 do + pos = {x=pos.x, y=pos.y+1, z=pos.z} + idx = math.min(idx, 12) + local node = minetest.get_node(pos) + if node.name == "techage:meltingpot_active" then + return + end + if node.name == "techage:meltingpot" then + if first_time then + techage.switch_to_active(pos) + else + techage.update_heat(pos) + end + return + end + minetest.add_node(pos, {name = "techage:flame"..math.min(idx,7)}) + local meta = minetest.get_meta(pos) + meta:set_int("heat", idx) + end +end + + +lRatio = {120, 110, 95, 75, 55, 28, 0} +lColor = {"000080", "400040", "800000", "800000", "800000", "800000", "800000"} +for idx,ratio in ipairs(lRatio) do + local color = "techage_flame_animated.png^[colorize:#"..lColor[idx].."B0:"..ratio + minetest.register_node("techage:flame"..idx, { + tiles = { + { + name = color, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1 + }, + }, + }, + + after_destruct = function(pos, oldnode) + pos.y = pos.y + 1 + local node = minetest.get_node(pos) + if minetest.get_item_group(node.name, "techage_flame") > 0 then + minetest.remove_node(pos) + end + end, + + use_texture_alpha = true, + inventory_image = "techage_flame.png", + paramtype = "light", + light_source = 13, + walkable = false, + buildable_to = true, + floodable = true, + sunlight_propagates = true, + damage_per_second = 4 + idx, + groups = {igniter = 2, dig_immediate = 3, techage_flame=1, not_in_creative_inventory=1}, + drop = "", + }) +end + +minetest.register_node("techage:ash", { + description = S("Ash"), + tiles = {"techage_ash.png"}, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-4/8, -4/8, -4/8, 4/8, -3/8, 4/8}, + }, + }, + is_ground_content = false, + groups = {crumbly = 3, not_in_creative_inventory=1}, + drop = "", + sounds = default.node_sound_defaults(), +}) + +function techage.start_burner(pos, playername) + local height = num_coal(pos) + if minetest.is_protected( + {x=pos.x, y=pos.y+height, z=pos.z}, + playername) then + return + 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("height", height) + start_burner(pos, height) + flame(pos, height, height, true) + local handle = minetest.sound_play("techage", { + pos = {x=pos.x, y=pos.y+height, z=pos.z}, + max_hear_distance = 20, + gain = height/32.0, + loop = true}) + meta:set_int("handle", handle) + minetest.get_node_timer(pos):start(5) + end +end + +function techage.keep_running_burner(pos) + local meta = minetest.get_meta(pos) + local height = meta:get_int("height") + remove_flame(pos, height) + local handle = meta:get_int("handle") + if handle then + minetest.sound_stop(handle) + meta:set_int("handle", 0) + end + if num_cobble(pos, height) == height * 8 then + local new_height = num_coal(pos) + if new_height > 0 then + flame(pos, height, new_height, false) + handle = minetest.sound_play("techage", { + pos = {x=pos.x, y=pos.y+height, z=pos.z}, + max_hear_distance = 32, + gain = new_height/32.0, + loop = true}) + meta:set_int("handle", handle) + else + minetest.swap_node(pos, {name="techage:ash"}) + return false + end + return true + end + return true +end + +function techage.stop_burner(pos) + local meta = minetest.get_meta(pos) + local height = meta:get_int("height") + remove_flame(pos, height) + local handle = meta:get_int("handle") + minetest.sound_stop(handle) +end diff --git a/iron_age/gravelsieve.lua b/iron_age/gravelsieve.lua index 4ae7461..325dbef 100644 --- a/iron_age/gravelsieve.lua +++ b/iron_age/gravelsieve.lua @@ -8,7 +8,7 @@ LGPLv2.1+ See LICENSE.txt for more information - TA2/TA3/TA4 Gravel Sieve, sieving gravel to find ores + Gravel Sieve, sieving gravel to find ores ]]-- diff --git a/iron_age/lighter.lua b/iron_age/lighter.lua new file mode 100644 index 0000000..03ed0f6 --- /dev/null +++ b/iron_age/lighter.lua @@ -0,0 +1,91 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Lighter for Coalburner and Charcoalpile + +]]-- + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +minetest.register_node("techage:lighter_burn", { + tiles = {"techage_lighter_burn.png"}, + + after_place_node = function(pos) + techage.start_pile(pos) + end, + + on_timer = function(pos, elapsed) + return techage.keep_running_pile(pos) + end, + + on_destruct = function(pos) + techage.stop_pile(pos) + end, + + drop = "", + light_source = 10, + is_ground_content = false, + groups = {crumbly = 2, not_in_creative_inventory=1}, + sounds = default.node_sound_dirt_defaults(), +}) + +minetest.register_node("techage:coal_lighter_burn", { + tiles = {"techage_lighter_burn.png"}, + + after_place_node = function(pos) + local meta = minetest.get_meta(pos) + local playername = meta:get_string("playername") + techage.start_burner(pos, playername) + end, + + on_timer = function(pos, elapsed) + return techage.keep_running_burner(pos) + end, + + on_destruct = function(pos) + techage.stop_burner(pos) + end, + + drop = "", + light_source = 10, + is_ground_content = false, + groups = {crumbly = 2, not_in_creative_inventory=1}, + sounds = default.node_sound_dirt_defaults(), +}) + +minetest.register_node("techage:lighter", { + description = S("Lighter"), + tiles = {"techage_lighter.png"}, + on_ignite = function(pos, igniter) + if minetest.find_node_near(pos, 1, "techage:charcoal") then + minetest.after(1, techage.ironage_swap_node, pos, "techage:coal_lighter_burn") + else + minetest.after(1, techage.ironage_swap_node, pos, "techage:lighter_burn") + end + end, + after_place_node = function(pos, placer) + local meta = minetest.get_meta(pos) + meta:set_string("playername", placer:get_player_name()) + end, + is_ground_content = false, + groups = {crumbly = 2, flammable = 2}, + sounds = default.node_sound_dirt_defaults(), +}) + +minetest.register_craft({ + output = 'techage:lighter 2', + recipe = { + {'group:wood'}, + {'farming:straw'}, + {''}, + } +}) diff --git a/iron_age/main.lua b/iron_age/main.lua new file mode 100644 index 0000000..03b8391 --- /dev/null +++ b/iron_age/main.lua @@ -0,0 +1,29 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + +]]-- + +function techage.ironage_swap_node(pos, name) + minetest.swap_node(pos, {name = name}) + local node = minetest.registered_nodes[name] + if node.on_construct then + node.on_construct(pos) + end + if node.after_place_node then + node.after_place_node(pos) + end +end + +function techage.ironage_swap_nodes(pos1, pos2, name1, name2) + for _,p in ipairs(minetest.find_nodes_in_area(pos1, pos2, name1)) do + techage.ironage_swap_node(p, name2) + end +end + diff --git a/iron_age/meltingpot.lua b/iron_age/meltingpot.lua new file mode 100644 index 0000000..629473e --- /dev/null +++ b/iron_age/meltingpot.lua @@ -0,0 +1,534 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Meltingpot to produce metal and alloy ingots + +]]-- + + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + +local SMELTING_TIME = 2 + +local Tabs = S("Menu,Recipes") + +local Recipes = {} -- registered recipes +local KeyList = {} -- index to Recipes key translation +local NumRecipes = 0 +local Cache = {} -- store melting pot inventory data + +-- formspec images +local function draw(images) + local tbl = {} + for y=0,4 do + for x=0,4 do + local idx = 1 + x + y * 5 + local img = images[idx] + if img ~= false then + tbl[#tbl+1] = "image["..(x*0.8)..","..(y*0.8)..";0.8,0.8;"..img..".png]" + end + end + end + return table.concat(tbl) +end + +local formspec1 = + "size[8,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "tabheader[0,0;tab;"..Tabs..";1;;true]".. + "label[1,0.2;"..S("Menu").."]".. + + "container[1,1]".. + "list[current_name;src;0,0;2,2;]".. + "item_image[2.6,0;0.8,0.8;techage:meltingpot]".. + "image[2.3,0.6;1.6,1;gui_furnace_arrow_bg.png^[transformR270]".. + "list[current_name;dst;4,0;2,2;]".. + "container_end[]".. + + "list[current_player;main;0,4;8,4;]".. + "listring[current_name;dst]".. + "listring[current_player;main]".. + "listring[current_name;src]".. + "listring[current_player;main]" + +local function formspec2(idx) + idx = math.min(idx, #KeyList) + local key = KeyList[idx] + local input1 = Recipes[key].input[1] or "" + local input2 = Recipes[key].input[2] or "" + local input3 = Recipes[key].input[3] or "" + local input4 = Recipes[key].input[4] or "" + local num = Recipes[key].number + local heat = Recipes[key].heat + local time = Recipes[key].time + local output = Recipes[key].output + if num > 1 then + output = output.." "..num + end + return "size[8,8]".. + default.gui_bg.. + default.gui_bg_img.. + default.gui_slots.. + "tabheader[0,0;tab;"..Tabs..";2;;true]".. + "label[1,0.2;"..S("Melting Guide").."]".. + + "container[1,1]".. + "item_image_button[0,0;1,1;"..input1..";b1;]".. + "item_image_button[1,0;1,1;"..input2..";b2;]".. + "item_image_button[0,1;1,1;"..input3..";b3;]".. + "item_image_button[1,1;1,1;"..input4..";b4;]".. + "item_image[2.6,0;0.8,0.8;techage:meltingpot]".. + "image[2.3,0.6;1.6,1;gui_furnace_arrow_bg.png^[transformR270]".. + "item_image_button[4,0.5;1,1;"..output..";b5;]".. + "label[2,2.2;"..S("Heat")..": "..heat.." / "..S("Time")..": "..time.." s]".. + "label[2,4;Recipe "..idx.." of "..NumRecipes.."]".. + "button[2,5.5;1,1;priv;<<]".. + "button[3,5.5;1,1;next;>>]".. + "container_end[]" +end + +local function on_receive_fields(pos, formname, fields, sender) + local meta = minetest.get_meta(pos) + local recipe_idx = meta:get_int("recipe_idx") + if recipe_idx == 0 then recipe_idx = 1 end + if fields.tab == "1" then + meta:set_string("formspec", formspec1) + elseif fields.tab == "2" then + meta:set_string("formspec", formspec2(recipe_idx)) + elseif fields.next == ">>" then + recipe_idx = math.min(recipe_idx + 1, NumRecipes) + meta:set_int("recipe_idx", recipe_idx) + meta:set_string("formspec", formspec2(recipe_idx)) + elseif fields.priv == "<<" then + recipe_idx = math.max(recipe_idx - 1, 1) + meta:set_int("recipe_idx", recipe_idx) + meta:set_string("formspec", formspec2(recipe_idx)) + end +end + +local function can_dig(pos, player) + local meta = minetest.get_meta(pos); + local inv = meta:get_inventory() + return inv:is_empty("dst") and inv:is_empty("src") +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 + 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 + +-- generate an unique key based on the unsorted and +-- variable number of inventory items +local function recipe_key(items) + local tbl = {} + -- remove items which exist more than once + for _,item in ipairs(items) do + tbl[item] = true + end + local names = {} + for key,_ in pairs(tbl) do + names[#names + 1] = key + end + -- bring in a sorted order + table.sort(names) + return table.concat(names, "-") +end + +-- determine recipe based on inventory items +local function get_recipe(inv) + -- collect items + local stacks = {} + local names = {} + for _,stack in ipairs(inv:get_list("src")) do + if not stack:is_empty() then + table.insert(names, stack:get_name()) + table.insert(stacks, stack) + else + table.insert(stacks, ItemStack("")) + end + end + local key = recipe_key(names) + local recipe = Recipes[key] + + if recipe then + return { + input = recipe.input, + stacks = stacks, + output = ItemStack(recipe.output.." "..recipe.number), + heat = recipe.heat, + time = recipe.time, + } + end + return nil +end + +-- prepare recipe and store in cache table for faster access +local function store_recipe_in_cache(pos) + local hash = minetest.hash_node_position(pos) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + local recipe = get_recipe(inv) + Cache[hash] = recipe + return recipe +end + +-- read value from the node below +local function get_heat(pos) + local heat = 0 + pos.y = pos.y - 1 + local node = minetest.get_node(pos) + local meta = minetest.get_meta(pos) + pos.y = pos.y + 1 + if minetest.get_item_group(node.name, "techage_flame") > 0 then + heat = meta:get_int("heat") + end + return heat +end + +-- Start melting if heat is ok AND source items available +function techage.switch_to_active(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + local recipe = store_recipe_in_cache(pos) + + if recipe and heat >= recipe.heat then + minetest.swap_node(pos, {name = "techage:meltingpot_active"}) + minetest.registered_nodes["techage:meltingpot_active"].on_construct(pos) + meta:set_string("infotext", S("Melting Pot active (heat=")..heat..")") + minetest.get_node_timer(pos):start(2) + return true + end + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") + return false +end + +function techage.update_heat(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") +end + +local function set_inactive(meta, pos, heat) + minetest.get_node_timer(pos):stop() + minetest.swap_node(pos, {name = "techage:meltingpot"}) + minetest.registered_nodes["techage:meltingpot"].on_construct(pos) + meta:set_string("infotext", S("Melting Pot inactive (heat=")..heat..")") +end + +-- Stop melting if heat to low OR no source items available +local function switch_to_inactive(pos) + local meta = minetest.get_meta(pos) + local heat = get_heat(pos) + local hash = minetest.hash_node_position(pos) + local recipe = Cache[hash] or store_recipe_in_cache(pos) + + if not recipe or heat < recipe.heat then + set_inactive(meta, pos, heat) + return true + end + meta:set_string("infotext", S("Melting Pot active (heat=")..heat..")") + return false +end + + +local function index(list, x) + for idx, v in pairs(list) do + if v == x then return idx end + end + return nil +end + +-- move recipe src items to output inventory +local function process(inv, recipe, heat) + if heat < recipe.heat then + return false + end + local res = false + if inv:room_for_item("dst", recipe.output) then + for _,item in ipairs(recipe.input) do + res = false + for _, stack in ipairs(recipe.stacks) do + if stack:get_count() > 0 and stack:get_name() == item then + stack:take_item(1) + res = true + break + end + end + if res == false then + return false + end + end + inv:add_item("dst", recipe.output) + inv:set_list("src", recipe.stacks) + return true + end + return false +end + +local function smelting(pos, recipe, heat, elapsed) + local meta = minetest.get_meta(pos) + local inv = meta:get_inventory() + elapsed = elapsed + meta:get_int("leftover") + + while elapsed >= recipe.time do + if process(inv, recipe, heat) == false then + meta:set_int("leftover", 0) + set_inactive(meta, pos, heat) + return false + end + elapsed = elapsed - recipe.time + end + meta:set_int("leftover", elapsed) + return true +end + +local function pot_node_timer(pos, elapsed) + if switch_to_inactive(pos) == false then + local hash = minetest.hash_node_position(pos) + local heat = get_heat(pos) + local recipe = Cache[hash] or store_recipe_in_cache(pos) + if recipe then + return smelting(pos, recipe, heat, elapsed) + end + end + return false +end + +minetest.register_node("techage:meltingpot_active", { + description = S("Melting Pot"), + tiles = { + { + image = "techage_meltingpot_top_active.png", + backface_culling = false, + animation = { + type = "vertical_frames", + aspect_w = 16, + aspect_h = 16, + length = 1, + }, + }, + "default_cobble.png^techage_meltingpot.png", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-10/16, -8/16, -10/16, 10/16, 9/16, -6/16}, + {-10/16, -8/16, 6/16, 10/16, 9/16, 10/16}, + {-10/16, -8/16, -10/16, -6/16, 9/16, 10/16}, + { 6/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + { -6/16, -8/16, -6/16, 6/16, 5/16, 6/16}, + }, + }, + selection_box = { + type = "fixed", + fixed = {-10/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec1) + local inv = meta:get_inventory() + inv:set_size('src', 4) + inv:set_size('dst', 4) + end, + + on_timer = function(pos, elapsed) + return pot_node_timer(pos, elapsed) + end, + + on_receive_fields = function(pos, formname, fields, sender) + on_receive_fields(pos, formname, fields, sender) + end, + + on_metadata_inventory_move = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + on_metadata_inventory_put = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + on_metadata_inventory_take = function(pos) + store_recipe_in_cache(pos) + switch_to_inactive(pos) + end, + + can_dig = can_dig, + + drop = "techage:meltingpot", + is_ground_content = false, + groups = {cracky = 3, not_in_creative_inventory=1}, + sounds = default.node_sound_metal_defaults(), + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, +}) + +minetest.register_node("techage:meltingpot", { + description = S("Melting Pot"), + tiles = { + "default_cobble.png", + "default_cobble.png^techage_meltingpot.png", + }, + drawtype = "nodebox", + node_box = { + type = "fixed", + fixed = { + {-10/16, -8/16, -10/16, 10/16, 9/16, -6/16}, + {-10/16, -8/16, 6/16, 10/16, 9/16, 10/16}, + {-10/16, -8/16, -10/16, -6/16, 9/16, 10/16}, + { 6/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + { -6/16, -8/16, -6/16, 6/16, -4/16, 6/16}, + }, + }, + selection_box = { + type = "fixed", + fixed = {-10/16, -8/16, -10/16, 10/16, 9/16, 10/16}, + }, + + on_construct = function(pos) + local meta = minetest.get_meta(pos) + meta:set_string("formspec", formspec1) + meta:set_string("infotext", S("Melting Pot inactive (heat=0)")) + local inv = meta:get_inventory() + inv:set_size('src', 4) + inv:set_size('dst', 4) + end, + + on_metadata_inventory_move = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_metadata_inventory_put = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_metadata_inventory_take = function(pos) + store_recipe_in_cache(pos) + techage.switch_to_active(pos) + end, + + on_receive_fields = function(pos, formname, fields, sender) + on_receive_fields(pos, formname, fields, sender) + end, + + can_dig = can_dig, + + is_ground_content = false, + groups = {cracky = 3}, + sounds = default.node_sound_metal_defaults(), + + allow_metadata_inventory_put = allow_metadata_inventory_put, + allow_metadata_inventory_move = allow_metadata_inventory_move, + allow_metadata_inventory_take = allow_metadata_inventory_take, +}) + +minetest.register_craft({ + output = "techage:meltingpot", + recipe = { + {"default:cobble", "default:copper_ingot", "default:cobble"}, + {"default:cobble", "", "default:cobble"}, + {"default:cobble", "default:cobble", "default:cobble"}, + }, +}) + +if minetest.global_exists("unified_inventory") then + unified_inventory.register_craft_type("melting", { + description = S("Melting"), + icon = "default_cobble.png^techage_meltingpot.png", + width = 2, + height = 2, + }) + unified_inventory.register_craft_type("burning", { + description = S("Burning"), + icon = "techage_smoke.png", + width = 1, + height = 1, + }) + unified_inventory.register_craft({ + output = "techage:charcoal", + items = {"group:wood"}, + type = "burning", + }) +end + +function techage.ironage_register_recipe(recipe) + local key = recipe_key(recipe.recipe) + local output = string.split(recipe.output, " ") + local number = tonumber(output[2] or 1) + table.insert(KeyList, key) + Recipes[key] = { + input = recipe.recipe, + output = output[1], + number = number, + heat = math.max(recipe.heat or 3, 2), + time = math.max(recipe.time or 2, 2*number), + } + NumRecipes = NumRecipes + 1 + + if minetest.global_exists("unified_inventory") then + recipe.items = recipe.recipe + recipe.type = "melting" + unified_inventory.register_craft(recipe) + end +end + + +techage.ironage_register_recipe({ + output = "default:obsidian", + recipe = {"default:cobble"}, + heat = 5, + time = 4, +}) + +techage.ironage_register_recipe({ + output = "default:coral_skeleton", + recipe = {"gravelsieve:compressed_gravel"}, + heat = 4, + time = 4, +}) + +techage.ironage_register_recipe({ + output = "default:bronze_ingot 4", + recipe = {"default:copper_ingot", "default:copper_ingot", "default:copper_ingot", "default:tin_ingot"}, + heat = 4, + time = 8, +}) + diff --git a/iron_age/meridium.lua b/iron_age/meridium.lua new file mode 100644 index 0000000..9150f3d --- /dev/null +++ b/iron_age/meridium.lua @@ -0,0 +1,128 @@ +--[[ + + TechAge + ======= + + Copyright (C) 2019 Joachim Stolberg + + LGPLv2.1+ + See LICENSE.txt for more information + + Brilliant Meririum and tools (mod "wielded_light" needed) + +]]-- + +-- Load support for intllib. +local MP = minetest.get_modpath("techage") +local S, NS = dofile(MP.."/intllib.lua") + + +minetest.register_craftitem("techage:meridium_ingot", { + description = "Meridium Ingot", + inventory_image = "techage_meridium_ingot.png", +}) + + +minetest.register_tool("techage:pick_meridium", { + description = S("Meridium Pickaxe"), + inventory_image = "techage_meridiumpick.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + cracky = {times={[1]=4.00, [2]=1.60, [3]=0.80}, uses=30, maxlevel=2}, + }, + damage_groups = {fleshy=4}, + }, + sound = {breaks = "default_tool_breaks"}, + light_source = 12, +}) + +minetest.register_tool("techage:shovel_meridium", { + description = S("Meridium Shovel"), + inventory_image = "techage_meridiumshovel.png", + wield_image = "techage_meridiumshovel.png^[transformR90", + tool_capabilities = { + full_punch_interval = 1.1, + max_drop_level=1, + groupcaps={ + crumbly = {times={[1]=1.50, [2]=0.90, [3]=0.40}, uses=40, maxlevel=2}, + }, + damage_groups = {fleshy=3}, + }, + sound = {breaks = "default_tool_breaks"}, + light_source = 12, +}) + +minetest.register_tool("techage:axe_meridium", { + description = S("Meridium Axe"), + inventory_image = "techage_meridiumaxe.png", + tool_capabilities = { + full_punch_interval = 1.0, + max_drop_level=1, + groupcaps={ + choppy={times={[1]=2.50, [2]=1.40, [3]=1.00}, uses=20, maxlevel=2}, + }, + damage_groups = {fleshy=4}, + }, + sound = {breaks = "default_tool_breaks"}, + light_source = 12, +}) + +minetest.register_tool("techage:sword_meridium", { + description = S("Meridium Sword"), + inventory_image = "techage_meridiumsword.png", + tool_capabilities = { + full_punch_interval = 0.8, + max_drop_level=1, + groupcaps={ + snappy={times={[1]=2.5, [2]=1.20, [3]=0.35}, uses=30, maxlevel=2}, + }, + damage_groups = {fleshy=6}, + }, + sound = {breaks = "default_tool_breaks"}, + light_source = 12, +}) + +minetest.register_craft({ + output = 'techage:pick_meridium', + recipe = { + {'techage:meridium_ingot', 'techage:meridium_ingot', 'techage:meridium_ingot'}, + {'', 'group:stick', ''}, + {'', 'group:stick', ''}, + } +}) + +minetest.register_craft({ + output = 'techage:shovel_meridium', + recipe = { + {'techage:meridium_ingot'}, + {'group:stick'}, + {'group:stick'}, + } +}) + +minetest.register_craft({ + output = 'techage:axe_meridium', + recipe = { + {'techage:meridium_ingot', 'techage:meridium_ingot'}, + {'techage:meridium_ingot', 'group:stick'}, + {'', 'group:stick'}, + } +}) + +minetest.register_craft({ + output = 'techage:sword_meridium', + recipe = { + {'techage:meridium_ingot'}, + {'techage:meridium_ingot'}, + {'group:stick'}, + } +}) + +techage.register_recipe({ + output = "techage:meridium_ingot", + recipe = {"default:steel_ingot", "default:mese_crystal_fragment"}, + heat = 4, + time = 3, +}) diff --git a/mod.conf b/mod.conf index 95386aa..53d7069 100644 --- a/mod.conf +++ b/mod.conf @@ -1,3 +1,4 @@ name = techage -depends = default, tubelib2, basic_materials +depends = default,tubelib2,basic_materials +optional_depends = unified_inventory,wielded_light description = Hello World! \ No newline at end of file diff --git a/steam_engine/firebox.lua b/steam_engine/firebox.lua index 6f88ee1..8c08994 100644 --- a/steam_engine/firebox.lua +++ b/steam_engine/firebox.lua @@ -23,85 +23,11 @@ local TRD = function(pos) return (minetest.registered_nodes[minetest.get_node(po local MP = minetest.get_modpath("techage") local I,_ = dofile(MP.."/intllib.lua") +local firebox = techage.firebox + local CYCLE_TIME = 2 -local BURN_CYCLES = 10 -local Fuels = { - ["techage:charcoal"] = true, - ["default:coal_lump"] = true, - ["default:coalblock"] = true, -} - -local function formspec(mem) - local fuel_percent = 0 - if mem.running then - fuel_percent = (mem.burn_cycles * 100) / BURN_CYCLES - end - return "size[8,6]".. - default.gui_bg.. - default.gui_bg_img.. - default.gui_slots.. - "list[current_name;fuel;1,0.5;1,1;]".. - "image[3,0.5;1,1;default_furnace_fire_bg.png^[lowpart:".. - fuel_percent..":default_furnace_fire_fg.png]".. - "button[5,0.5;1.8,1;update;"..I("Update").."]".. - "list[current_player;main;0,2;8,4;]".. - "listring[current_name;fuel]".. - "listring[current_player;main]".. - default.get_hotbar_bg(0, 2) -end - -local function can_dig(pos, player) - local inv = M(pos):get_inventory() - return inv:is_empty("fuel") -end - -local function allow_metadata_inventory(pos, listname, index, stack, player) - if minetest.is_protected(pos, player:get_player_name()) then - return 0 - end - if Fuels[stack:get_name()] then - return stack:get_count() - end - return 0 -end - -local function on_receive_fields(pos, formname, fields, player) - if minetest.is_protected(pos, player:get_player_name()) then - return - end - - if fields.update then - local mem = tubelib2.get_mem(pos) - M(pos):set_string("formspec", formspec(mem)) - end -end - -local function on_rightclick(pos, node, clicker) - local mem = tubelib2.get_mem(pos) - M(pos):set_string("formspec", formspec(mem)) -end - -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 - -local function get_fuel(pos) - local inv = M(pos):get_inventory() - local items = inv:get_stack("fuel", 1) - if items:get_count() > 0 then - local taken = items:take_item(1) - inv:set_stack("fuel", 1, items) - return taken - end -end - local function node_timer(pos, elapsed) local mem = tubelib2.get_mem(pos) if mem.running then @@ -111,12 +37,14 @@ local function node_timer(pos, elapsed) end mem.burn_cycles = (mem.burn_cycles or 0) - 1 if mem.burn_cycles <= 0 then - if get_fuel(pos) then - mem.burn_cycles = BURN_CYCLES + local taken = firebox.get_fuel(pos) + if taken then + mem.burn_cycles = firebox.Burntime[taken:get_name()] / CYCLE_TIME + mem.burn_cycles_total = mem.burn_cycles else mem.running = false - swap_node(pos, "techage:firebox") - M(pos):set_string("formspec", formspec(mem)) + firebox.swap_node(pos, "techage:firebox") + M(pos):set_string("formspec", firebox.formspec(mem)) return false end end @@ -142,30 +70,31 @@ minetest.register_node("techage:firebox", { sounds = default.node_sound_stone_defaults(), on_timer = node_timer, - can_dig = can_dig, - allow_metadata_inventory_put = allow_metadata_inventory, - allow_metadata_inventory_take = allow_metadata_inventory, - on_receive_fields = on_receive_fields, - on_rightclick = on_rightclick, + can_dig = firebox.can_dig, + allow_metadata_inventory_put = firebox.allow_metadata_inventory, + allow_metadata_inventory_take = firebox.allow_metadata_inventory, + on_receive_fields = firebox.on_receive_fields, + on_rightclick = firebox.on_rightclick, on_construct = function(pos) local mem = tubelib2.init_mem(pos) mem.running = false mem.burn_cycles = 0 local meta = M(pos) - meta:set_string("formspec", formspec(mem)) + meta:set_string("formspec", firebox.formspec(mem)) local inv = meta:get_inventory() inv:set_size('fuel', 1) end, - on_metadata_inventory_put = function(pos) + on_metadata_inventory_put = function(pos, listname, index, stack, player) local mem = tubelib2.init_mem(pos) mem.running = true -- activate the formspec fire temporarily - mem.burn_cycles = BURN_CYCLES - M(pos):set_string("formspec", formspec(mem)) + mem.burn_cycles = firebox.Burntime[stack:get_name()] / CYCLE_TIME + mem.burn_cycles_total = mem.burn_cycles + M(pos):set_string("formspec", firebox.formspec(mem)) mem.burn_cycles = 0 - swap_node(pos, "techage:firebox_on") + firebox.swap_node(pos, "techage:firebox_on") minetest.get_node_timer(pos):start(CYCLE_TIME) end, }) @@ -199,10 +128,10 @@ minetest.register_node("techage:firebox_on", { drop = "techage:firebox", on_timer = node_timer, - can_dig = can_dig, - allow_metadata_inventory_put = allow_metadata_inventory, - allow_metadata_inventory_take = allow_metadata_inventory, - on_receive_fields = on_receive_fields, - on_rightclick = on_rightclick, + can_dig = firebox.can_dig, + allow_metadata_inventory_put = firebox.allow_metadata_inventory, + allow_metadata_inventory_take = firebox.allow_metadata_inventory, + on_receive_fields = firebox.on_receive_fields, + on_rightclick = firebox.on_rightclick, }) diff --git a/textures/techage_appl_distri.png b/textures/techage_appl_distri.png index 9361894..b3ad288 100644 Binary files a/textures/techage_appl_distri.png and b/textures/techage_appl_distri.png differ diff --git a/textures/techage_appl_distri4.png b/textures/techage_appl_distri4.png index 06233a9..ad2494e 100644 Binary files a/textures/techage_appl_distri4.png and b/textures/techage_appl_distri4.png differ diff --git a/textures/techage_appl_distri_blue.png b/textures/techage_appl_distri_blue.png index ab28407..a9eb9c5 100644 Binary files a/textures/techage_appl_distri_blue.png and b/textures/techage_appl_distri_blue.png differ diff --git a/textures/techage_appl_distri_green.png b/textures/techage_appl_distri_green.png index 801c04b..3ff3193 100644 Binary files a/textures/techage_appl_distri_green.png and b/textures/techage_appl_distri_green.png differ diff --git a/textures/techage_appl_distri_red.png b/textures/techage_appl_distri_red.png index 490083f..9f99781 100644 Binary files a/textures/techage_appl_distri_red.png and b/textures/techage_appl_distri_red.png differ diff --git a/textures/techage_appl_distri_yellow.png b/textures/techage_appl_distri_yellow.png index 0279786..12f47dd 100644 Binary files a/textures/techage_appl_distri_yellow.png and b/textures/techage_appl_distri_yellow.png differ diff --git a/textures/techage_appl_firehole4.png b/textures/techage_appl_firehole4.png index b0ccec3..5aee730 100644 Binary files a/textures/techage_appl_firehole4.png and b/textures/techage_appl_firehole4.png differ diff --git a/textures/techage_appl_grinder2.png b/textures/techage_appl_grinder2.png new file mode 100644 index 0000000..47d8566 Binary files /dev/null and b/textures/techage_appl_grinder2.png differ diff --git a/textures/techage_appl_hole_electric.png b/textures/techage_appl_hole_electric.png index 916592e..da19107 100644 Binary files a/textures/techage_appl_hole_electric.png and b/textures/techage_appl_hole_electric.png differ diff --git a/textures/techage_appl_sieve.png b/textures/techage_appl_sieve.png index c0d6515..109d863 100644 Binary files a/textures/techage_appl_sieve.png and b/textures/techage_appl_sieve.png differ diff --git a/textures/techage_appl_sieve4.png b/textures/techage_appl_sieve4.png index deaa6f7..50061a6 100644 Binary files a/textures/techage_appl_sieve4.png and b/textures/techage_appl_sieve4.png differ diff --git a/textures/techage_appl_sieve4_top.png b/textures/techage_appl_sieve4_top.png index 6a836ad..edcf126 100644 Binary files a/textures/techage_appl_sieve4_top.png and b/textures/techage_appl_sieve4_top.png differ diff --git a/textures/techage_appl_sieve_top.png b/textures/techage_appl_sieve_top.png index d54fe63..ce3658f 100644 Binary files a/textures/techage_appl_sieve_top.png and b/textures/techage_appl_sieve_top.png differ diff --git a/textures/techage_ash.png b/textures/techage_ash.png new file mode 100644 index 0000000..430148c Binary files /dev/null and b/textures/techage_ash.png differ diff --git a/textures/techage_ash_side.png b/textures/techage_ash_side.png new file mode 100644 index 0000000..4efa1a3 Binary files /dev/null and b/textures/techage_ash_side.png differ diff --git a/textures/techage_charcoal.png b/textures/techage_charcoal.png new file mode 100644 index 0000000..1418812 Binary files /dev/null and b/textures/techage_charcoal.png differ diff --git a/textures/techage_charcoal_burn.png b/textures/techage_charcoal_burn.png new file mode 100644 index 0000000..7fbb0e2 Binary files /dev/null and b/textures/techage_charcoal_burn.png differ diff --git a/textures/techage_coal_boiler.png b/textures/techage_coal_boiler.png new file mode 100644 index 0000000..51b92d5 Binary files /dev/null and b/textures/techage_coal_boiler.png differ diff --git a/textures/techage_coal_boiler4.png b/textures/techage_coal_boiler4.png new file mode 100644 index 0000000..2313ed0 Binary files /dev/null and b/textures/techage_coal_boiler4.png differ diff --git a/textures/techage_coal_boiler_fire_hole.png b/textures/techage_coal_boiler_fire_hole.png new file mode 100644 index 0000000..4b2f7be Binary files /dev/null and b/textures/techage_coal_boiler_fire_hole.png differ diff --git a/textures/techage_coal_boiler_hole.png b/textures/techage_coal_boiler_hole.png new file mode 100644 index 0000000..bf51cc3 Binary files /dev/null and b/textures/techage_coal_boiler_hole.png differ diff --git a/textures/techage_coal_boiler_inv.png b/textures/techage_coal_boiler_inv.png new file mode 100644 index 0000000..a5a8f27 Binary files /dev/null and b/textures/techage_coal_boiler_inv.png differ diff --git a/textures/techage_coal_boiler_mesh.png b/textures/techage_coal_boiler_mesh.png new file mode 100644 index 0000000..46373a4 Binary files /dev/null and b/textures/techage_coal_boiler_mesh.png differ diff --git a/textures/techage_electric_junction.png b/textures/techage_electric_junction.png index 5d9b576..e0464b1 100644 Binary files a/textures/techage_electric_junction.png and b/textures/techage_electric_junction.png differ diff --git a/textures/techage_frame4_ta4_top.png b/textures/techage_frame4_ta4_top.png index 38d61be..17c2032 100644 Binary files a/textures/techage_frame4_ta4_top.png and b/textures/techage_frame4_ta4_top.png differ diff --git a/textures/techage_handsieve_sieve.png b/textures/techage_handsieve_sieve.png index dbf785c..109f357 100644 Binary files a/textures/techage_handsieve_sieve.png and b/textures/techage_handsieve_sieve.png differ diff --git a/textures/techage_handsieve_top.png b/textures/techage_handsieve_top.png index 32f6159..3565eee 100644 Binary files a/textures/techage_handsieve_top.png and b/textures/techage_handsieve_top.png differ diff --git a/textures/techage_lighter.png b/textures/techage_lighter.png new file mode 100644 index 0000000..47ec8cc Binary files /dev/null and b/textures/techage_lighter.png differ diff --git a/textures/techage_lighter_burn.png b/textures/techage_lighter_burn.png new file mode 100644 index 0000000..52c435b Binary files /dev/null and b/textures/techage_lighter_burn.png differ diff --git a/textures/techage_meltingpot.png b/textures/techage_meltingpot.png new file mode 100644 index 0000000..5d220d9 Binary files /dev/null and b/textures/techage_meltingpot.png differ diff --git a/textures/techage_meltingpot_top_active.png b/textures/techage_meltingpot_top_active.png new file mode 100644 index 0000000..1e95256 Binary files /dev/null and b/textures/techage_meltingpot_top_active.png differ diff --git a/textures/techage_meridium_ingot.png b/textures/techage_meridium_ingot.png new file mode 100644 index 0000000..7bd3c1e Binary files /dev/null and b/textures/techage_meridium_ingot.png differ diff --git a/textures/techage_meridiumaxe.png b/textures/techage_meridiumaxe.png new file mode 100644 index 0000000..81a2df6 Binary files /dev/null and b/textures/techage_meridiumaxe.png differ diff --git a/textures/techage_meridiumpick.png b/textures/techage_meridiumpick.png new file mode 100644 index 0000000..de24b64 Binary files /dev/null and b/textures/techage_meridiumpick.png differ diff --git a/textures/techage_meridiumshovel.png b/textures/techage_meridiumshovel.png new file mode 100644 index 0000000..2e8df10 Binary files /dev/null and b/textures/techage_meridiumshovel.png differ diff --git a/textures/techage_meridiumsword.png b/textures/techage_meridiumsword.png new file mode 100644 index 0000000..621568d Binary files /dev/null and b/textures/techage_meridiumsword.png differ diff --git a/textures/techage_smoke.png b/textures/techage_smoke.png new file mode 100644 index 0000000..07b9fae Binary files /dev/null and b/textures/techage_smoke.png differ diff --git a/textures/techage_tool_hammer_diamond.png b/textures/techage_tool_hammer_diamond.png index 5be814e..0e29bbc 100644 Binary files a/textures/techage_tool_hammer_diamond.png and b/textures/techage_tool_hammer_diamond.png differ diff --git a/textures/techage_tool_hammer_steel.png b/textures/techage_tool_hammer_steel.png index 680717e..3f64ae8 100644 Binary files a/textures/techage_tool_hammer_steel.png and b/textures/techage_tool_hammer_steel.png differ