123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391 |
- -- Function tables, per tier.
- battery_lv = battery_lv or {}
- battery_mv = battery_mv or {}
- battery_hv = battery_hv or {}
- -- Localize for performance.
- local math_floor = math.floor
- for k, v in ipairs({
- {tier="lv", up="LV", name="Low-Voltage"},
- {tier="mv", up="MV", name="Medium-Voltage"},
- {tier="hv", up="HV", name="High-Voltage"},
- }) do
- -- Which function table are we operating on?
- local functable = _G["battery_" .. v.tier]
-
- -- Typedata is used when traversing the network, without touching the node.
- -- It must contain as much data as needed to get the node even if unloaded.
- -- This must be done after node construction.
- -- This should also be done when punched, to allow old nodes to be upgraded.
- functable.initialize_typedata =
- function(pos)
- local meta = minetest.get_meta(pos)
- meta:set_string("technic_machine", "yes")
- meta:set_string("technic_type", "battery")
- meta:set_string("technic_tier", v.tier)
- -- This will technically be the wrong name, most of the time, but we should
- -- only ever use it to look up the node definition in order to get functions.
- -- And the functions for arrays 0 through 12 should be all the same.
- meta:set_string("technic_name", "battery:array0_" .. v.tier)
- end
- functable.compose_infotext =
- function(pos)
- local meta = minetest.get_meta(pos)
- local inv = meta:get_inventory()
- local chg = meta:get_int("energy")
- local max = meta:get_int("max")
- local size = inv:get_size("batteries")
- local cnt = functable.get_battery_count(inv)
-
- local infotext = v.up .. " Battery Array\n" ..
- "Internal Battery Units: " .. cnt .. "/" .. size .. "\n" ..
- "Energy: " .. chg .. "/" .. max .. " EUs\n"
-
- if max > 0 then
- local percent = math_floor(chg / max * 100)
- infotext = infotext .. "Charge: " .. percent .. "%"
- else
- infotext = infotext .. "Charge: 0%"
- end
-
- meta:set_string("infotext", infotext)
- end
- functable.compose_formspec =
- function(pos)
- local meta = minetest.get_meta(pos)
- local chg, max = functable.get_energy_status(meta)
-
- local charge_desc = v.name .. " Charge Status: " ..
- chg .. "/" .. max .. " EUs"
-
- local formspec =
- "size[8,8.5]" ..
- default.formspec.get_form_colors() ..
- default.formspec.get_form_image() ..
- default.formspec.get_slot_colors() ..
-
- "label[0,0;" .. minetest.formspec_escape(charge_desc) .. "]" ..
-
- "label[0,0.5;NRAIB (Non-Redundant Array of Independant Batteries)]" ..
- "list[context;batteries;0,1;6,2;]" ..
-
- "label[7,0.5;Config]" ..
- "list[context;cfg;7,1;1,2;]" ..
-
- "list[current_player;main;0,4.25;8,1;]" ..
- "list[current_player;main;0,5.5;8,3;8]" ..
- default.get_hotbar_bg(0, 4.25)
- meta:set_string("formspec", formspec)
- end
- functable.update_charge_visual =
- function(pos)
- local meta = minetest.get_meta(pos)
- local chg, max = functable.get_energy_status(meta)
-
- local name = "battery:array0_" .. v.tier
-
- if max > 0 then -- Avoid divide-by-zero.
- local percent = math_floor((chg / max) * 100)
- local sz = math.ceil(100 / 12)
- for i = 0, 12, 1 do
- if percent <= sz*i then
- name = "battery:array" .. i .. "_" .. v.tier
- break
- end
- end
- end
-
- machines.swap_node(pos, name)
- end
- functable.on_punch =
- function(pos, node, puncher, pointed_thing)
- functable.initialize_typedata(pos)
- functable.trigger_update(pos)
- end
- functable.can_dig =
- function(pos, player)
- local meta = minetest.get_meta(pos)
- local inv = meta:get_inventory()
- return inv:is_empty("batteries") and
- inv:is_empty("cfg")
- end
- functable.allow_metadata_inventory_put =
- function(pos, listname, index, stack, player)
- local NCONF = "cfg:dev"
- local NBATT = "battery:battery"
- local pname = player:get_player_name()
- if minetest.test_protection(pos, pname) then
- return 0
- end
-
- if listname == "cfg" and stack:get_name() == NCONF then
- return stack:get_count()
- elseif listname == "batteries" and stack:get_name() == NBATT then
- return stack:get_count()
- end
-
- return 0
- end
- functable.allow_metadata_inventory_move =
- function(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 functable.allow_metadata_inventory_put(pos, to_list, to_index, stack, player)
- end
- functable.allow_metadata_inventory_take =
- function(pos, listname, index, stack, player)
- local pname = player:get_player_name()
- if minetest.test_protection(pos, pname) then
- return 0
- end
-
- return stack:get_count()
- end
- functable.get_battery_count =
- function(inv)
- local batteries = inv:get_list("batteries")
-
- local count = 0
- for k, v in ipairs(batteries) do
- if v:get_name() == "battery:battery" then
- -- Only 1 battery allowed per stack.
- count = count + 1
- end
- end
- return count
- end
- functable.update_maximum_charge =
- function(meta)
- local count = functable.get_battery_count(meta:get_inventory())
-
- local max
- if v.tier == "lv" then
- max = count * 10000
- elseif v.tier == "mv" then
- max = count * 50000
- elseif v.tier == "hv" then
- max = count * 120000
- end
-
- local chg = meta:get_int("energy")
-
- -- Ensure charge isn't over max. This can happen if user removed a battery.
- if chg > max then
- meta:set_int("energy", max)
- end
- meta:set_int("max", max)
- end
- functable.on_timer =
- function(pos, elapsed)
- machines.log_update(pos, "Battery Array")
- local meta = minetest.get_meta(pos)
-
- local current_amount = meta:get_int("energy")
- local old_eu_amount = meta:get_int("old_eu")
-
- -- Todo: here, we can respond to changes in EU amount since last update.
-
- meta:set_int("old_eu", current_amount)
-
- -- Needed in case the operator removes or adds a battery.
- -- Also, EUs can be added/drained from batteries without going through a distributer.
- functable.update_maximum_charge(meta)
- functable.update_listeners(pos)
-
- functable.update_charge_visual(pos)
- functable.compose_infotext(pos)
- functable.compose_formspec(pos)
- end
- functable.update_listeners =
- function(pos)
- local table_in = {
- purpose = "refresh_eu_status",
- }
- local table_out = {}
- local traversal = {}
-
- -- Do not process self.
- local hash = minetest.hash_node_position(pos)
- traversal[hash] = 0
-
- -- Update any listening EU observers on the same network tier.
- local hubs = machines.get_adjacent_network_hubs(pos, {v.tier})
- if hubs then
- for k, v in ipairs(hubs) do
- local node = minetest.get_node(v)
- local def = minetest.reg_ns_nodes[node.name]
- if def and def.on_machine_execute then
- def.on_machine_execute(v, table_in, table_out, traversal)
- end
- end
- end
- end
- functable.on_blast =
- function(pos)
- local drops = {}
- default.get_inventory_drops(pos, "batteries", drops)
- default.get_inventory_drops(pos, "cfg", drops)
- drops[#drops+1] = "battery:array0_" .. v.tier
- minetest.remove_node(pos)
- return drops
- end
- functable.on_construct =
- function(pos)
- functable.initialize_typedata(pos)
-
- local meta = minetest.get_meta(pos)
- local inv = meta:get_inventory()
-
- inv:set_size("batteries", 6*2)
- inv:set_size("cfg", 2)
-
- functable.update_maximum_charge(meta)
- functable.compose_infotext(pos)
- functable.compose_formspec(pos)
- end
- functable.after_place_node =
- function(pos, placer, itemstack, pointed_thing)
- end
- functable.on_metadata_inventory_move =
- function(pos)
- functable.trigger_update(pos)
- end
- functable.on_metadata_inventory_put =
- function(pos)
- functable.trigger_update(pos)
- end
- functable.on_metadata_inventory_take =
- function(pos)
- functable.trigger_update(pos)
- end
- functable.trigger_update =
- function(pos)
- local timer = minetest.get_node_timer(pos)
- if not timer:is_started() then
- timer:start(1.0)
- end
- end
- -- Read the current & max charge of the battery, but do not trigger any update.
- -- Function shall be used internally ONLY.
- functable.get_energy_status =
- function(meta)
- local chg = meta:get_int("energy")
- local max = meta:get_int("max")
- return chg, max
- end
- functable.on_machine_execute =
- function(pos, table_in, table_out, traversal)
- -- We do not check for recursion depth for battery array boxes because
- -- these cannot be chains, so there is no problem with network size.
- -- Do not process this node more than once.
- local hash = minetest.hash_node_position(pos)
- if traversal[hash] then return end
- traversal[hash] = 0
-
- local meta = minetest.get_meta(pos)
-
- local purpose = table_in.purpose
- if purpose == "get_eu_status" then
- local chg, max = functable.get_energy_status(meta)
- table_out.eu_chg = (table_out.eu_chg or 0) + chg
- table_out.eu_max = (table_out.eu_max or 0) + max
- table_out.num_batteries = (table_out.num_batteries or 0) + 1
- elseif purpose == "store_eu" then
- if table_out.amount_eu <= 0 then return end
-
- local chg = meta:get_int("energy")
- local max = meta:get_int("max")
-
- -- Don't trigger an update cascade unless something changed.
- if chg < max then
- local amount = (table_out.amount_eu or 0)
-
- -- Clamp the amount the battery receives to its max capacity.
- -- This allows us to correctly calculate the remaining charge,
- -- after putting as much as possible in the battery.
- if amount + chg > max then
- amount = max - chg
- end
-
- if amount >= 1 then
- local chg = chg + amount
- if chg > max then
- chg = max
- end
- meta:set_int("energy", chg)
- functable.trigger_update(pos)
- end
-
- -- Calculate remaining charge.
- table_out.amount_eu = (table_out.amount_eu or 0) - amount
- end
- elseif purpose == "retrieve_eu" then
- if (table_out.wanted_eu or 0) <= 0 then return end
-
- local wanted_eu = (table_out.wanted_eu or 0)
- local current_eu = meta:get_int("energy")
- local eu_retrieved = 0
-
- -- Do *not* drain battery if we don't have enough EU. Just return 0.
- if current_eu >= wanted_eu then
- eu_retrieved = wanted_eu
- current_eu = current_eu - wanted_eu
-
- table_out.gotten_eu = (table_out.gotten_eu or 0) + eu_retrieved
- table_out.wanted_eu = (table_out.wanted_eu or 0) - eu_retrieved
-
- meta:set_int("energy", current_eu)
- end
-
- -- Don't trigger an update cascade unless something changed.
- if eu_retrieved > 0 then -- Energy was drained; need update.
- functable.trigger_update(pos)
- end
- end
- end
- if not battery.functions_loaded then
- local c = "battery:core"
- local f = battery.modpath .. "/functions.lua"
- reload.register_file(c, f, false)
- battery.functions_loaded = true
- end
- end
|