Demander improvements; storage funcs; new sounds; added ROADMAP
This commit is contained in:
parent
cab538cfbf
commit
61004f5bb0
34
README.md
34
README.md
@ -5,30 +5,38 @@ Logistica is a item transport, distribution and storage mod.
|
||||
|
||||
The core principle behind this mod is that item transportation is demand-driven: no item is moved unless it is requested somewhere.
|
||||
|
||||
# Nodes
|
||||
# Machines
|
||||
|
||||
All nodes require to be connected to an active network to perform their tasks. Nodes without a network, or nodes with conflicting network connections will not do anything.
|
||||
All machines require to be connected to an active network to perform their tasks. Nodes without a network, or nodes with conflicting network connections will not do anything.
|
||||
|
||||
## Controller
|
||||
A Controller is a node required to create an active network. Exactly one controller can be conneted to a network, and removing it will disconnect all other devices connected to the network.
|
||||
A Controller is the node required to create an active network. Exactly one controller can be conneted to a network, and removing it will disconnect all other devices connected to the network. Controllers allow you to rename the network.
|
||||
|
||||
## Cables
|
||||
Cables are simple nodes that connect a controller to other nodes, allowing the establishing of a network. Placing a cable that bridges two different active networks will burn that cable. Burned cables can simply be picked up, and return normal cables. TODO Cables come in TODO variants, all being identical in function, but different variants do not connect to each other, allowing parallel networks.
|
||||
Cables are used to connect a controller to other machines, allowing the establishing of a network. Placing a cable that bridges two different active networks will burn that cable. Burned cables can simply be picked up, and return normal cables. TODO Cables come in TODO variants, all being identical in function, but different variants do not connect to each other, allowing parallel networks.
|
||||
|
||||
## Demander
|
||||
A Demander is a node that targets any other node with an inventory, and can be configured to request items from its network to keep the target's inventory full of a specific number of specific items.
|
||||
A Demander is a machine that inserts items into almost any other node that has an inventory. The Demander takes items from the network and tries to keep its target's inventory full of the specific items and the exact count it's configured with. For example, a demander might be configured to target a Furnace's "fuel" inventory and always try to keep 2 coal in it.
|
||||
|
||||
There's two variation of the Demander:
|
||||
- Basic Demander: Moves 1 item at a time to fulfil the requested items.
|
||||
- Stack Demander: Moves up to 1 stack at a time to fulfil the requested items.
|
||||
|
||||
Demanders check network storage first to fulfil their demand, and if not, they will check any suppliers.
|
||||
|
||||
## Supplier
|
||||
A Supplier is a node that takes items from another node's inventory, configuratble to only inject certain items, and tries to fulfil any supply for that item in its network. Suppliers have a tick rate and each tick they pick one inventory slot of the target's invenotry and check if there's demand anywhere on the network for that type of item. On the following tick, the supplier will move onto the next slot of the target's inventory and check that.
|
||||
A Supplier acts as a source for specific items that must be configured. It takes items from other nodes' inventories (e.g. chests, furnaces) and makes them available to any demand in the network. Suppliers won't actively push items into the network, but Demanders and Storage nodes can both take items from Suppliers when needed.
|
||||
|
||||
There are two variants:
|
||||
## Storage Injectors
|
||||
Storage Injectors take items from other nodes' inventories and make them available only to Mass Storage on the network. Just as with Suppliers, they won't push items into the network, but the difference is that Storage Injectors don't need to be configured for any items and instead will act as a source of items for any Mass Storage boxes that is pulling in items. Storage Injectors do not interact with Demanders
|
||||
|
||||
### Item Supplier
|
||||
This supplier takes only 1 item from each inventory slot it checks and fulfils one single demand with it.
|
||||
## Mass Storage
|
||||
Mass Storage box provide mass-storage for items, and are the first place a Demander will look for to fulfil any demand. Mass Storage needs to be configured with the exact items to store, and can also be upgraded to store more items. Mass Storage can also be set to actively pull items in from Suppliers and Storage Injectors.
|
||||
|
||||
### Stack Supplier
|
||||
This supplier will take the whole stack, or as many items as are needed out of a stack, and try to fulfil any demand on its network with those items.
|
||||
## Item Storage
|
||||
The Item Storage box provides a large number of storage slots, spread over 2 pages -- but it can only store tools (specifically, items that have a max stack size of 1). Item storage is also accessed by Demanders to provide items.
|
||||
|
||||
## Storage
|
||||
# Tools
|
||||
|
||||
Storage nodes provide mass-storage for items. They also act as suppliers for any demand. Storage nodes are more efficient at fulfilling demand over suppliers because they do not need to check one inventory slot at a time, but instead consider their entire inventory.
|
||||
## Network Info Tool
|
||||
Whe used on a Logistica node it will show which network, if any, the node is part of.
|
@ -11,6 +11,7 @@ High Priority:
|
||||
- Crafting Supplier
|
||||
- Ability to name storages
|
||||
- Machine Upgrades
|
||||
- Mesecons compat
|
||||
|
||||
Medium Priority
|
||||
- Wirelss Network Extender
|
||||
@ -19,6 +20,9 @@ Medium Priority
|
||||
- Rework all UI icons to be.. 48x48? 64x64? something else?
|
||||
- Direct pipeworks compatibility
|
||||
- Direct tubelib compatibility
|
||||
- Demander modes: AND/OR
|
||||
- Mode AND: supply target with "item 1 AND item 2..."
|
||||
- Mode OR: supply target with "item 1" OR (if not available) "item 2"
|
||||
|
||||
Low Priority:
|
||||
- Improve node sounds
|
||||
|
@ -32,7 +32,7 @@ function logistica.register_cable(tier, size)
|
||||
oddly_breakable_by_hand = 2,
|
||||
[cable_group] = 1,
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sounds = logistica.node_sound_metallic(),
|
||||
drop = cable_name,
|
||||
paramtype = "light",
|
||||
sunlight_propagates = true,
|
||||
|
@ -4,7 +4,7 @@ local FORMSPEC_NAME = "logconren"
|
||||
local controllerForms = {}
|
||||
|
||||
local function get_controller_formspec(pos)
|
||||
local name = logistica.get_network_name_or_nil(pos) or "<NO NETWORK>"
|
||||
local name = logistica.get_network_name_or_nil(pos) or "<ERROR>"
|
||||
return "formspec_version[6]" ..
|
||||
"size[10.5,2]" ..
|
||||
logistica.ui.background..
|
||||
@ -22,7 +22,6 @@ end
|
||||
local function on_controller_receive_fields(player, formname, fields)
|
||||
if formname ~= FORMSPEC_NAME then return end
|
||||
local playerName = player:get_player_name()
|
||||
minetest.chat_send_all("rec: "..logistica.ttos(fields))
|
||||
if fields.quit and not fields.key_enter_field then
|
||||
controllerForms[playerName] = nil
|
||||
elseif (fields[SET_BUTTON] or fields.key_enter_field) and fields[NAME_FIELD] then
|
||||
@ -114,7 +113,7 @@ logistica.register_controller("Simple Controller", {
|
||||
groups = {
|
||||
oddly_breakable_by_hand = 1, cracky = 2,
|
||||
},
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sounds = logistica.node_sound_metallic(),
|
||||
paramtype = "light",
|
||||
sunlight_propagates = false,
|
||||
drawtype = "normal",
|
||||
|
@ -17,8 +17,8 @@ local function get_demander_formspec(pos)
|
||||
return "formspec_version[4]" ..
|
||||
"size[10.6,7]" ..
|
||||
logistica.ui.background..
|
||||
logistica.ui.push_list_picker(PUSH_LIST_PICKER, 7.5, 0.7, pushPos, selectedList)..
|
||||
logistica.ui.on_off_btn(isOn, 9.5, 0.5, ON_OFF_BUTTON)..
|
||||
logistica.ui.push_list_picker(PUSH_LIST_PICKER, 6.5, 0.7, pushPos, selectedList, "Put items in:")..
|
||||
logistica.ui.on_off_btn(isOn, 9.3, 0.5, ON_OFF_BUTTON)..
|
||||
"list["..posForm..";filter;0.5,0.5;"..NUM_DEMAND_SLOTS..",1;0]"..
|
||||
"list[current_player;main;0.5,2;8,4;0]"
|
||||
end
|
||||
@ -41,7 +41,7 @@ local function on_player_receive_fields(player, formname, fields)
|
||||
local pos = demanderForms[playerName].position
|
||||
if not pos then return false end
|
||||
if logistica.toggle_machine_on_off(pos) then
|
||||
logistica.start_demander_timer(pos, 1)
|
||||
logistica.start_demander_timer(pos)
|
||||
end
|
||||
show_demander_formspec(player:get_player_name(), pos)
|
||||
elseif fields[PUSH_LIST_PICKER] then
|
||||
@ -55,7 +55,6 @@ local function on_player_receive_fields(player, formname, fields)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
local function on_demander_punch(pos, node, puncher, pointed_thing)
|
||||
local targetPos = logistica.get_demander_target(pos)
|
||||
if targetPos and puncher:is_player() and puncher:get_player_control().sneak then
|
||||
@ -86,6 +85,7 @@ local function allow_demander_storage_inv_put(pos, listname, index, stack, playe
|
||||
local slotStack = inv:get_stack(listname, index)
|
||||
slotStack:add_item(stack)
|
||||
inv:set_stack(listname, index, slotStack)
|
||||
logistica.start_demander_timer(pos, 1)
|
||||
return 0
|
||||
end
|
||||
|
||||
@ -112,8 +112,9 @@ minetest.register_on_player_receive_fields(on_player_receive_fields)
|
||||
----------------------------------------------------------------
|
||||
-- Public Registration API
|
||||
----------------------------------------------------------------
|
||||
|
||||
function logistica.register_demander(simpleName)
|
||||
-- `simpleName` is used for the description and for the name (can contain spaces)
|
||||
-- transferRate is how many items per tick this demander can transfer, -1 for unlimited
|
||||
function logistica.register_demander(simpleName, transferRate)
|
||||
local lname = string.lower(simpleName:gsub(" ", "_"))
|
||||
local demander_name = "logistica:demander_"..lname
|
||||
logistica.demanders[demander_name] = true
|
||||
@ -135,7 +136,7 @@ function logistica.register_demander(simpleName)
|
||||
is_ground_content = false,
|
||||
groups = grps,
|
||||
drop = demander_name,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sounds = logistica.node_sound_metallic(),
|
||||
on_timer = logistica.on_demander_timer,
|
||||
after_place_node = function (pos, placer, itemstack)
|
||||
after_place_demander(pos, placer, itemstack, NUM_DEMAND_SLOTS)
|
||||
@ -146,6 +147,7 @@ function logistica.register_demander(simpleName)
|
||||
allow_metadata_inventory_take = allow_demander_inv_take,
|
||||
allow_metadata_inventory_move = allow_demander_inv_move,
|
||||
logistica = {
|
||||
demander_transfer_rate = transferRate,
|
||||
on_connect_to_network = function(pos, networkId)
|
||||
logistica.start_demander_timer(pos)
|
||||
end
|
||||
@ -171,4 +173,5 @@ function logistica.register_demander(simpleName)
|
||||
|
||||
end
|
||||
|
||||
logistica.register_demander("Basic")
|
||||
logistica.register_demander("Basic", 1)
|
||||
logistica.register_demander("Stack", 99)
|
||||
|
@ -172,7 +172,7 @@ function logistica.register_mass_storage(simpleName, numSlots, numItemsPerSlot,
|
||||
description = simpleName.." Mass Storage\n(Empty)",
|
||||
tiles = { "logistica_"..lname.."_mass_storage.png" },
|
||||
groups = grps,
|
||||
sounds = default.node_sound_metal_defaults(),
|
||||
sounds = logistica.node_sound_metallic(),
|
||||
after_place_node = function(pos, placer, itemstack)
|
||||
after_place_mass_storage(pos, placer, itemstack, numSlots, numUpgradeSlots)
|
||||
end,
|
||||
|
@ -1,8 +1,6 @@
|
||||
local TIMER_DURATION_SHORT = 2.0
|
||||
local TIMER_DURATION_LONG = 4.0
|
||||
local TIMER_DURATION_SHORT = 1.0
|
||||
local TIMER_DURATION_LONG = 3.0
|
||||
local META_DEMANDER_LISTNAME = "demtarlist"
|
||||
local MASS_STORAGE_LIST_NAME = "storage"
|
||||
local ITEM_STORAGE_LIST_NAME = "main"
|
||||
local TARGET_NODES_REQUIRING_TIMER = {}
|
||||
TARGET_NODES_REQUIRING_TIMER["default:furnace"] = true
|
||||
TARGET_NODES_REQUIRING_TIMER["gravelsieve:auto_sieve3"] = true
|
||||
@ -12,6 +10,18 @@ local function get_meta(pos)
|
||||
return minetest.get_meta(pos)
|
||||
end
|
||||
|
||||
local function get_max_rate_for_demander(pos)
|
||||
local node = minetest.get_node_or_nil(pos)
|
||||
if not node then return 0 end
|
||||
local nodeDef = minetest.registered_nodes[node.name]
|
||||
if nodeDef and nodeDef.logistica and nodeDef.logistica.demander_transfer_rate then
|
||||
if nodeDef.logistica.demander_transfer_rate <= 0 then return 9999
|
||||
else return nodeDef.logistica.demander_transfer_rate end
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
local function get_valid_demander_and_target_inventory(demanderPos)
|
||||
local meta = get_meta(demanderPos)
|
||||
local targetList = meta:get_string(META_DEMANDER_LISTNAME)
|
||||
@ -27,6 +37,7 @@ local function get_valid_demander_and_target_inventory(demanderPos)
|
||||
if not targetInv:get_list(targetList) then return end
|
||||
|
||||
return {
|
||||
demanderPos = demanderPos,
|
||||
demanderInventory = meta:get_inventory(),
|
||||
targetInventory = targetInv,
|
||||
targetList = targetList,
|
||||
@ -34,10 +45,10 @@ local function get_valid_demander_and_target_inventory(demanderPos)
|
||||
}
|
||||
end
|
||||
|
||||
local function get_actual_demand_for_item(demandStack, storageInv, storageListName)
|
||||
local storageList = storageInv:get_list(storageListName)
|
||||
local function get_actual_demand_for_item(demandStack, invs)
|
||||
local storageList = invs.targetInventory:get_list(invs.targetList)
|
||||
local remaining = demandStack:get_count()
|
||||
for i,v in ipairs(storageList) do
|
||||
for i,_ in ipairs(storageList) do
|
||||
local stored = storageList[i]
|
||||
if demandStack:get_name() == stored:get_name() then
|
||||
remaining = remaining - stored:get_count()
|
||||
@ -53,71 +64,35 @@ local function get_actual_demand_for_item(demandStack, storageInv, storageListNa
|
||||
end
|
||||
end
|
||||
|
||||
local function try_to_fulfil_demanded_item_from_network_item_storage(pos, filterStack, network, inventories)
|
||||
for storageHash, _ in pairs(network.item_storage) do
|
||||
local storagePos = minetest.get_position_from_hash(storageHash)
|
||||
local storageInv = get_meta(storagePos):get_inventory()
|
||||
if storageInv:contains_item(ITEM_STORAGE_LIST_NAME, filterStack) then
|
||||
local leftover =
|
||||
logistica.insert_itemstack_for_demander(pos, filterStack)
|
||||
if leftover == 0 then -- stack max is 1, so just take the whole itemstack out
|
||||
storageInv:remove_item(ITEM_STORAGE_LIST_NAME, filterStack)
|
||||
return true
|
||||
end -- otherwise, the insert failed for some reason..
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
local function try_to_fulfil_demanded_item_from_locations(pos, filterStack, locations, inventories)
|
||||
local filterStackName = filterStack:get_name()
|
||||
local remainingDemand = filterStack:get_count()
|
||||
for storageHash, _ in pairs(locations) do
|
||||
if filterStack:get_count() == 0 then return end
|
||||
local storagePos = minetest.get_position_from_hash(storageHash)
|
||||
local storageInv = get_meta(storagePos):get_inventory()
|
||||
local storageList = storageInv:get_list(MASS_STORAGE_LIST_NAME)
|
||||
-- we can't use the usual take/put methods because mass storage exceeds max stack
|
||||
for i = #storageList, 1, -1 do -- traverse backwards for taking items
|
||||
local storageStack = storageList[i]
|
||||
if filterStackName == storageStack:get_name() then
|
||||
local numTaken = math.min(storageStack:get_count(), remainingDemand)
|
||||
local takenStack = ItemStack(filterStack)
|
||||
takenStack:set_count(numTaken)
|
||||
local leftover =
|
||||
logistica.insert_itemstack_for_demander(pos, takenStack)
|
||||
numTaken = numTaken - leftover
|
||||
storageStack:set_count(storageStack:get_count() - numTaken)
|
||||
remainingDemand = remainingDemand - numTaken
|
||||
if remainingDemand <= 0 then
|
||||
storageInv:set_list(MASS_STORAGE_LIST_NAME, storageList)
|
||||
return true
|
||||
end
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
storageInv:set_list(MASS_STORAGE_LIST_NAME, storageList)
|
||||
end
|
||||
return false
|
||||
-- returns:
|
||||
-- nil: nothing in inventory?
|
||||
-- 0: no item has demand
|
||||
-- ItemStack: the next demanded item
|
||||
local function get_next_demanded_stack(pos)
|
||||
local inventories = get_valid_demander_and_target_inventory(pos)
|
||||
if not inventories then return nil end
|
||||
local demandStack = nil
|
||||
local nextSlot = logistica.get_next_filled_item_slot(get_meta(pos), "filter")
|
||||
local startingSlot = nextSlot
|
||||
repeat
|
||||
if nextSlot <= 0 then return nil end
|
||||
local filterStack = inventories.demanderInventory:get_list("filter")[nextSlot]
|
||||
demandStack = get_actual_demand_for_item(filterStack, inventories)
|
||||
if demandStack:get_count() > 0 then return demandStack end
|
||||
nextSlot = logistica.get_next_filled_item_slot(get_meta(pos), "filter")
|
||||
until( nextSlot == startingSlot ) -- until we get back to the starting slot
|
||||
return 0 -- we had filled slots, but none had demand
|
||||
end
|
||||
|
||||
local function take_demanded_items_from_network(pos, network)
|
||||
local inventories = get_valid_demander_and_target_inventory(pos)
|
||||
if not inventories then return true end
|
||||
for _, filterStack in pairs(inventories.demanderInventory:get_list("filter")) do
|
||||
local demandStack =
|
||||
get_actual_demand_for_item(filterStack, inventories.targetInventory, inventories.targetList)
|
||||
local filterStackName = demandStack:get_name()
|
||||
local isTool = demandStack:get_stack_max() <= 1
|
||||
if isTool then
|
||||
try_to_fulfil_demanded_item_from_network_item_storage(pos, demandStack, network, inventories)
|
||||
else -- check chaced mass-storage
|
||||
local locations = network.storage_cache[filterStackName]
|
||||
if not locations then return true end
|
||||
try_to_fulfil_demanded_item_from_locations(pos, demandStack, locations, inventories)
|
||||
end
|
||||
end
|
||||
|
||||
local demandStack = get_next_demanded_stack(pos)
|
||||
if demandStack == nil then return false end
|
||||
if demandStack == 0 then return true end -- had items but nothing in demand
|
||||
-- limiting the number of items requested
|
||||
demandStack:set_count(math.min(get_max_rate_for_demander(pos), demandStack:get_count()))
|
||||
local collect = function(st) return logistica.insert_itemstack_for_demander(pos, st) end
|
||||
logistica.take_stack_from_network(demandStack, network, collect)
|
||||
return true
|
||||
end
|
||||
|
||||
----------------------------------------------------------------
|
||||
@ -127,17 +102,17 @@ end
|
||||
function logistica.start_demander_timer(pos, duration)
|
||||
if duration == nil then duration = TIMER_DURATION_SHORT end
|
||||
logistica.start_node_timer(pos, duration)
|
||||
logistica.set_logistica_node_infotext(pos, true)
|
||||
logistica.set_node_on_off_state(pos, true)
|
||||
end
|
||||
|
||||
function logistica.on_demander_timer(pos, elapsed)
|
||||
local network = logistica.get_network_or_nil(pos)
|
||||
if not network or not logistica.is_machine_on(pos) then
|
||||
logistica.set_logistica_node_infotext(pos, false)
|
||||
logistica.set_node_on_off_state(pos, false)
|
||||
return false
|
||||
end
|
||||
take_demanded_items_from_network(pos, network)
|
||||
return true
|
||||
if take_demanded_items_from_network(pos, network) then return true
|
||||
else return false end
|
||||
end
|
||||
|
||||
function logistica.set_demander_target_list(pos, listName)
|
||||
|
@ -1,7 +1,9 @@
|
||||
local path = logistica.MODPATH .. "/logic"
|
||||
-- once again, order is important
|
||||
dofile(path .. "/processing_queue.lua")
|
||||
dofile(path .. "/groups.lua")
|
||||
dofile(path .. "/network_logic.lua")
|
||||
dofile(path .. "/network_storage.lua")
|
||||
dofile(path .. "/controller.lua")
|
||||
dofile(path .. "/storage.lua")
|
||||
dofile(path .. "/supplier.lua")
|
||||
|
@ -28,6 +28,9 @@ local function has_machine(network, id)
|
||||
end
|
||||
end
|
||||
|
||||
function logistica.get_network_by_id_or_nil(networkId)
|
||||
return networks[networkId]
|
||||
end
|
||||
|
||||
function logistica.get_network_or_nil(pos)
|
||||
local hash = p2h(pos)
|
||||
|
77
logic/network_storage.lua
Normal file
77
logic/network_storage.lua
Normal file
@ -0,0 +1,77 @@
|
||||
|
||||
local MASS_STORAGE_LIST_NAME = "storage"
|
||||
local ITEM_STORAGE_LIST_NAME = "main"
|
||||
|
||||
local function get_meta(pos)
|
||||
logistica.load_position(pos)
|
||||
return minetest.get_meta(pos)
|
||||
end
|
||||
|
||||
-- tries to take a stack from the network locations
|
||||
-- calls the collectorFunc with the stack - collectorFunc needs to return how many were left-over<br>
|
||||
-- `collectorFunc = function(stackToInsert)`<br>
|
||||
-- note that it may be called multiple times as the itemstack is gathered from mass storage
|
||||
function logistica.take_stack_from_network(stackToTake, network, collectorFunc)
|
||||
if stackToTake:get_stack_max() <= 1 then
|
||||
logistica.take_stack_from_item_storage(stackToTake, network, collectorFunc)
|
||||
else
|
||||
logistica.take_stack_from_mass_storage(stackToTake, network, collectorFunc)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- calls the collectorFunc with the stack - collectorFunc needs to return how many were left-over<br>
|
||||
-- `collectorFunc = function(stackToInsert)`<br>
|
||||
-- returns true if item successfully found and given to collector, false otherwise
|
||||
function logistica.take_stack_from_item_storage(filterStack, network, collectorFunc)
|
||||
for storageHash, _ in pairs(network.item_storage) do
|
||||
local storagePos = minetest.get_position_from_hash(storageHash)
|
||||
local storageInv = get_meta(storagePos):get_inventory()
|
||||
if storageInv:contains_item(ITEM_STORAGE_LIST_NAME, filterStack) then
|
||||
local leftover = collectorFunc(filterStack)
|
||||
if leftover == 0 then -- stack max is 1, so just take the whole itemstack out
|
||||
storageInv:remove_item(ITEM_STORAGE_LIST_NAME, filterStack)
|
||||
return true
|
||||
end -- otherwise, the insert failed for some reason..
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- tries to take a stack from the given network
|
||||
-- calls the collectorFunc with the stack - collectorFunc needs to return how many were left-over<br>
|
||||
-- `collectorFunc = function(stackToInsert)`<br>
|
||||
-- note that it may be called multiple times as the itemstack is gathered from mass storage
|
||||
-- returns true if item successfully found and given to collector, false otherwise
|
||||
function logistica.take_stack_from_mass_storage(stackToTake, network, collectorFunc)
|
||||
local stackToTakeName = stackToTake:get_name()
|
||||
local remainingDemand = stackToTake:get_count()
|
||||
local massLocations = network.storage_cache[stackToTake:get_name()]
|
||||
if massLocations == nil then return end
|
||||
for storageHash, _ in pairs(massLocations) do
|
||||
if stackToTake:get_count() == 0 then return end
|
||||
local storagePos = minetest.get_position_from_hash(storageHash)
|
||||
local storageInv = get_meta(storagePos):get_inventory()
|
||||
local storageList = storageInv:get_list(MASS_STORAGE_LIST_NAME)
|
||||
-- we can't use the usual take/put methods because mass storage exceeds max stack
|
||||
for i = #storageList, 1, -1 do -- traverse backwards for taking items
|
||||
local storageStack = storageList[i]
|
||||
if stackToTakeName == storageStack:get_name() then
|
||||
local numTaken = math.min(storageStack:get_count(), remainingDemand)
|
||||
local takenStack = ItemStack(stackToTake)
|
||||
takenStack:set_count(numTaken)
|
||||
local leftover = collectorFunc(takenStack)
|
||||
numTaken = numTaken - leftover
|
||||
storageStack:set_count(storageStack:get_count() - numTaken)
|
||||
remainingDemand = remainingDemand - numTaken
|
||||
if remainingDemand <= 0 then
|
||||
storageInv:set_list(MASS_STORAGE_LIST_NAME, storageList)
|
||||
return true
|
||||
end
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
storageInv:set_list(MASS_STORAGE_LIST_NAME, storageList)
|
||||
end
|
||||
return false
|
||||
end
|
BIN
sounds/logistica_node_dig.1.ogg
Normal file
BIN
sounds/logistica_node_dig.1.ogg
Normal file
Binary file not shown.
BIN
sounds/logistica_node_dig.2.ogg
Normal file
BIN
sounds/logistica_node_dig.2.ogg
Normal file
Binary file not shown.
BIN
sounds/logistica_node_dig.3.ogg
Normal file
BIN
sounds/logistica_node_dig.3.ogg
Normal file
Binary file not shown.
BIN
sounds/logistica_node_footstep.1.ogg
Normal file
BIN
sounds/logistica_node_footstep.1.ogg
Normal file
Binary file not shown.
BIN
sounds/logistica_node_footstep.2.ogg
Normal file
BIN
sounds/logistica_node_footstep.2.ogg
Normal file
Binary file not shown.
BIN
sounds/logistica_node_footstep.3.ogg
Normal file
BIN
sounds/logistica_node_footstep.3.ogg
Normal file
Binary file not shown.
BIN
sounds/logsitica_node_dug.1.ogg
Normal file
BIN
sounds/logsitica_node_dug.1.ogg
Normal file
Binary file not shown.
BIN
sounds/logsitica_node_dug.2.ogg
Normal file
BIN
sounds/logsitica_node_dug.2.ogg
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
textures/logistica_stack_demander_back.png
Normal file
BIN
textures/logistica_stack_demander_back.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.1 KiB |
BIN
textures/logistica_stack_demander_front.png
Normal file
BIN
textures/logistica_stack_demander_front.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
BIN
textures/logistica_stack_demander_side.png
Normal file
BIN
textures/logistica_stack_demander_side.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
@ -104,12 +104,36 @@ function logistica.toggle_machine_on_off(pos)
|
||||
end
|
||||
|
||||
-- isOn is optional
|
||||
function logistica.set_logistica_node_infotext(pos, isOn)
|
||||
-- extraText is optional
|
||||
function logistica.set_node_on_off_state(pos, isOn, extraText)
|
||||
if extraText == nil then extraText = "" else extraText = "\n"..extraText end
|
||||
if isOn == nil then isOn = logistica.is_machine_on(pos) end
|
||||
logistica.load_position(pos)
|
||||
local meta = minetest.get_meta(pos)
|
||||
local node = minetest.get_node(pos)
|
||||
local text = minetest.registered_nodes[node.name].description..
|
||||
"\n"..(isOn and "Running" or "Stopped")
|
||||
extraText.."\n"..(isOn and "Running" or "Stopped")
|
||||
meta:set_string("infotext", text)
|
||||
end
|
||||
|
||||
-- returns a value of [1,#listSize], incrementing the slot each
|
||||
-- time this is called, and returining a slot that has an item
|
||||
-- if there's no item in the list, it will return 0
|
||||
function logistica.get_next_filled_item_slot(nodeMeta, listName)
|
||||
local metaKey = listName.."rot"
|
||||
local inv = nodeMeta:get_inventory()
|
||||
local listSize = inv:get_list(listName)
|
||||
if not listSize then return 0 end
|
||||
listSize = #listSize
|
||||
local startPos = nodeMeta:get_int(metaKey) or 0
|
||||
for i = startPos, startPos + listSize do
|
||||
i = (i % listSize) + 1
|
||||
local items = inv:get_stack(listName, i)
|
||||
if items:get_count() > 0 then
|
||||
nodeMeta:set_int(metaKey, i)
|
||||
return i
|
||||
end
|
||||
end
|
||||
nodeMeta:set_int(metaKey, 0)
|
||||
return 0
|
||||
end
|
||||
|
11
util/sound.lua
Normal file
11
util/sound.lua
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
function logistica.node_sound_metallic()
|
||||
local tbl = {
|
||||
footstep = {name = "logistica_node_footstep", gain = 0.2},
|
||||
dig = {name = "logistica_node_dig", gain = 0.5},
|
||||
dug = {name = "logsitica_node_dug", gain = 0.5},
|
||||
place = {name = "default_place_node_hard", gain = 0.5},
|
||||
}
|
||||
default.node_sound_defaults(tbl)
|
||||
return tbl
|
||||
end
|
22
util/ui.lua
22
util/ui.lua
@ -16,30 +16,36 @@ local function get_lists(pushToPos, allowedLists)
|
||||
end
|
||||
|
||||
|
||||
local function list_dropdown(name, itemTable, x, y, default)
|
||||
local function list_dropdown(name, itemTable, x, y, default, label)
|
||||
local labelField = ""
|
||||
if label then labelField = "label["..x..","..(y-0.2)..";"..label.."]" end
|
||||
local defaultIndex = 0
|
||||
for i, v in ipairs(itemTable) do if default == v then defaultIndex = i end end
|
||||
local items = table.concat(itemTable, ",")
|
||||
return "dropdown["..x..","..y..";2,0.6;"..name..";"..items..";"..defaultIndex..";false]"
|
||||
return "dropdown["..x..","..y..";2,0.6;"..name..";"..items..";"..defaultIndex..";false]"..labelField
|
||||
end
|
||||
|
||||
--------------------------------
|
||||
-- public functions
|
||||
--------------------------------
|
||||
|
||||
function logistica.ui.on_off_btn(isOn, x, y, name, w, h)
|
||||
function logistica.ui.on_off_btn(isOn, x, y, name, showLabel, w, h)
|
||||
if showLabel == nil then showLabel = true end
|
||||
if not w or not h then
|
||||
w = 1; h = 1
|
||||
end
|
||||
local label=""
|
||||
if showLabel then label = "label["..(x+0.2)..","..y..";Power]" end
|
||||
|
||||
local texture = (isOn and "logistica_icon_on.png" or "logistica_icon_off.png")
|
||||
return "image_button["..x..","..y..";"..w..","..h..";"..
|
||||
""..texture..";"..name..";;false;false;"..texture.."]"
|
||||
""..texture..";"..name..";;false;false;"..texture.."]"..label
|
||||
end
|
||||
|
||||
function logistica.ui.pull_list_picker(name, x, y, pullFromPos, default)
|
||||
return list_dropdown(name, get_lists(pullFromPos, logistica.ALLOWED_PULL_LISTS), x, y, default)
|
||||
function logistica.ui.pull_list_picker(name, x, y, pullFromPos, default, label)
|
||||
return list_dropdown(name, get_lists(pullFromPos, logistica.ALLOWED_PULL_LISTS), x, y, default, label)
|
||||
end
|
||||
|
||||
function logistica.ui.push_list_picker(name, x, y, pushToPos, default)
|
||||
return list_dropdown(name, get_lists(pushToPos, logistica.ALLOWED_PUSH_LISTS), x, y, default)
|
||||
function logistica.ui.push_list_picker(name, x, y, pushToPos, default, label)
|
||||
return list_dropdown(name, get_lists(pushToPos, logistica.ALLOWED_PUSH_LISTS), x, y, default, label)
|
||||
end
|
||||
|
@ -5,3 +5,4 @@ dofile(path.."/rotations.lua")
|
||||
dofile(path.."/hud.lua")
|
||||
dofile(path.."/ui_logic.lua")
|
||||
dofile(path.."/ui.lua")
|
||||
dofile(path.."/sound.lua")
|
||||
|
Loading…
x
Reference in New Issue
Block a user