398 lines
13 KiB
Lua
398 lines
13 KiB
Lua
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 LAVA_UNIT = "logistica:lava_unit"
|
|
|
|
local INV_FUEL = "fuel"
|
|
local INV_INPT = "src"
|
|
local INV_OUTP = "dst"
|
|
local INV_ADDI = "input"
|
|
|
|
local GUIDE_BTN = "guide"
|
|
|
|
local UPDATE_INTERVAL = 1.0
|
|
|
|
local function is_lava_bucket(itemstackName)
|
|
return logistica.reservoir_get_full_buckets_for_liquid(logistica.liquids.lava)[itemstackName] ~= nil
|
|
end
|
|
|
|
local function fill_lava_tank_from_fuel(pos, meta, inv)
|
|
local itemstackName = inv:get_stack(INV_FUEL, 1):get_name()
|
|
if not is_lava_bucket(itemstackName) and itemstackName ~= LAVA_UNIT then return end
|
|
|
|
local returnStack = logistica.reservoir_get_empty_bucket_for_full_bucket(itemstackName) or ItemStack("")
|
|
local currLevel = meta:get_int(META_LAVA_IN_TANK)
|
|
local cap = logistica.lava_furnace_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<br>
|
|
-- 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 outputDefs = logistica.get_lava_furnace_recipes_for(currItemStack:get_name())
|
|
if not outputDefs then return nil end
|
|
for _, outputDef in ipairs(outputDefs) do
|
|
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
|
|
}
|
|
end
|
|
end
|
|
return nil
|
|
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 = logistica.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("Remaining: ")..(currLava/1000)..S(" Buckets").."]"
|
|
end
|
|
|
|
local function common_formspec(pos, meta)
|
|
local currLava = meta:get_int(META_LAVA_IN_TANK)
|
|
local lavaCap = logistica.lava_furnace_get_lava_capacity(pos) or 1
|
|
local lavaPercent = logistica.round(currLava / lavaCap * 100)
|
|
return "formspec_version[4]"..
|
|
"size["..logistica.inv_size(10.5, 11.25).."]" ..
|
|
logistica.ui.background_lava_furnace..
|
|
"listcolors[#00000069;#5A5A5A;#141318;#30434C;#FFF]"..
|
|
logistica.player_inv_formspec(0.5, 5.9)..
|
|
"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.2,0.5;Additives]"..
|
|
"label[2.0,4.8;"..S("Crafts unique recipes (click ? button in top right)").."]"..
|
|
"label[2.0,5.2;"..S("and can also cook regular recipes at twice the speed").."]"..
|
|
"listring[context;dst]"..
|
|
"listring[current_player;main]"..
|
|
"listring[context;src]"..
|
|
"listring[current_player;main]"..
|
|
"listring[context;fuel]"..
|
|
"listring[current_player;main]"..
|
|
"button[9.2,0.4;0.8,0.8;"..GUIDE_BTN..";?]"..
|
|
"tooltip["..GUIDE_BTN..";"..S("Recipes").."]"..
|
|
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 = logistica.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, 1)
|
|
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 minetest.is_protected(pos, player:get_player_name()) then return 0 end
|
|
local stackName = stack:get_name()
|
|
if listname == INV_INPT or listname == INV_ADDI then
|
|
return stack:get_count()
|
|
elseif listname == INV_FUEL
|
|
and (is_lava_bucket(stackName) or stackName == LAVA_UNIT) then
|
|
return 1
|
|
else
|
|
return 0
|
|
end
|
|
end
|
|
|
|
local function lava_furnace_allow_metadata_inv_take(pos, listname, index, stack, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then return 0 end
|
|
return stack:get_count()
|
|
end
|
|
|
|
local function lava_furnace_allow_metadata_inv_move(pos, from_list, from_index, to_list, to_index, count, player)
|
|
if minetest.is_protected(pos, player:get_player_name()) then return 0 end
|
|
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)
|
|
logistica.start_node_timer(pos, UPDATE_INTERVAL)
|
|
end
|
|
|
|
local function lava_furnace_receive_fields(pos, formname, fields, sender)
|
|
if fields[GUIDE_BTN] and sender and sender:is_player() then
|
|
logistica.lava_furnace_show_guide(sender:get_player_name())
|
|
end
|
|
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<br>
|
|
`name`: lower case no spaces unique name<br>
|
|
`lavaCap`: Lava capacity, in buckets (min 1)<br>
|
|
`combinedTiles` - should have 2 entires: combinedTiles.inactive and combinedTiles.active<br>
|
|
]]
|
|
function logistica.register_lava_furnace(desc, name, lavaCapacity, combinedTiles)
|
|
local lname = name:gsub("%s", "_"):lower()
|
|
local def = {
|
|
description = S(desc),
|
|
drawtype = "nodebox",
|
|
tiles = combinedTiles.inactive,
|
|
node_box = {
|
|
type = "fixed",
|
|
fixed = {
|
|
{-8/16, -8/16, -8/16, -7/16, 5/16, -7/16},
|
|
{ 7/16, -8/16, -8/16, 8/16, 5/16, -7/16},
|
|
{-8/16, -8/16, -8/16, 8/16, -7/16, -7/16},
|
|
{-8/16, -1/16, -8/16, 8/16, 1/16, -7/16},
|
|
{-8/16, 5/16, -8/16, -6/16, 8/16, -7/16},
|
|
{ 6/16, 5/16, -8/16, 8/16, 8/16, -7/16},
|
|
{-6/16, 6/16, -8/16, -5/16, 8/16, -7/16},
|
|
{ 5/16, 6/16, -8/16, 6/16, 8/16, -7/16},
|
|
{-5/16, 7/16, -8/16, 5/16, 8/16, -7/16},
|
|
{-8/16, -8/16, -7/16, 8/16, 8/16, 8/16},
|
|
}
|
|
},
|
|
selection_box = { type = "normal" },
|
|
paramtype2 = "facedir",
|
|
groups = { cracky= 2, pickaxey = 2, },
|
|
is_ground_content = false,
|
|
sounds = logistica.sound_mod.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,
|
|
on_receive_fields = lava_furnace_receive_fields,
|
|
logistica = {
|
|
lava_capacity = lavaCapacity,
|
|
lava_furnace = true,
|
|
},
|
|
_mcl_hardness = 3,
|
|
_mcl_blast_resistance = 15
|
|
}
|
|
|
|
local lavaFurnaceName = "logistica:"..lname
|
|
minetest.register_node(lavaFurnaceName, def)
|
|
logistica.register_non_pushable(lavaFurnaceName)
|
|
|
|
local defActive = table.copy(def)
|
|
|
|
defActive.tiles = combinedTiles.active
|
|
defActive.groups.not_in_creative_inventory = 1
|
|
defActive.light_source = 9
|
|
|
|
minetest.register_node(lavaFurnaceName.."_active", defActive)
|
|
|
|
end
|