diff --git a/api/lava_furnace.lua b/api/lava_furnace.lua
index e69de29..ac4e848 100644
--- a/api/lava_furnace.lua
+++ b/api/lava_furnace.lua
@@ -0,0 +1,365 @@
+local S = logistica.TRANSLATOR
+
+local META_LAVA_IN_TANK = "lavam"
+local META_RUNNING_TIME = "cktm"
+local META_LAST_ITEM = "lstitm"
+local META_LAVA_USED = "ufuel"
+
+local get_meta = minetest.get_meta
+
+local BUCKET_LAVA = "bucket:bucket_lava"
+local BUCKET_EMPTY = "bucket:bucket_empty"
+local LAVA_UNIT = "logistica:lava_unit"
+
+local INV_FUEL = "fuel"
+local INV_INPT = "src"
+local INV_OUTP = "dst"
+local INV_ADDI = "input"
+
+local UPDATE_INTERVAL = 1.0
+
+-- returns the lava cap in milibuckets
+local function get_lava_capacity(pos)
+ local nodeName = minetest.get_node(pos).name
+ local nodeDef = minetest.registered_nodes[nodeName]
+ if not nodeDef or not nodeDef.logistica or not nodeDef.logistica.lava_capacity then
+ return nil
+ end
+ return nodeDef.logistica.lava_capacity * 1000
+end
+
+local function fill_lava_tank_from_fuel(pos, meta, inv)
+ local itemstackName = inv:get_stack(INV_FUEL, 1):get_name()
+ if itemstackName ~= BUCKET_LAVA and itemstackName ~= LAVA_UNIT then return end
+
+ local returnStack = ItemStack("")
+ if itemstackName == BUCKET_LAVA then
+ returnStack = ItemStack(BUCKET_EMPTY)
+ end
+ local currLevel = meta:get_int(META_LAVA_IN_TANK)
+ local cap = get_lava_capacity(pos)
+ if cap - currLevel < 1000 then return end
+ currLevel = currLevel + 1000
+ meta:set_int(META_LAVA_IN_TANK, currLevel)
+ inv:set_stack(INV_FUEL, 1, returnStack)
+end
+
+-- returns running time in secs
+local function load_running_time(meta)
+ return meta:get_int(META_RUNNING_TIME) / 1000.0
+end
+
+-- newTime is in seconds
+local function save_running_time(meta, newTime)
+ meta:set_int(META_RUNNING_TIME, math.floor(newTime * 1000))
+end
+
+local function is_new_item(meta, currItemStack)
+ local currStackName = currItemStack:get_name()
+ local lastItem = meta:get_string(META_LAST_ITEM)
+ meta:set_string(META_LAST_ITEM, currStackName)
+ return currStackName ~= lastItem
+end
+
+local function get_running_time(meta, isNewItem)
+ if isNewItem then
+ save_running_time(meta, 0)
+ return 0
+ else
+ return load_running_time(meta)
+ end
+end
+
+-- returns nil if recipe for `currItemStack` cannot be fulfilled
+-- otherwise returns a table:
+-- `{input = ItemStack, output = ItemStack, lava = #, additive = ItemStack, additive_use_chance = #, time = #}`
+local function get_valid_config(meta, currItemStack)
+ local inv = meta:get_inventory()
+ local outputDef = logistica.get_lava_furnace_recipe_for(currItemStack:get_name())
+ if not outputDef then return nil end
+ local inputStack = ItemStack(currItemStack) ; inputStack:set_count(outputDef.input_count)
+ local outputStack = ItemStack(outputDef.output)
+ local additiveStack = ItemStack(outputDef.additive or "")
+ if inv:contains_item(INV_INPT, inputStack)
+ and inv:contains_item(INV_ADDI, additiveStack)
+ and inv:room_for_item(INV_OUTP, outputStack) then
+ return {
+ input = inputStack,
+ output = outputStack,
+ lava = outputDef.lava,
+ additive = additiveStack,
+ additive_use_chance = outputDef.additive_use_chance,
+ time = outputDef.time
+ }
+ else
+ return nil
+ end
+end
+
+local function save_lava_used(meta, amount)
+ meta:set_int(META_LAVA_USED, amount)
+end
+
+local function get_lava_used_so_far(meta, isNewItem)
+ if isNewItem then
+ save_lava_used(meta, 0)
+ return 0
+ else
+ return meta:get_int(META_LAVA_USED)
+ end
+end
+
+-- returns nil if there isn't enough lava (and it won't use it)
+-- otherwise uses the lava and returns the time left to completion (which may < 0 if we overshot)
+local function useLava(meta, totalLavaUse, totalTime, runningTime, elapsed, isNewItem)
+ local lavaUsedSoFar = get_lava_used_so_far(meta, isNewItem)
+ local currAmount = meta:get_int(META_LAVA_IN_TANK)
+ local lavaUse = 0
+ local remainigTime = totalTime - runningTime - elapsed
+ if remainigTime <= 0 then
+ lavaUse = math.max(0, totalLavaUse - lavaUsedSoFar) -- use up all that's left
+ else
+ lavaUse = math.round(totalLavaUse * elapsed / totalTime)
+ end
+ if currAmount - lavaUse < 0 then
+ return nil -- not enough lava in tank
+ end
+ meta:set_int(META_LAVA_IN_TANK, currAmount - lavaUse)
+ save_lava_used(meta, lavaUsedSoFar + lavaUse)
+ return remainigTime
+end
+
+--------------------------------
+-- Formspec
+--------------------------------
+
+local function get_lava_img(currLava, lavaPercent)
+ local img = ""
+ if lavaPercent > 0 then
+ img = "image[0.4,1.4;1,3;logistica_lava_furnace_tank_bg.png^[lowpart:"..
+ lavaPercent..":logistica_lava_furnace_tank.png]"
+ else
+ img = "image[0.4,1.4;1,3;logistica_lava_furnace_tank_bg.png]"
+ end
+ return img.."tooltip[0.4,1.4;1,3;"..S("Remaminig: ")..(currLava/1000)..S(" Buckets").."]"
+end
+
+local function common_formspec(pos, meta)
+ local currLava = meta:get_int(META_LAVA_IN_TANK)
+ local lavaCap = get_lava_capacity(pos) or 1
+ local lavaPercent = math.round(currLava / lavaCap * 100)
+ return "formspec_version[6]"..
+ "size[10.5,11]"..
+ "list[current_player;main;0.4,5.9;8,4;0]"..
+ "list[context;fuel;0.4,4.5;1,1;0]"..
+ "list[context;src;2.2,2.3;1,1;0]"..
+ "list[context;dst;7.8,2.3;2,2;0]"..
+ "list[context;input;4.3,0.9;2,1;0]"..
+ "label[0.5,1.1;Lava]"..
+ "label[4.7,0.5;Additives]"..
+ get_lava_img(currLava, lavaPercent)
+end
+
+local function get_inactive_formspec(pos, meta)
+ return common_formspec(pos, meta)..
+ "image[4,2.3;3,1;logistica_lava_furnace_arrow_bg.png^[transformR270]"
+end
+
+local function get_active_formspec(pos, meta, runningTime, totalTime)
+ local timePercent = math.round(runningTime / totalTime * 100)
+ local progressImg = ""
+ if timePercent > 0 then
+ progressImg = "image[4,2.3;3,1;logistica_lava_furnace_arrow_bg.png^[lowpart:"..timePercent..
+ ":logistica_lava_furnace_arrow.png^[transformR270]"
+ else
+ progressImg = "image[4,2.3;3,1;logistica_lava_furnace_arrow_bg.png^[transformR270]"
+ end
+ return common_formspec(pos, meta)..progressImg
+end
+
+local function reset_furnace(pos, meta)
+ save_running_time(meta, 0)
+ save_lava_used(meta, 0)
+ meta:set_string("formspec", get_inactive_formspec(pos, meta))
+ local node = minetest.get_node(pos)
+ local inactiveNodeName = string.gsub(node.name, "_active", "")
+ logistica.swap_node(pos, inactiveNodeName)
+end
+
+local function set_furnace_active(pos, meta, runningTime, totalTime)
+ meta:set_string("formspec", get_active_formspec(pos, meta, runningTime, totalTime))
+ local node = minetest.get_node(pos)
+ if not string.find(node.name, "_active") then
+ local activeNodeName = node.name.."_active"
+ logistica.swap_node(pos, activeNodeName)
+ end
+end
+
+--------------------------------
+-- Callbacks
+--------------------------------
+
+local function lava_furnace_node_timer(pos, elapsed)
+ local meta = get_meta(pos)
+ local inv = meta:get_inventory()
+ fill_lava_tank_from_fuel(pos, meta, inv)
+
+ repeat
+ local currItemStack = inv:get_stack(INV_INPT, 1)
+ local isNewItem = is_new_item(meta, currItemStack)
+ local runningTime = get_running_time(meta, isNewItem)
+ local config = get_valid_config(meta, currItemStack)
+
+ if not config then -- invalid input, or not enough additives or space
+ reset_furnace(pos, meta)
+ return false
+ end
+
+
+ local timeLeft = useLava(meta, config.lava, config.time, runningTime, elapsed, isNewItem)
+ if timeLeft == nil then --not enough lava left
+ reset_furnace(pos, meta)
+ return false
+ end
+ if timeLeft <= 0 then
+ elapsed = -timeLeft -- becase we overshot the target time
+ end
+
+ fill_lava_tank_from_fuel(pos, meta, inv)
+ if timeLeft <= 0 then
+ -- cook is ready
+ inv:remove_item(INV_INPT, config.input)
+ inv:add_item(INV_OUTP, config.output)
+ if config.additive
+ and config.additive_use_chance
+ and logistica.random_chance(config.additive_use_chance) then
+ inv:remove_item(INV_ADDI, config.additive)
+ end
+ save_lava_used(meta, 0)
+ save_running_time(meta, 0)
+ set_furnace_active(pos, meta, 0, config.time)
+ else -- we're still cooking, used entire elapsed time
+ runningTime = runningTime + elapsed
+ save_running_time(meta, runningTime)
+ elapsed = 0
+ set_furnace_active(pos, meta, runningTime, config.time)
+ end
+ until (elapsed <= 0)
+ return true
+end
+
+local function lava_furnace_on_construct(pos)
+ local meta = minetest.get_meta(pos)
+ local inv = meta:get_inventory()
+ inv:set_size(INV_INPT, 1)
+ inv:set_size(INV_FUEL, 1)
+ inv:set_size(INV_OUTP, 4)
+ inv:set_size(INV_ADDI, 2)
+ meta:set_string("formspec", get_inactive_formspec(pos, meta))
+ lava_furnace_node_timer(pos, 0)
+end
+
+local function lava_furnace_on_destruct(pos)
+ local meta = get_meta(pos)
+ local amount = meta:get_int(META_LAVA_IN_TANK)
+ amount = math.floor(amount / 1000)
+ if amount > 0 then
+ for i = 1, amount do
+ minetest.item_drop(
+ ItemStack("logistica:lava_unit"),
+ nil,
+ vector.add(pos, vector.new(math.random() - 0.5, 0.2, math.random() - 0.5))
+ )
+ end
+ end
+end
+
+local function lava_furnace_can_dig(pos)
+ local inv = get_meta(pos):get_inventory()
+ return (inv:is_empty(INV_INPT) and inv:is_empty(INV_FUEL)
+ and inv:is_empty(INV_OUTP) and inv:is_empty(INV_ADDI))
+end
+
+local function lava_furnace_allow_metadata_inv_put(pos, listname, index, stack, player)
+ if listname == INV_INPT or listname == INV_ADDI then
+ return stack:get_count()
+ elseif listname == INV_FUEL
+ and (stack:get_name() == BUCKET_LAVA or stack:get_name() == LAVA_UNIT) then
+ return 1
+ else
+ return 0
+ end
+end
+
+local function lava_furnace_allow_metadata_inv_take(pos, listname, index, stack, player)
+ return stack:get_count()
+end
+
+local function lava_furnace_allow_metadata_inv_move(pos, from_list, from_index, to_list, to_index, count, player)
+ if to_list == INV_ADDI or to_list == INV_INPT then
+ return count
+ elseif to_list == INV_FUEL then
+ if get_meta(pos):get_inventory():get_stack(from_list, from_index):get_name() == BUCKET_LAVA then
+ return count
+ else
+ return 0
+ end
+ else
+ return 0
+ end
+end
+
+local function lava_furnace_on_inv_change(pos)
+ -- local timer = minetest.get_node_timer(pos)
+ -- if not timer:is_started() and lava_furnace_node_timer(pos, 0) then
+ -- timer:start(UPDATE_INTERVAL)
+ -- end
+ logistica.start_node_timer(pos, UPDATE_INTERVAL)
+end
+
+--------------------------------
+-- Public API
+--------------------------------
+
+--[[
+The Lava Furnace does not require nor does it connect to any networks - but it can still be used via injector/
+`desc`: item description
+`name`: lower case no spaces unique name
+`lavaCap`: Lava capacity, in buckets (min 1)
+`combinedTiles` - should have 2 entires: combinedTiles.inactive and combinedTiles.active
+]]
+function logistica.register_lava_furnace(desc, name, lavaCapacity, combinedTiles)
+ local lname = name:gsub("%s", "_"):lower()
+ local def = {
+ description = S(desc),
+ tiles = combinedTiles.inactive,
+ paramtype2 = "facedir",
+ groups = { cracky= 2 },
+ is_ground_content = false,
+ sounds = default.node_sound_stone_defaults(),
+ can_dig = lava_furnace_can_dig,
+ on_timer = lava_furnace_node_timer,
+ on_construct = lava_furnace_on_construct,
+ on_destruct = lava_furnace_on_destruct,
+ on_metadata_inventory_move = lava_furnace_on_inv_change,
+ on_metadata_inventory_put = lava_furnace_on_inv_change,
+ on_metadata_inventory_take = lava_furnace_on_inv_change,
+ allow_metadata_inventory_put = lava_furnace_allow_metadata_inv_put,
+ allow_metadata_inventory_move = lava_furnace_allow_metadata_inv_move,
+ allow_metadata_inventory_take = lava_furnace_allow_metadata_inv_take,
+ logistica = {
+ lava_capacity = lavaCapacity
+ }
+ }
+
+ minetest.register_node("logistica:"..lname, def)
+
+ local defActive = table.copy(def)
+
+ defActive.tiles = combinedTiles.active
+ defActive.groups.not_in_creative_inventory = 1
+ defActive.light_source = 9
+
+ minetest.register_node("logistica:"..lname.."_active", defActive)
+
+end
diff --git a/api/lava_furnace_recipe.lua b/api/lava_furnace_recipe.lua
index bd4e3c8..525434e 100644
--- a/api/lava_furnace_recipe.lua
+++ b/api/lava_furnace_recipe.lua
@@ -1,16 +1,20 @@
-logistica.lava_furance_recipes = {}
+local lava_furance_recipes = {}
+local NORMAL_COOK_LAVA_USAGE_PER_SEC = 5 -- in millibuckets
+local NORMAL_COOK_REDUCTION_FACTOR = 2
+local MIN_TIME = 0.5
--[[
The Lava Furnace recipes format is indexed for item stack.
-`name`: The input item, count N is optional, and may be omitted (assumed 1)
+`name`: The input item
`def`: A table in the following format:
{
+ input_count = N, -- optional; how many of the input items are needed
output = "item_name N", -- the result of the crystalization
lava = 1000, -- how much lava is consumed. 1000 units = 1 bucket
additive = "item_name N", -- optional; the additive that is required to be present for this recipe
additive_use_chance = 100, -- optional; the chance that the additive will be consumed (0 = never, 100 = always)
- time = 10, -- approximate time, in seconds, this recipe takes to complete, min 0.2
+ time = 10, -- approximate time, in seconds, this recipe takes to complete, min is defined by MIN_TIME (or 1sec in practice)
}
]]
function logistica.register_lava_furnace_recipe(name, def)
@@ -18,12 +22,36 @@ function logistica.register_lava_furnace_recipe(name, def)
return
end
- local useChance = (def.additive ~= nil and logistica.clamp(def.additive, 0, 100)) or nil
- logistica.lava_furance_recipes[name] = {
+ local useChance = (def.additive_use_chance ~= nil and logistica.clamp(def.additive_use_chance, 0, 100)) or 100
+ lava_furance_recipes[name] = {
+ input_count = def.input_count or 1,
output = def.output,
- lava = math.max(1, def.output),
+ lava = math.max(1, def.lava),
additive = def.additive,
additive_use_chance = useChance,
- time = math.max(0.2, def.time),
+ time = math.max(MIN_TIME, def.time or 1),
}
end
+
+function logistica.get_lava_furnace_recipe_for(itemName)
+ local preset = lava_furance_recipes[itemName]
+ if preset then return preset end
+
+ -- else, try to adopt the real one
+ local output, decrOut = minetest.get_craft_result({
+ method = "cooking", width = 1, items = { ItemStack(itemName) }
+ })
+
+ if output.time > 0 and decrOut.items[1]:is_empty() then
+ local lavaTime = math.max(MIN_TIME, output.time / NORMAL_COOK_REDUCTION_FACTOR)
+ return {
+ input_count = 1,
+ output = output.item:to_string(),
+ lava = lavaTime * NORMAL_COOK_LAVA_USAGE_PER_SEC,
+ time = lavaTime
+ }
+ end
+
+ -- nothing found
+ return nil
+end
diff --git a/item/craft_item.lua b/item/craft_item.lua
index 34e6fa7..76aedc8 100644
--- a/item/craft_item.lua
+++ b/item/craft_item.lua
@@ -3,6 +3,12 @@ local S = logistica.TRANSLATOR
logistica.craftitem.general = {}
local items = logistica.craftitem.general
+items["logistica:lava_unit"] = {
+ description = S("A Unit of Lava\nUse in Lava Furnace or with Empty Bucket"),
+ inventory_image = "logistica_lava_unit.png",
+ stack_max = 1,
+}
+
items["logistica:silverin_slice"] = {
description = S("Silverin Slice"),
inventory_image = "logistica_silverin_slice.png",
diff --git a/registration/crystalizer_recipes.lua b/registration/crystalizer_recipes.lua
deleted file mode 100644
index e69de29..0000000
diff --git a/registration/lava_furnace_recipes.lua b/registration/lava_furnace_recipes.lua
new file mode 100644
index 0000000..9cafa02
--- /dev/null
+++ b/registration/lava_furnace_recipes.lua
@@ -0,0 +1,8 @@
+
+logistica.register_lava_furnace_recipe("default:silver_sand", {
+ output = "logistica:silverin",
+ lava = 50,
+ additive = "default:ice",
+ additive_use_chance = 90,
+ time = 5
+})
diff --git a/registration/nodes.lua b/registration/nodes.lua
index 0683195..06d7721 100644
--- a/registration/nodes.lua
+++ b/registration/nodes.lua
@@ -94,7 +94,7 @@ logistica.register_item_storage("Tool Box\nStores Tools Only", "simple", {
--------------------------------
logistica.register_mass_storage("basic", "Mass Storage", 8, 1024, 4, {
- "logistica_basic_mass_storage.png", "logistica_basic_mass_storage.png",
+ "logistica_basic_mass_storage_top.png", "logistica_basic_mass_storage_top.png",
"logistica_basic_mass_storage.png", "logistica_basic_mass_storage.png",
"logistica_basic_mass_storage.png", "logistica_basic_mass_storage_front.png"
})
@@ -132,3 +132,25 @@ logistica.register_supplier("Passive Supplier Chest", "simple", 16, {
-- Lava Furnace
--------------------------------
+logistica.register_lava_furnace("Lava Furnace", "lava_furnace", 4, {
+ inactive = {
+ "logistica_lava_furnace_side.png", "logistica_lava_furnace_side.png",
+ "logistica_lava_furnace_side.png", "logistica_lava_furnace_side.png",
+ "logistica_lava_furnace_side.png", "logistica_lava_furnace_front_off.png"
+ },
+ active = {
+ "logistica_lava_furnace_side.png", "logistica_lava_furnace_side.png",
+ "logistica_lava_furnace_side.png", "logistica_lava_furnace_side.png",
+ "logistica_lava_furnace_side.png",
+ {
+ image = "logistica_lava_furnace_front_on_anim.png",
+ backface_culling = false,
+ animation = {
+ type = "vertical_frames",
+ aspect_w = 16,
+ aspect_h = 16,
+ length = 1.5
+ },
+ }
+ }
+})
diff --git a/registration/registration.lua b/registration/registration.lua
index 89cc2e9..03208bb 100644
--- a/registration/registration.lua
+++ b/registration/registration.lua
@@ -1,4 +1,4 @@
local path = logistica.MODPATH .. "/registration"
-- once again, order is important
dofile(path.."/nodes.lua")
-dofile(path.."/crystalizer_recipes.lua")
+dofile(path.."/lava_furnace_recipes.lua")
diff --git a/textures/logistica_basic_mass_storage.png b/textures/logistica_basic_mass_storage.png
index 3e5029f..c7a1fb8 100644
Binary files a/textures/logistica_basic_mass_storage.png and b/textures/logistica_basic_mass_storage.png differ
diff --git a/textures/logistica_basic_mass_storage_front.png b/textures/logistica_basic_mass_storage_front.png
index 7c041d5..6fff35b 100644
Binary files a/textures/logistica_basic_mass_storage_front.png and b/textures/logistica_basic_mass_storage_front.png differ
diff --git a/textures/logistica_basic_mass_storage_top.png b/textures/logistica_basic_mass_storage_top.png
new file mode 100644
index 0000000..1eee3bb
Binary files /dev/null and b/textures/logistica_basic_mass_storage_top.png differ
diff --git a/textures/logistica_lava_furnace_arrow.png b/textures/logistica_lava_furnace_arrow.png
new file mode 100644
index 0000000..a5495af
Binary files /dev/null and b/textures/logistica_lava_furnace_arrow.png differ
diff --git a/textures/logistica_lava_furnace_arrow_bg.png b/textures/logistica_lava_furnace_arrow_bg.png
new file mode 100644
index 0000000..2fbbf21
Binary files /dev/null and b/textures/logistica_lava_furnace_arrow_bg.png differ
diff --git a/textures/logistica_lava_furnace_front_off.png b/textures/logistica_lava_furnace_front_off.png
new file mode 100644
index 0000000..8eea8d6
Binary files /dev/null and b/textures/logistica_lava_furnace_front_off.png differ
diff --git a/textures/logistica_lava_furnace_front_on_anim.png b/textures/logistica_lava_furnace_front_on_anim.png
new file mode 100644
index 0000000..0907ea6
Binary files /dev/null and b/textures/logistica_lava_furnace_front_on_anim.png differ
diff --git a/textures/logistica_lava_furnace_side.png b/textures/logistica_lava_furnace_side.png
new file mode 100644
index 0000000..cdea5ac
Binary files /dev/null and b/textures/logistica_lava_furnace_side.png differ
diff --git a/textures/logistica_lava_furnace_tank.png b/textures/logistica_lava_furnace_tank.png
new file mode 100644
index 0000000..a550abf
Binary files /dev/null and b/textures/logistica_lava_furnace_tank.png differ
diff --git a/textures/logistica_lava_furnace_tank_bg.png b/textures/logistica_lava_furnace_tank_bg.png
new file mode 100644
index 0000000..844cd9e
Binary files /dev/null and b/textures/logistica_lava_furnace_tank_bg.png differ
diff --git a/textures/logistica_lava_unit.png b/textures/logistica_lava_unit.png
new file mode 100644
index 0000000..acc432b
Binary files /dev/null and b/textures/logistica_lava_unit.png differ
diff --git a/util/common.lua b/util/common.lua
index aa19af4..97d1cf5 100644
--- a/util/common.lua
+++ b/util/common.lua
@@ -190,4 +190,10 @@ end
function logistica.table_is_empty(table)
return table == nil or (next(table) == nil)
-end
\ No newline at end of file
+end
+
+-- returns true a given percentage of the time
+function logistica.random_chance(percent)
+ return percent >= math.random(1, 100)
+end
+