minetest-mods/basic_machines/technic_power.lua

551 lines
20 KiB
Lua

local machines_timer=5
local machines_minstep = 1
-- BATTERY
local battery_update_meta = function(pos)
local meta = minetest.get_meta(pos)
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local capacity = meta:get_float("capacity")
local maxpower = meta:get_float("maxpower")
local energy = math.ceil(10*meta:get_float("energy"))/10
local form =
"size[8,6.5]".. -- width, height
"label[0,0;FUEL] ".."label[6,0;UPGRADE] "..
"label[0.,1.5;UPGRADE: diamond/mese block for power/capacity]"..
"label[0.,1.75;UPGRADE: maxpower ".. maxpower .. " / CAPACITY " .. meta:get_int("capacity") .. "]"..
"list["..list_name..";fuel;0.,0.5;1,1;]".. "list["..list_name..";upgrade;6.,0.5;2,2;]" ..
"list[current_player;main;0,2.5;8,4;]"..
"button[4.5,0.35;1.5,1;OK;REFRESH]"..
"listring["..list_name..";upgrade]"..
"listring[current_player;main]"..
"listring["..list_name..";fuel]"..
"listring[current_player;main]"
meta:set_string("formspec", form)
end
--[power crystal name] = energy provided
basic_machines.energy_crystals = {
["basic_machines:power_cell"]=1,
["basic_machines:power_block"]=11,
["basic_machines:power_rod"]=100,
}
battery_recharge = function(pos)
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
local inv = meta:get_inventory();
local stack = inv:get_stack("fuel", 1); local item = stack:get_name();
local crystal = false;
local add_energy=0;
add_energy = basic_machines.energy_crystals[item] or 0;
if add_energy>0 then
if pos.y>1500 then add_energy=2*add_energy end -- in space recharge is more efficient
crystal = true;
if add_energy<=capacity then
stack:take_item(1);
inv:set_stack("fuel", 1, stack)
else
meta:set_string("infotext", "recharge problem: capacity " .. capacity .. ", needed " .. energy+add_energy)
return energy
end
else -- try do determine caloric value of fuel inside battery
local fuellist = inv:get_list("fuel");if not fuellist then return energy end
local fueladd, afterfuel = minetest.get_craft_result({method = "fuel", width = 1, items = fuellist})
if fueladd.time > 0 then
add_energy = fueladd.time/40;
if energy+add_energy<=capacity then
inv:set_stack("fuel", 1, afterfuel.items[1]);
end
end
end
if add_energy>0 then
energy=energy+add_energy
if energy<0 then energy = 0 end
if energy>capacity then energy = capacity end -- excess energy is wasted
meta:set_float("energy",energy);
meta:set_string("infotext", "(R) energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
minetest.sound_play("electric_zap", {pos=pos,gain=0.05,max_hear_distance = 8,})
end
local full_coef = math.floor(energy/capacity*3); if full_coef > 2 then full_coef = 2 end
minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef}) -- graphic energy
return energy; -- new battery energy level
end
battery_upgrade = function(pos)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory();
local count1,count2;count1=0;count2=0;
local stack,item,count;
for i=1,4 do
stack = inv:get_stack("upgrade", i);item = stack:get_name();count= stack:get_count();
if item == "default:mese" then
count1=count1+count
elseif item == "default:diamondblock" then
count2=count2+count
end
end
--if count1<count2 then count =count1 else count=count2 end
if pos.y>1500 then count1 = 2*count1; count2=2*count2 end -- space increases efficiency
meta:set_int("upgrade",count2); -- diamond for power
-- adjust capacity
--yyy
local capacity = 3+3*count1; -- mese for capacity
local maxpower = 1+count2*2; -- old 99 upgrade -> 200 power
capacity = math.ceil(capacity*10)/10;
local energy = 0;
meta:set_float("capacity",capacity)
meta:set_float("maxpower",maxpower)
meta:set_float("energy",0)
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
end
local machines_activate_furnace = minetest.registered_nodes["default:furnace"].on_metadata_inventory_put; -- this function will activate furnace
minetest.register_node("basic_machines:battery_0", {
description = "battery - stores energy, generates energy from fuel, can power nearby machines, or accelerate/run furnace above it. Its upgradeable.",
tiles = {"basic_machine_outlet.png","basic_machine_side.png","basic_machine_battery_0.png"},
groups = {cracky=3, mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext","battery - stores energy, generates energy from fuel, can power nearby machines, or accelerate/run furnace above it when activated by keypad");
meta:set_string("owner",placer:get_player_name());
local inv = meta:get_inventory();inv:set_size("fuel", 1*1); -- place to put crystals
inv:set_size("upgrade", 2*2);
meta:set_int("upgrade",0); -- upgrade level determines energy storage capacity and max energy output
meta:set_float("capacity",3);meta:set_float("maxpower",1);
meta:set_float("energy",0);
end,
mesecons = {effector = {
action_on = function (pos, node,ttl)
if type(ttl)~="number" then ttl = 1 end
if ttl<0 then return end -- machines_TTL prevents infinite recursion
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
local full_coef = math.floor(energy/capacity*3);
-- try to power furnace on top of it
if energy>=1 then -- need at least 1 energy
pos.y=pos.y+1; local node = minetest.get_node(pos).name;
if node== "default:furnace" or node=="default:furnace_active" then
local fmeta = minetest.get_meta(pos);
local fuel_totaltime = fmeta:get_float("fuel_totaltime") or 0;
local fuel_time = fmeta:get_float("fuel_time") or 0;
local t0 = meta:get_int("ftime"); -- furnace time
local t1 = minetest.get_gametime();
if t1-t0<machines_minstep then -- to prevent too quick furnace acceleration, punishment is cooking reset
fmeta:set_float("src_time",0); return
end
meta:set_int("ftime",t1);
local upgrade = meta:get_int("upgrade");upgrade=upgrade*0.1;
--if fuel_time>4 then -- accelerated cooking
local src_time = fmeta:get_float("src_time") or 0
energy = energy - 0.25*upgrade; -- use energy to accelerate burning
if fuel_time>40 or fuel_totaltime == 0 or node=="default:furnace" then -- to add burn time: must burn for at least 40 secs or furnace out of fuel
fmeta:set_float("fuel_totaltime",60);fmeta:set_float("fuel_time",0) -- add 60 second burn time to furnace
energy=energy-0.5; -- use up energy to add fuel
-- make furnace start if not already started
if node~="default:furnace_active" and machines_activate_furnace then machines_activate_furnace(pos) end
-- update energy display
end
if energy<0 then
energy = 0
else -- only accelerate if we had enough energy, note: upgrade*0.1*0.25<power_rod is limit upgrade, so upgrade = 40*100 = 4000
fmeta:set_float("src_time",src_time+machines_timer*upgrade); -- accelerated smelt: with 99 upgrade battery furnace works 11x faster
end
meta:set_float("energy",energy);
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
if energy>=1 then -- no need to recharge yet, will still work next time
local full_coef_new = math.floor(energy/capacity*3); if full_coef_new>2 then full_coef_new = 2 end
pos.y = pos.y-1;
if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end
return
else
local infotext = meta:get_string("infotext");
local new_infotext = "furnace needs at least 1 energy";
if new_infotext~=infotext then -- dont update unnecesarilly
meta:set_string("infotext", new_infotext);
pos.y=pos.y-1; -- so that it points to battery again!
end
end
else
pos.y=pos.y-1;
end
end
-- try to recharge by converting inserted fuel/power cells into energy
if energy<capacity then -- not full, try to recharge
battery_recharge(pos);
return
end
local full_coef_new = math.floor(energy/capacity*3); if full_coef_new>2 then full_coef_new = 2 end
if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end
end
}},
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
battery_update_meta(pos);
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then return end
local meta = minetest.get_meta(pos);
battery_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname=="fuel" then
battery_recharge(pos);
battery_update_meta(pos);
elseif listname == "upgrade" then
battery_upgrade(pos);
battery_update_meta(pos);
end
return stack:get_count();
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
if listname == "upgrade" then
battery_upgrade(pos);
battery_update_meta(pos);
end
return stack:get_count();
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
can_dig = function(pos)
local meta = minetest.get_meta(pos);
if meta:get_int("upgrade")~=0 then return false else return true end
end,
tube = {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("fuel", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if meta:get_int("split_material_stacks") == 1 then
stack = stack:peek_item(1)
end
return inv:room_for_item("fuel", stack)
end,
input_inventory = "fuel",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
},
})
-- GENERATOR
local generator_update_meta = function(pos)
local meta = minetest.get_meta(pos);
local list_name = "nodemeta:"..pos.x..','..pos.y..','..pos.z
local form =
"size[8,6.5]" .. -- width, height
"label[0,0;POWER CRYSTALS] ".."label[6,0;UPGRADE] "..
"label[1,1;UPGRADE LEVEL ".. meta:get_int("upgrade").." (generator)]"..
"list["..list_name..";fuel;0.,0.5;1,1;]"..
"list["..list_name..";upgrade;6.,0.5;2,1;]"..
"list[current_player;main;0,2.5;8,4;]"..
"button[4.5,1.5;1.5,1;OK;REFRESH]"..
"button[6,1.5;1.5,1;help;help]"..
"listring["..list_name..";fuel]"..
"listring[current_player;main]"..
"listring["..list_name..";upgrade]"..
"listring[current_player;main]"
meta:set_string("formspec", form)
end
generator_upgrade = function(pos)
local meta = minetest.get_meta(pos);
local inv = meta:get_inventory();
local stack,item,count;
count = 0
for i=1,2 do
stack = inv:get_stack("upgrade", i);item = stack:get_name();
if item == "basic_machines:generator" then
count= count + stack:get_count();
end
end
meta:set_int("upgrade",count);
end
minetest.register_node("basic_machines:generator", {
description = "Generator - very expensive, generates power crystals that provide power. Its upgradeable.",
tiles = {"basic_machine_generator.png"},
groups = {cracky=3, mesecon_effector_on = 1},
sounds = default.node_sound_wood_defaults(),
after_place_node = function(pos, placer)
local meta = minetest.get_meta(pos);
meta:set_string("infotext","generator - generates power crystals that provide power. Upgrade with up to 99 gold/diamond blocks.");
meta:set_string("owner",placer:get_player_name());
local inv = meta:get_inventory();
inv:set_size("fuel", 1*1); -- here generated power crystals are placed
inv:set_size("upgrade", 2*1);
meta:set_int("upgrade",0); -- upgrade level determines quality of produced crystals
end,
on_rightclick = function(pos, node, player, itemstack, pointed_thing)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return end -- only owner can interact with recycler
generator_update_meta(pos);
end,
on_receive_fields = function(pos, formname, fields, sender)
if fields.quit then return end
if fields.help then
local text = "Generator slowly produces power crystals. Those can be used to recharge batteries and come in 3 flavors:\n\n low level (0-4), medium level (5-19) and high level (20+). Upgrading the generator (upgrade with generators) will increase the rate at which the crystals are produced.\n\nYou can automate the process of battery recharging by using mover in inventory mode, taking from inventory \"fuel\"";
local form = "size [6,7] textarea[0,0;6.5,8.5;help;GENERATOR HELP;".. text.."]"
minetest.show_formspec(sender:get_player_name(), "basic_machines:help_mover", form)
return
end
local meta = minetest.get_meta(pos);
generator_update_meta(pos);
end,
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
local meta = minetest.get_meta(pos);
local privs = minetest.get_player_privs(player:get_player_name());
if minetest.is_protected(pos,player:get_player_name()) and not privs.privs then return 0 end
return stack:get_count();
end,
on_metadata_inventory_put = function(pos, listname, index, stack, player)
if listname == "upgrade" then
generator_upgrade(pos);
generator_update_meta(pos);
end
return stack:get_count();
end,
on_metadata_inventory_take = function(pos, listname, index, stack, player)
if listname == "upgrade" then
generator_upgrade(pos);
generator_update_meta(pos);
end
return stack:get_count();
end,
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
return 0;
end,
can_dig = function(pos)
local meta = minetest.get_meta(pos);
if meta:get_int("upgrade")~=0 then return false else return true end
end,
tube = {
insert_object = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
return inv:add_item("upgrade", stack)
end,
can_insert = function(pos, node, stack, direction)
local meta = minetest.get_meta(pos)
local inv = meta:get_inventory()
if meta:get_int("split_material_stacks") == 1 then
stack = stack:peek_item(1)
end
return inv:room_for_item("upgrade", stack)
end,
input_inventory = "fuel",
connect_sides = {left = 1, right = 1, back = 1, front = 1, bottom = 1, top = 1}
},
})
minetest.register_abm({
nodenames = {"basic_machines:generator"},
neighbors = {""},
interval = 19,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
local meta = minetest.get_meta(pos);
local upgrade = meta:get_int("upgrade");
local inv = meta:get_inventory();
local stack = inv:get_stack("fuel", 1);
local crystal, text;
if upgrade >= 20 then
crystal = "basic_machines:power_rod " .. math.floor(1+(upgrade-20)*9/178)
text = "high upgrade: power rod";
elseif upgrade >=5 then
crystal ="basic_machines:power_block " .. math.floor(1+(upgrade-5)*9/15);
text = "medium upgrade: power block";
else
crystal ="basic_machines:power_cell " .. math.floor(1+2*upgrade);
text = "low upgrade: power cell";
end
local morecrystal = ItemStack(crystal)
stack:add_item(morecrystal);
inv:set_stack("fuel", 1, stack)
meta:set_string("infotext",text)
end
})
-- API for power distribution
function basic_machines.check_power(pos, power_draw) -- mover checks power source - battery
--minetest.chat_send_all(" battery: check_power " .. minetest.pos_to_string(pos) .. " " .. power_draw)
local batname = "basic_machines:battery";
if not string.find(minetest.get_node(pos).name,batname) then
return -1 -- battery not found!
end
local meta = minetest.get_meta(pos);
local energy = meta:get_float("energy");
local capacity = meta:get_float("capacity");
local maxpower = meta:get_float("maxpower");
local full_coef = math.floor(energy/capacity*3); -- 0,1,2
if power_draw>maxpower then
meta:set_string("infotext", "Power draw required : " .. power_draw .. " maximum power output " .. maxpower .. ". Please upgrade battery")
return 0;
end
if power_draw>energy then
energy = battery_recharge(pos); -- try recharge battery and continue operation immidiately
if not energy then return 0 end
end
energy = energy-power_draw;
if energy<0 then
meta:set_string("infotext", "used fuel provides too little power for current power draw ".. power_draw);
return 0
end -- recharge wasnt enough, needs to be repeated manually, return 0 power available
meta:set_float("energy", energy);
-- update energy display
meta:set_string("infotext", "energy: " .. math.ceil(energy*10)/10 .. " / ".. capacity);
local full_coef_new = math.floor(energy/capacity*3); if full_coef_new>2 then full_coef_new = 2 end
if full_coef_new ~= full_coef then minetest.swap_node(pos,{name = "basic_machines:battery_".. full_coef_new}) end -- graphic energy level display
return power_draw;
end
------------------------
-- CRAFTS
------------------------
-- minetest.register_craft({
-- output = "basic_machines:battery",
-- recipe = {
-- {"","default:steel_ingot",""},
-- {"default:steel_ingot","default:mese","default:steel_ingot"},
-- {"","default:diamond",""},
-- }
-- })
-- minetest.register_craft({
-- output = "basic_machines:generator",
-- recipe = {
-- {"","",""},
-- {"default:diamondblock","basic_machines:battery","default:diamondblock"},
-- {"default:diamondblock","default:diamondblock","default:diamondblock"}
-- }
-- })
minetest.register_craftitem("basic_machines:power_cell", {
description = "Power cell - provides 1 power",
inventory_image = "power_cell.png",
stack_max = 25
})
minetest.register_craftitem("basic_machines:power_block", {
description = "Power block - provides 11 power",
inventory_image = "power_block.png",
stack_max = 25
})
minetest.register_craftitem("basic_machines:power_rod", {
description = "Power rod - provides 100 power",
inventory_image = "power_rod.png",
stack_max = 25
})
-- various battery levels: 0,1,2 (2 >= 66%, 1 >= 33%,0>=0%)
local batdef = {};
for k,v in pairs(minetest.registered_nodes["basic_machines:battery_0"]) do batdef[k] = v end
for i = 1,2 do
batdef.tiles[3] = "basic_machine_battery_" .. i ..".png"
minetest.register_node("basic_machines:battery_"..i, batdef)
end