diff --git a/api/api.lua b/api/api.lua index f696b72..214f094 100644 --- a/api/api.lua +++ b/api/api.lua @@ -16,3 +16,4 @@ dofile(path.."/vaccuum_chest.lua") dofile(path.."/crafter_auto.lua") dofile(path.."/crafting_supplier.lua") dofile(path.."/cobble_supplier.lua") +dofile(path.."/synchronizer.lua") diff --git a/api/synchronizer.lua b/api/synchronizer.lua new file mode 100644 index 0000000..ec65335 --- /dev/null +++ b/api/synchronizer.lua @@ -0,0 +1,67 @@ + +-------------------------------- +-- callbacks +-------------------------------- + +local function on_rightclick_sync(pos, node, clicker, itemstack, pointed_thing) + if not clicker or not clicker:is_player() then return end + if minetest.is_protected(pos, clicker:get_player_name()) then return end + logistica.sync_on_rightclick(pos, node, clicker, itemstack, pointed_thing) +end + +local function after_place_sync(pos, placer, itemstack) + logistica.sync_after_place(pos, placer, itemstack) +end + +local function allow_storage_inv_put_sync(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then return 0 end + return logistica.sync_allow_storage_inv_put(pos, listname, index, stack, player) +end + +local function allow_inv_take_sync(pos, listname, index, stack, player) + if minetest.is_protected(pos, player:get_player_name()) then return 0 end + return logistica.sync_allow_inv_take(pos, listname, index, stack, player) +end + +local function allow_inv_move_sync(_, _, _, _, _, _, _) + return 0 +end + + +---------------------------------------------------------------- +-- Public Registration API +---------------------------------------------------------------- + +-- `simpleName` is used for the description and for the name (can contain spaces) +function logistica.register_synchronizer(description, name, tiles) + local lname = string.lower(name:gsub(" ", "_")) + local syncName = "logistica:"..lname + + local grps = {oddly_breakable_by_hand = 3, cracky = 3 } + local def = { + description = description, + drawtype = "normal", + tiles = tiles, + paramtype2 = "facedir", + is_ground_content = false, + groups = grps, + drop = syncName, + sounds = logistica.node_sound_metallic(), + after_place_node = after_place_sync, + on_rightclick = on_rightclick_sync, + can_dig = logistica.sync_can_dig, + allow_metadata_inventory_put = allow_storage_inv_put_sync, + allow_metadata_inventory_take = allow_inv_take_sync, + allow_metadata_inventory_move = allow_inv_move_sync, + -- on_metadata_inventory_move = logistica.sync_on_inv_move, + on_metadata_inventory_put = logistica.sync_on_inv_put, + on_metadata_inventory_take = logistica.sync_on_inv_take, + logistica = {} + } + + minetest.register_node(syncName, def) +end + +logistica.register_synchronizer("Wireless Upgrader", "wireless_synchronizer", { + "logistica_synchronizer_side.png" +}) \ No newline at end of file diff --git a/item/craft_item.lua b/item/craft_item.lua index 80c8056..f474243 100644 --- a/item/craft_item.lua +++ b/item/craft_item.lua @@ -52,6 +52,12 @@ items[L("cobblegen_upgrade")] = { stack_max = 4, } +items[L("wireless_crystal")] = { + description = S("Wireless Crystal\nUsed for upgrading the Wireless Access Pad"), + inventory_image = "logistica_wireless_crystal.png", + stack_max = 99, +} + for name, info in pairs(items) do minetest.register_craftitem(name, { description = info.description, diff --git a/logic/logic.lua b/logic/logic.lua index 9ee63b3..7a1d4f2 100644 --- a/logic/logic.lua +++ b/logic/logic.lua @@ -17,3 +17,4 @@ dofile(path.."/trashcan.lua") dofile(path.."/vaccuum_chest.lua") dofile(path.."/autocrafting_logic.lua") dofile(path.."/crafting_supplier.lua") +dofile(path.."/synchronizer.lua") diff --git a/logic/synchronizer.lua b/logic/synchronizer.lua new file mode 100644 index 0000000..c0cab95 --- /dev/null +++ b/logic/synchronizer.lua @@ -0,0 +1,373 @@ +local S = logistica.TRANSLATOR + +local FORMSPEC_NAME = "logistica_sync" + +local META_LAVA = "loglav" +local META_F1 = "crf1" +local META_S1 = "crs1" +local META_F2 = "crf2" +local META_S2 = "crs2" +local META_TF1 = "tarf1" +local META_TS1 = "tars1" +local META_TF2 = "tarf2" +local META_TS2 = "tars2" + +local MAX_LAVA_AMOUNT = 2000 -- in millibuckets + +local FUP1_BTN = "FUP1" +local FDN1_BTN = "FDN1" +local SR1_BTN = "SR1" +local SL1_BTN = "SL1" +local FUP2_BTN = "FUP2" +local FDN2_BTN = "FDN2" +local SR2_BTN = "SR2" +local SL2_BTN = "SL2" +local APPLY_BUTTON = "APPLY" + +local INV_C1 = "invc1" +local INV_C2 = "invc2" +local INV_UPGRADE = "upgr" + +local THIRD_PI = 3.1415926 / 3 +local FREQ_MIN = 200 +local FREQ_MAX = 2000 +local FREQ_STEP = 50 +local SHIFT_MAX = 3000 +local SHIFT_MIN = -3000 +local SHIFT_STEP = 500 +local DISPLAY_FACTOR = 1000.0 +local GRAPH_XMIN = -35.0 +local GRAPH_XSIZE = 70.0 +local GRAPH_YMIN = -2.2 +local GRAPH_YSIZE = 4.4 +local GRAPH_STEP = 0.1 +-- derived +local SHIFT_NUM_STEPS = (SHIFT_MAX - SHIFT_MIN) / SHIFT_STEP +local FREQ_NUM_STEPS = (FREQ_MAX - FREQ_MIN) / FREQ_STEP +local BOX_SIZE = math.min(GRAPH_STEP / 2, 0.02) +local BOX_W = BOX_SIZE * 2 + +local ITEM_WIRELESS_CRYSTAL = "logistica:wireless_crystal" +local ITEM_WAP = "logistica:wireless_access_pad" + +local WAP_RANGE_INCREASE_STEP = 200 + +local COLOR_TARGET = "#6BA1FFFF" +local COLOR_PTS_NO_MATCH = "#FFB300FF" +local COLOR_PTS_MATCH = "#CCFF00FF" + +local forms = {} +local get_meta = minetest.get_meta + +---------------------------------------------------------------- +-- local funcs +---------------------------------------------------------------- + +-- returns true if there was enough lava (and was used), false if not +-- local function use_lava(meta, amount) +-- local currLevel = meta:get_int(META_LAVA) +-- if currLevel - amount >= 0 then +-- meta:set_int(META_LAVA, currLevel - amount) +-- return true +-- else +-- return false +-- end +-- end + +-- local function get_lava_level(meta) +-- return meta:get_int(META_LAVA) +-- end + +-- -- returns y value for f(x) with given params +local function f(x, freq, shift) + return math.sin( freq * x + shift * THIRD_PI ) +end + +local function both_crystals_present(inv) + return (not inv:is_empty(INV_C1)) and (not inv:is_empty(INV_C2)) +end + +local function change_freq(meta, crysNum, change) + local META_F = META_F1 ; if crysNum ~= 1 then META_F = META_F2 end + local curF = meta:get_int(META_F) + local newF = logistica.clamp(curF + change * FREQ_STEP, FREQ_MIN, FREQ_MAX) + meta:set_int(META_F, newF) +end + +local function change_shift(meta, crysNum, change) + local META_S = META_S1 ; if crysNum ~= 1 then META_S = META_S2 end + local curS = meta:get_int(META_S) + local newS = curS + change * SHIFT_STEP + if newS >= SHIFT_MAX then + meta:set_int(META_S, SHIFT_MIN) + elseif newS <= SHIFT_MIN then + meta:set_int(META_S, SHIFT_MAX) + else + meta:set_int(META_S, newS) + end +end + +local function waves_match(meta) + local freq1 = meta:get_int(META_F1) + local freq2 = meta:get_int(META_F2) + local shft1 = meta:get_int(META_S1) + local shft2 = meta:get_int(META_S2) + local freqT1 = meta:get_int(META_TF1) + local shftT1 = meta:get_int(META_TS1) + local freqT2 = meta:get_int(META_TF2) + local shftT2 = meta:get_int(META_TS2) + return (freq1 == freqT1 and shft1 == shftT1 and freq2 == freqT2 and shft2 == shftT2) or + (freq2 == freqT1 and shft2 == shftT1 and freq1 == freqT2 and shft1 == shftT2) +end + +local function apply_to_wap(pos, info) + local meta = get_meta(pos) + local inv = meta:get_inventory() + if inv:is_empty(INV_UPGRADE) then return end + if not both_crystals_present(inv) then return end + if not waves_match(meta) then return end + + local item = inv:get_stack(INV_UPGRADE, 1) + local itemMeta = item:get_meta() + if item:get_name() == ITEM_WAP then + local currRange = itemMeta:get_int(logistica.tools.wap.meta_range_key) + local newRange = currRange + WAP_RANGE_INCREASE_STEP + -- TODO: check max range against server-configurable range + itemMeta:set_int(logistica.tools.wap.meta_range_key, newRange) + itemMeta:set_string("description", logistica.tools.wap.get_description_with_range(newRange)) + inv:set_stack(INV_UPGRADE, 1, item) + inv:set_stack(INV_C1, 1, ItemStack("")) + inv:set_stack(INV_C2, 1, ItemStack("")) + end + +end + +local function set_new_targets(meta, valid) + local targetF1 = (valid and FREQ_MIN + math.random(0, FREQ_NUM_STEPS) * FREQ_STEP) or 0 + local targetF2 = (valid and FREQ_MIN + math.random(0, FREQ_NUM_STEPS) * FREQ_STEP) or 0 + local targetS1 = (valid and SHIFT_MIN + math.random(0, SHIFT_NUM_STEPS) * SHIFT_STEP) or (SHIFT_MIN - 1) + local targetS2 = (valid and SHIFT_MIN + math.random(0, SHIFT_NUM_STEPS) * SHIFT_STEP) or (SHIFT_MIN - 1) + meta:set_int(META_TF1, targetF1) + meta:set_int(META_TF2, targetF2) + meta:set_int(META_TS1, targetS1) + meta:set_int(META_TS2, targetS2) +end + +local function randomize_curr_values(meta, valid) + if not valid then return 0 end + local cF1 = FREQ_MIN + math.random(0, FREQ_NUM_STEPS) * FREQ_STEP + local cF2 = FREQ_MIN + math.random(0, FREQ_NUM_STEPS) * FREQ_STEP + local cS1 = SHIFT_MIN + math.random(0, SHIFT_NUM_STEPS) * SHIFT_STEP + local cS2 = SHIFT_MIN + math.random(0, SHIFT_NUM_STEPS) * SHIFT_STEP + meta:set_int(META_F1, cF1) + meta:set_int(META_F2, cF2) + meta:set_int(META_S1, cS1) + meta:set_int(META_S2, cS2) +end + +---------------------------------------------------------------- +-- formspec +---------------------------------------------------------------- + +local function box(xy, color) + return string.format( + "box[%s,%s;%s,%s;%s]", + tostring(xy.x - BOX_SIZE), + tostring(xy.y - BOX_SIZE), + tostring(BOX_W), + tostring(BOX_W), + color + ) +end + +-- returns {x=x, y=y} +local function map(x, y, rx, ry, rw, rh) + return { + x = rx + ((x - GRAPH_XMIN) / GRAPH_XSIZE) * rw, + y = ry + ((y - GRAPH_YMIN) / GRAPH_YSIZE) * rh, + } +end + +local function get_point_boxes(x, y, w, h, f1, s1, f2, s2, color) + if not color then return "" end + local pts = {} + for ptX = GRAPH_XMIN, GRAPH_XMIN + GRAPH_XSIZE, GRAPH_STEP do + pts[ptX] = f(ptX, f1, s1) + f(ptX, f2, s2) + end + return table.concat( + logistica.table_to_list_indexed( + pts, + function(ptX, ptY) + return box(map(ptX, ptY, x, y, w, h), color) + end + ) + ) +end + +local function get_formspec_sync(pos, playerName, optMeta) + local posForm = "nodemeta:"..pos.x..","..pos.y..","..pos.z + local meta = optMeta or get_meta(pos) + local tf1 = meta:get_int(META_TF1) / DISPLAY_FACTOR + local ts1 = meta:get_int(META_TS1) / DISPLAY_FACTOR + local tf2 = meta:get_int(META_TF2) / DISPLAY_FACTOR + local ts2 = meta:get_int(META_TS2) / DISPLAY_FACTOR + local f1 = meta:get_int(META_F1) / DISPLAY_FACTOR + local f2 = meta:get_int(META_F2) / DISPLAY_FACTOR + local s1 = meta:get_int(META_S1) / DISPLAY_FACTOR + local s2 = meta:get_int(META_S2) / DISPLAY_FACTOR + local valid = both_crystals_present(meta:get_inventory()) + local matching = waves_match(meta) + local ptsColor = nil + local tarColor = nil + local applyBtn = "" + if valid then + if matching then + ptsColor = COLOR_PTS_MATCH + applyBtn = "button[3.2,6.8;2,0.8;"..APPLY_BUTTON..";"..S("Upgrade").."]" + else + tarColor = COLOR_TARGET + ptsColor = COLOR_PTS_NO_MATCH + end + end + + local targBoxes = get_point_boxes(0.3,2.6,10,4, tf1, ts1, tf2, ts2, tarColor) + local currBoxes = get_point_boxes(0.3,2.6,10,4, f1, s1, f2, s2, ptsColor) + + return "formspec_version[4]".. + "size[10.5,13]".. + logistica.ui.background.. + "list[current_player;main;0.4,8;8,4;0]".. + "list["..posForm..";"..INV_C1..";2.9,1.1;1,1;0]".. + "list["..posForm..";"..INV_C2..";6.6,1.1;1,1;0]".. + "image_button[2.1,0.8;0.8,0.8;logistica_icon_fup.png;"..FUP1_BTN..";]".. + "image_button[2.1,1.6;0.8,0.8;logistica_icon_fdn.png;"..FDN1_BTN..";]".. + "image_button[3.9,0.8;0.8,0.8;logistica_icon_sr.png;"..SR1_BTN..";]".. + "image_button[3.9,1.6;0.8,0.8;logistica_icon_sl.png;"..SL1_BTN..";]".. + "image_button[5.8,0.8;0.8,0.8;logistica_icon_fup.png;"..FUP2_BTN..";]".. + "image_button[5.8,1.6;0.8,0.8;logistica_icon_fdn.png;"..FDN2_BTN..";]".. + "image_button[7.6,0.8;0.8,0.8;logistica_icon_sr.png;"..SR2_BTN..";]".. + "image_button[7.6,1.6;0.8,0.8;logistica_icon_sl.png;"..SL2_BTN..";]".. + "image[4.75,0.6;1,2;logistica_icon_combine.png]".. + "image[0.3,2.6;10,4;logistica_icon_graph_back.png]".. + targBoxes.. + currBoxes.. + applyBtn.. + "list["..posForm..";"..INV_UPGRADE..";5.3,6.7;1,1;0]".. + "label[3.0,0.5;Crystal 1]".. + "label[6.6,0.5;Crystal 2]".. + "label[6.4,7.2;"..S("Wireless Access Pad").."]" +end + +local function show_formspec_sync(playerName, pos, optMeta) + minetest.show_formspec(playerName, FORMSPEC_NAME, get_formspec_sync(pos, optMeta)) +end + +---------------------------------------------------------------- +-- callbacks +---------------------------------------------------------------- + +function logistica.sync_on_player_receive_fields(player, formname, fields) + if not player or not player:is_player() then return false end + if formname ~= FORMSPEC_NAME then return false end + local playerName = player:get_player_name() + if not forms[playerName] then return false end + local info = forms[playerName] + local pos = info.position + if not pos then return false end + if minetest.is_protected(pos, playerName) then return true end + local meta = get_meta(pos) + + if fields.quit then forms[playerName] = nil; return true + elseif fields[FUP1_BTN] then change_freq(meta, 1, 1) + elseif fields[FDN1_BTN] then change_freq(meta, 1, -1) + elseif fields[SR1_BTN] then change_shift(meta, 1, -1) + elseif fields[SL1_BTN] then change_shift(meta, 1, 1) + elseif fields[FUP2_BTN] then change_freq(meta, 2, 1) + elseif fields[FDN2_BTN] then change_freq(meta, 2, -1) + elseif fields[SR2_BTN] then change_shift(meta, 2, -1) + elseif fields[SL2_BTN] then change_shift(meta, 2, 1) + elseif fields[APPLY_BUTTON] then apply_to_wap(pos, info) + end + show_formspec_sync(playerName, pos, meta) + return true +end + +function logistica.sync_on_rightclick(pos, node, clicker, itemstack, pointed_thing) + for k, _ in pairs(forms) do + logistica.show_popup(clicker:get_player_name(), S("Someone is currently using this Upgrader!")) + return + end + forms[clicker:get_player_name()] = { + position = pos + } + show_formspec_sync(clicker:get_player_name(), pos) +end + +function logistica.sync_after_place(pos, placer, itemstack) + local meta = minetest.get_meta(pos) + if placer and placer:is_player() then + meta:set_string("owner", placer:get_player_name()) + end + logistica.set_infotext(pos, S("Wireless Upgrader")) + local inv = meta:get_inventory() + inv:set_size(INV_C1, 1) + inv:set_size(INV_C2, 1) + inv:set_size(INV_UPGRADE, 1) + set_new_targets(meta, false) +end + +function logistica.sync_allow_storage_inv_put(pos, listname, index, stack, player) + local inv = minetest.get_meta(pos):get_inventory() + if listname == INV_C1 or listname == INV_C2 then + if not inv:get_stack(listname, index):is_empty() then return 0 end + if stack:get_name() ~= ITEM_WIRELESS_CRYSTAL then return 0 + else return 1 end + elseif listname == INV_UPGRADE then + if stack:get_name() ~= ITEM_WAP then return 0 + else return 1 end + end + return 0 +end + +function logistica.sync_allow_inv_take(pos, listname, index, stack, player) + return 1 +end + +function logistica.sync_on_inv_put(pos, listname, index, stack, player) + if not player then return end + if listname == INV_C1 or listname == INV_C2 then + if not forms[player:get_player_name()] then return end + local meta = get_meta(pos) + if both_crystals_present(meta:get_inventory()) then + set_new_targets(meta, true) + randomize_curr_values(meta, true) + end + show_formspec_sync(player:get_player_name(), pos) + end +end + +function logistica.sync_on_inv_take(pos, listname, index, stack, player) + if not player then return end + if listname == INV_C1 or listname == INV_C2 then + if not forms[player:get_player_name()] then return end + set_new_targets(get_meta(pos), false) + show_formspec_sync(player:get_player_name(), pos) + end +end + +function logistica.sync_can_dig(pos) + local inv = get_meta(pos):get_inventory() + return inv:is_empty(INV_C1) and inv:is_empty(INV_C2) and inv:is_empty(INV_UPGRADE) +end + +---------------------------------------------------------------- +-- Minetest registration +---------------------------------------------------------------- + +minetest.register_on_player_receive_fields(logistica.sync_on_player_receive_fields) + +minetest.register_on_leaveplayer(function(objRef, _) + if objRef:is_player() then + forms[objRef:get_player_name()] = nil + end +end) diff --git a/registration/lava_furnace_recipes.lua b/registration/lava_furnace_recipes.lua index e62c09f..3784180 100644 --- a/registration/lava_furnace_recipes.lua +++ b/registration/lava_furnace_recipes.lua @@ -31,3 +31,11 @@ logistica.register_lava_furnace_recipe("default:glass", { additive_use_chance = 100, time = 4 }) + +logistica.register_lava_furnace_recipe(L("silverin"), { + output = L("wireless_crystal"), + lava = 120, + additive = "default:mese_crystal", + additive_use_chance = 100, + time = 6 +}) diff --git a/textures/logistica_icon_combine.png b/textures/logistica_icon_combine.png new file mode 100644 index 0000000..234aba5 Binary files /dev/null and b/textures/logistica_icon_combine.png differ diff --git a/textures/logistica_icon_fdn.png b/textures/logistica_icon_fdn.png new file mode 100644 index 0000000..19a1bc2 Binary files /dev/null and b/textures/logistica_icon_fdn.png differ diff --git a/textures/logistica_icon_fup.png b/textures/logistica_icon_fup.png new file mode 100644 index 0000000..9536dfe Binary files /dev/null and b/textures/logistica_icon_fup.png differ diff --git a/textures/logistica_icon_graph_back.png b/textures/logistica_icon_graph_back.png new file mode 100644 index 0000000..de30a4d Binary files /dev/null and b/textures/logistica_icon_graph_back.png differ diff --git a/textures/logistica_icon_sl.png b/textures/logistica_icon_sl.png new file mode 100644 index 0000000..24713f5 Binary files /dev/null and b/textures/logistica_icon_sl.png differ diff --git a/textures/logistica_icon_sr.png b/textures/logistica_icon_sr.png new file mode 100644 index 0000000..3360e42 Binary files /dev/null and b/textures/logistica_icon_sr.png differ diff --git a/textures/logistica_synchronizer_side.png b/textures/logistica_synchronizer_side.png new file mode 100644 index 0000000..9d930b2 Binary files /dev/null and b/textures/logistica_synchronizer_side.png differ diff --git a/textures/logistica_wireless_crystal.png b/textures/logistica_wireless_crystal.png new file mode 100644 index 0000000..87443bc Binary files /dev/null and b/textures/logistica_wireless_crystal.png differ diff --git a/tools/tools.lua b/tools/tools.lua index 2225944..02ca203 100644 --- a/tools/tools.lua +++ b/tools/tools.lua @@ -1,4 +1,6 @@ local path = logistica.MODPATH.."/tools" +logistica.tools = {} + dofile(path.."/misc.lua") dofile(path.."/wireless_access_pad.lua") diff --git a/tools/wireless_access_pad.lua b/tools/wireless_access_pad.lua index 2d79f9f..c4cfa0f 100644 --- a/tools/wireless_access_pad.lua +++ b/tools/wireless_access_pad.lua @@ -1,7 +1,18 @@ local S = logistica.TRANSLATOR local META_ACCESS_POINT_POSITION = "logacptps" -local WAP_MAX_DIST_DEF = 200 -- in nodes +local META_RANGE = "log_range" + +local STR_INIT_TIP = S("Put in a Wireless Upgrader to initialize") + +logistica.tools.wap = { + meta_range_key = META_RANGE, + description_default = S("Wireless Access Pad").."\n"..STR_INIT_TIP, + get_description_with_range = function (range) + return S("Wireless Access Pad\nSneak+Punch an Access Point to Sync\nMax range: @1", range) + end +} + -- we need this because default tostring(number) function returns scientific representation which loses accuracy local str = function(anInt) return string.format("%.0f", anInt) end @@ -14,12 +25,22 @@ local function on_wireless_pad_primary(itemstack, user, pointed_thing) if minetest.get_item_group(node.name, logistica.TIER_ACCESS_POINT) <= 0 then return end local playerName = user:get_player_name() + local itemMeta = itemstack:get_meta() + local range = itemMeta:get_int(META_RANGE) + + if range <= 0 then + logistica.show_popup( + playerName, + S("This Wireless Access Pad is not initialized").."\n"..STR_INIT_TIP + ) + return + end + if minetest.is_protected(pos, playerName) then logistica.show_popup(playerName, S("This Access Point is in a protected area!")) return end - local itemMeta = itemstack:get_meta() local posHashStr = str(minetest.hash_node_position(pos)) itemMeta:set_string(META_ACCESS_POINT_POSITION, posHashStr) @@ -35,12 +56,28 @@ local function on_wireless_pad_secondary(itemstack, placer, pointed_thing) local itemMeta = itemstack:get_meta() local posHashStr = itemMeta:get_string(META_ACCESS_POINT_POSITION) + local range = itemMeta:get_int(META_RANGE) + if range <= 0 then + logistica.show_popup( + playerName, + S("This Wireless Access Pad is not initialized").."\n"..STR_INIT_TIP + ) + return + end + if posHashStr == "" then logistica.show_popup(playerName, S("This WAP is not synced to any Access Point.")) return end local targetPos = minetest.get_position_from_hash(tonumber(posHashStr)) + + local dist = vector.length(vector.subtract(placer:get_pos(), targetPos)) + if not dist or dist > range then + logistica.show_popup(playerName, S("The synced Access Point is too far away!")) + return + end + logistica.load_position(targetPos) logistica.try_to_wake_up_network(targetPos) @@ -71,10 +108,11 @@ end -- end) minetest.register_craftitem("logistica:wireless_access_pad",{ - description = S("Wireless Access Pad\nSneak+Punch an Access Point to Sync"), + description = logistica.tools.wap.description_default, inventory_image = "logistica_wap.png", wield_image = "logistica_wap.png", stack_max = 1, on_use = on_wireless_pad_primary, on_secondary_use = on_wireless_pad_secondary, + on_place = on_wireless_pad_secondary, }) diff --git a/util/common.lua b/util/common.lua index 5c68ae3..b97f3ae 100644 --- a/util/common.lua +++ b/util/common.lua @@ -202,3 +202,10 @@ function logistica.table_map(table, func) for k,v in pairs(table) do t[k] = func(v) end return t end + +function logistica.table_to_list_indexed(table, func) + local t = {} + local index = 0 + for k,v in pairs(table) do index = index + 1; t[index] = func(k, v) end + return t +end