diff --git a/c-inv_0.0.2/config.lua b/c-inv_0.0.2/config.lua new file mode 100644 index 00000000..9fa3b4b1 --- /dev/null +++ b/c-inv_0.0.2/config.lua @@ -0,0 +1,11 @@ +--the chest that a player put things in +INPUT_CHEST_NAME = "put-chest" +INPUT_CHEST_PICTURE_PATH = nil +INPUT_CHEST_ICON_PATH = nil +INPUT_CHEST_FILE = "intput-items.txt" + +--the chest that the player get things from +OUTPUT_CHEST_NAME = "get-chest" +OUTPUT_CHEST_PICTURE_PATH = nil +OUTPUT_CHEST_ICON_PATH = nil +OUTPUT_CHEST_FILE = "output-items.txt" \ No newline at end of file diff --git a/c-inv_0.0.2/control.lua b/c-inv_0.0.2/control.lua index 1b7a9046..b8c46c67 100644 --- a/c-inv_0.0.2/control.lua +++ b/c-inv_0.0.2/control.lua @@ -1,236 +1,142 @@ -script.on_init(function() - if global.timer == nil then - global.timer = 0 - end - if global.guitimer == nil then - global.guitimer = 0 - end - global.spentItems = {} - global.items = {} - global.items["iron-plate"] = 100 -end) --- GUI functions ---[[ -/c game.player.gui.left.clusterio.destroy() -game.player.gui.left.add{type="frame", name="clusterio", caption="Clusterio"} -game.player.gui.left.clusterio.add{type="label", name="clusterioInputLabel", caption="Iron plates: "} -game.player.gui.left.clusterio.add{type="textfield", name="clusterioInput"} -game.player.gui.left.clusterio.add{type="button", name="clusterioButtonSave", caption="Save"} -game.player.gui.left.clusterio.style.maximal_height=10 -]]-- -global.items = {} --- request items -script.on_event(defines.events.on_tick, function(event) - if global.guitimer > 1800 then - global.guitimer = 0 - -- request spentItems * 2 - items left - for k, v in pairs(spentItems) do - _print(k, v, " | ", (v * 2) - items[k]) - game.write_file("order.txt", k .. " " .. (v * 2) - items[k] .. "\n", true) - global.spentItems[k] = 0 - end - - else - global.guitimer = global.guitimer + 1 - end -end) -remote.add_interface("clusterio", { - hello = function() game.player.print("Hi!") end, - import = function(name, value) - _print(name) - _print(value) - if(type(name) == "string" and type(tonumber(value)) == "number") then - if(global.items == nil) then global.items = {} end - global.items[name] = tonumber(value); +require("config") + +function HashPosition(position) + return 40000 * (position.y) + position.x +end + +function OnBuiltEntity(event) + local entity = event.created_entity + --only add entities that are not ghosts + if entity.type ~= "entity-ghost" then + if entity.name == INPUT_CHEST_NAME then + --if the table hasn't been initialized then do it + global.inputChests = global.inputChests or {} + --add the chests to a lists if these chests so they can be interated over + global.inputChests[HashPosition(entity.position)] = entity + elseif entity.name == OUTPUT_CHEST_NAME then + --if the table hasn't been initialized then do it + global.outputChests = global.outputChests or {} + --add the chests to a lists if these chests so they can be interated over + global.outputChests[HashPosition(entity.position)] = entity end end -}) -script.on_load(function() - if global.timer == nil then - global.timer = 0 +end + +function OnKilledEntity(event) + local entity = event.entity + if entity.type ~= "entity-ghost" then + --remove the entities from the tables as they are dead + if entity.name == INPUT_CHEST_NAME then + global.inputChests[HashPosition(entity.position)] = nil + elseif entity.name == OUTPUT_CHEST_NAME then + global.outputChests[HashPosition(entity.position)] = nil + end end - if global.guitimer == nil then - global.guitimer = 0 - end - if global.spentItems == nil then - global.spentItems = {} - end - global.items = {} -end) -script.on_event(defines.events.on_tick, function(event) - if global.timer > 9 then - global.timer = 0 - voidChests() - else - global.timer = global.timer + 1 - end -end) +end + + + +--[[ Thing Creation Events ]]-- script.on_event(defines.events.on_built_entity, function(event) - if event.created_entity.name == "c-inv_voidChest" then - if global.voidChests == nil then global.voidChests = {} end - table.insert(global.voidChests, event.created_entity) - end + OnBuiltEntity(event) +end) +script.on_event(defines.events.on_robot_built_entity, function(event) + OnBuiltEntity(event) end) -function voidChests() - if global.voidChests ~= nil then - for i = 1, #global.voidChests do - if global.voidChests[i].valid then - local chest = global.voidChests[i].get_inventory(1) - if global.voidChests[i].get_inventory(defines.inventory.chest).get_contents() ~= nil then - for k,v in pairs(global.voidChests[i].get_inventory(defines.inventory.chest).get_contents()) do - -- WTF, string conectation in lua is done with .. instead of +? - game.write_file("output.txt", k .. " " .. v .. "\n", true) - end - end - global.voidChests[i].clear_items_inside() - else - table.remove(global.voidChests, i) - break - end - end - end -end - --- spawn belts - -local belts -local spawn_item = "iron-ore" -local chest_detection_rate = 50 -remote.add_interface("spawnbelt", { - setitem = function(item) - global.spawn_item = item; - spawn_item = global.spawn_item; - end -}) - -script.on_load(function(event) - if global.belts ~= nil then - belts = global.belts; - script.on_event(defines.events.on_tick, tick_belts); - end - if global.spawn_item ~= nil then - spawn_item = global.spawn_item; - end +--[[ Thing Killing Events ]]-- +script.on_event(defines.events.on_entity_died, function(event) + OnKilledEntity(event) +end) +script.on_event(defines.events.on_robot_pre_mined, function(event) + OnKilledEntity(event) +end) +script.on_event(defines.events.on_preplayer_mined_item, function(event) + OnKilledEntity(event) end) -script.on_event(defines.events.on_built_entity, function(event) - if event.created_entity.name == "spawn-belt" - or event.created_entity.name == "void-belt" then - initalize_globals(); - new_belt = {}; - new_belt["entity"] = event.created_entity; - new_belt["item"] = spawn_item; - new_belt["chest"] = nil; - table.insert(belts, new_belt) - end + + + +script.on_event(defines.events.on_tick, function(event) + global.inputChests = global.inputChests or {} + global.outputChests = global.outputChests or {} + + HandleInputChests() + HandleOutputChests() end) -function _print(...) - local args = { n = select("#", ...); ... }; - local string = ""; - for i, player in pairs(game.players) do - for i = 1, args.n do - string = string .. serpent.block(args[i]) .. "\t"; - end - player.print(string); - end -end - - -function initalize_globals() - if global.belts == nil then - global.belts = {}; - global.pumps = {}; - belts = global.belts; - pumps = global.pumps; - script.on_event(defines.events.on_tick, tick_belts) - end -end - -function destroy_globals() - if #global.belts == 0 then - belts = nil; - pumps = nil; - global.pumps = nil; - global.pumps = nil; - script.on_event(defines.events.on_tick, nil); - end -end - -function tick_belts(tick) - for k, belt in ipairs(belts) do - if belt.entity.valid ~= true then - table.remove(belts, k) - destroy_globals(); - else - if belt.entity.name == "spawn-belt" then - - -- On a lower interval rate, look for chests behind the belt to copy item type - if tick.tick % chest_detection_rate == 0 then - x = belt.entity.position.x; - y = belt.entity.position.y; - if belt.entity.direction == 0 then - y = y + 1; - elseif belt.entity.direction == 2 then - x = x - 1; - elseif belt.entity.direction == 4 then - y = y - 1; - elseif belt.entity.direction == 6 then - x = x + 1; - end - - chests = belt.entity.surface.find_entities_filtered({area = {{x,y},{x,y}}, type="container"}); - if #chests > 0 then - inventory = chests[1].get_inventory(defines.inventory.chest); - if inventory ~= nil - and inventory.valid == true - and inventory.is_empty() == false - and inventory[1].valid == true - and inventory[1].valid_for_read == true then - belt.item = inventory[1].name; +function HandleInputChests() + local linesToWriteToFile = {} + for k, v in pairs(global.inputChests) do + if v.valid then + --get the content of the chest + local items = v.get_inventory(defines.inventory.chest).get_contents() + --write everything to the file + for itemName, itemCount in pairs(items) do + linesToWriteToFile[#linesToWriteToFile + 1] = itemName..", "..itemCount.."\n" end - end + -- clear the inventory + v.get_inventory(defines.inventory.chest).clear() end - - -- Fill the belt with selected item - line1 = belt.entity.get_transport_line(1); - if line1.can_insert_at_back() then - if(global.items ~= nil and global.spentItems ~= nil) then - if(global.items[belt.item] ~= nil and global.spentItems[belt.item] ~= nil) then - if(global.items[belt.item] > 1) then - global.items[belt.item] = global.items[belt.item] - 1; - global.spentItems[belt.item] = global.spentItems[belt.item] + 1; - line1.insert_at_back({name = belt.item}); + end + if #linesToWriteToFile > 0 then + --only write to file once as i/o is slow + --it's much faster to concatenate all the lines with table.concat + --instead of doing it with the .. operator + game.write_file(INPUT_CHEST_FILE, table.concat(linesToWriteToFile), true) + end +end + +function HandleOutputChests() + local linesToWriteToFile = {} + local simpleItemStack = {} + for k, v in pairs(global.outputChests) do + if v.valid and not v.to_be_deconstructed(v.force) then + --get the inventory here once for faster execution + local chestInventory = v.get_inventory(defines.inventory.chest) + for i = 1, 10 do + --the item the chest wants + local requestItem = v.get_request_slot(i) + if requestItem ~= nil then + local itemsInChest = chestInventory.get_item_count(requestItem.name) + --if there isn't enough items in the chest + if itemsInChest < requestItem.count then + simpleItemStack.name = requestItem.name + simpleItemStack.count = requestItem.count - itemsInChest + --insert the missing items + local insertedItemsCount = chestInventory.insert(simpleItemStack) + --write how many items was inserted + linesToWriteToFile[#linesToWriteToFile + 1] = simpleItemStack.name..", "..insertedItemsCount.."\n" end - else - global.items[belt.item] = 0 - global.spentItems[belt.item] = 0 end end end - line2 = belt.entity.get_transport_line(2); - if line2.can_insert_at_back() then - if(global.items ~= nil) then - if(global.items[belt.item] ~= nil) then - if(global.items[belt.item] > 1) then - global.items[belt.item] = global.items[belt.item] - 1; - global.spentItems[belt.item] = global.spentItems[belt.item] + 1; - line2.insert_at_back({name = belt.item}); - end - else - global.items[belt.item] = 0 - end - end - end - - elseif belt.entity.name == "void-belt" then - belt.entity.get_transport_line(1).clear(); - belt.entity.get_transport_line(2).clear(); - end end - end + if #linesToWriteToFile > 0 then + --only write to file once as i/o is slow + --it's much faster to concatenate all the lines with table.concat + --instead of doing it with the .. operator + game.write_file(OUTPUT_CHEST_FILE, table.concat(linesToWriteToFile), true) + end end + + + + + + + + + + + + + + + + + diff --git a/c-inv_0.0.2/data.lua b/c-inv_0.0.2/data.lua index ac33aabb..f23ed413 100644 --- a/c-inv_0.0.2/data.lua +++ b/c-inv_0.0.2/data.lua @@ -1,8 +1,87 @@ -require("prototypes.groups") -require("prototypes.items") -require("prototypes.recipes") -require("prototypes.entitys") --- spawn belt -require("prototypes.item") -require("prototypes.recipe") -require("prototypes.entity") \ No newline at end of file +require("util") +require("config") + +function MakeLogisticEntity(entity, name, picturePath, iconPath) + entity.name = name + entity.minable.result = name + --if no picture is defined then use the default one + entity.picture.filename = picturePath or entity.picture.filename + --if no icon is defined then use the default one + entity.icon = iconPath or entity.icon + + -- add the entity to a technology so it can be unlocked + local wasAddedToTech = AddEntityToTech("construction-robotics", name) + + data:extend( + { + -- add the entity + entity, + -- add the recipe for the entity + { + type = "recipe", + name = name, + --if the recipe was succesfully attached to the tech then the recipe + --shouldn't be enabled to begin with. + --but if the recipe isn't attached to a tech then it should + --be enabled to begin with because otherwise the player can never use the item ingame + enabled = not wasAddedToTech, + ingredients = + { + {"steel-chest", 1}, + {"electronic-circuit", 3}, + {"advanced-circuit", 1} + }, + result = name, + requester_paste_multiplier = 4 + }, + { + type = "item", + name = name, + icon = entity.icon, + flags = {"goes-to-quickbar"}, + subgroup = "storage", + order = "a[items]-b["..name.."]", + place_result = name, + stack_size = 50 + } + }) +end + +--adds a recipe to a tech and returns true or if that fails returns false +function AddEntityToTech(techName, name) + --can't add the recipe to the tech if it doesn't exist + if data.raw["technology"][techName] ~= nil then + local effects = data.raw["technology"][techName].effects + --if another mod removed the effects or made it nil then make a new table to put the recipe in + effects = effects or {} + --insert the recipe as an unlock when the research is done + effects[#effects + 1] = { + type = "unlock-recipe", + recipe = name + } + --if a new table for the effects is made then the effects has to be attached to the + -- tech again because the table won't otherwise be owned by the tech + data.raw["technology"][techName].effects = effects + return true + end + return false +end + + + +MakeLogisticEntity(table.deepcopy(data.raw["logistic-container"]["logistic-chest-requester"]), OUTPUT_CHEST_NAME, OUTPUT_CHEST_PICTURE_PATH, OUTPUT_CHEST_ICON_PATH) +MakeLogisticEntity(table.deepcopy(data.raw["container"]["iron-chest"]), INPUT_CHEST_NAME, INPUT_CHEST_PICTURE_PATH, INPUT_CHEST_ICON_PATH) + + + + + + + + + + + + + + diff --git a/c-inv_0.0.2/graphics/entity/spawn-belt/spawn-belt.png b/c-inv_0.0.2/graphics/entity/spawn-belt/spawn-belt.png deleted file mode 100644 index 65097990..00000000 Binary files a/c-inv_0.0.2/graphics/entity/spawn-belt/spawn-belt.png and /dev/null differ diff --git a/c-inv_0.0.2/graphics/entity/void-belt/void-belt.png b/c-inv_0.0.2/graphics/entity/void-belt/void-belt.png deleted file mode 100644 index 65097990..00000000 Binary files a/c-inv_0.0.2/graphics/entity/void-belt/void-belt.png and /dev/null differ diff --git a/c-inv_0.0.2/graphics/icons/spawn-belt.png b/c-inv_0.0.2/graphics/icons/spawn-belt.png deleted file mode 100644 index af378a95..00000000 Binary files a/c-inv_0.0.2/graphics/icons/spawn-belt.png and /dev/null differ diff --git a/c-inv_0.0.2/graphics/icons/void-belt.png b/c-inv_0.0.2/graphics/icons/void-belt.png deleted file mode 100644 index af378a95..00000000 Binary files a/c-inv_0.0.2/graphics/icons/void-belt.png and /dev/null differ diff --git a/c-inv_0.0.2/inspect.lua b/c-inv_0.0.2/inspect.lua deleted file mode 100644 index be805452..00000000 --- a/c-inv_0.0.2/inspect.lua +++ /dev/null @@ -1,336 +0,0 @@ -local inspect ={ - _VERSION = 'inspect.lua 3.1.0', - _URL = 'http://github.com/kikito/inspect.lua', - _DESCRIPTION = 'human-readable representations of tables', - _LICENSE = [[ - MIT LICENSE - Copyright (c) 2013 Enrique García Cota - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ]] -} - -local tostring = tostring - -inspect.KEY = setmetatable({}, {__tostring = function() return 'inspect.KEY' end}) -inspect.METATABLE = setmetatable({}, {__tostring = function() return 'inspect.METATABLE' end}) - --- Apostrophizes the string if it has quotes, but not aphostrophes --- Otherwise, it returns a regular quoted string -local function smartQuote(str) - if str:match('"') and not str:match("'") then - return "'" .. str .. "'" - end - return '"' .. str:gsub('"', '\\"') .. '"' -end - --- \a => '\\a', \0 => '\\0', 31 => '\31' -local shortControlCharEscapes = { - ["\a"] = "\\a", ["\b"] = "\\b", ["\f"] = "\\f", ["\n"] = "\\n", - ["\r"] = "\\r", ["\t"] = "\\t", ["\v"] = "\\v" -} -local longControlCharEscapes = {} -- \a => nil, \0 => \000, 31 => \031 -for i=0, 31 do - local ch = string.char(i) - if not shortControlCharEscapes[ch] then - shortControlCharEscapes[ch] = "\\"..i - longControlCharEscapes[ch] = string.format("\\%03d", i) - end -end - -local function escape(str) - return (str:gsub("\\", "\\\\") - :gsub("(%c)%f[0-9]", longControlCharEscapes) - :gsub("%c", shortControlCharEscapes)) -end - -local function isIdentifier(str) - return type(str) == 'string' and str:match( "^[_%a][_%a%d]*$" ) -end - -local function isSequenceKey(k, sequenceLength) - return type(k) == 'number' - and 1 <= k - and k <= sequenceLength - and math.floor(k) == k -end - -local defaultTypeOrders = { - ['number'] = 1, ['boolean'] = 2, ['string'] = 3, ['table'] = 4, - ['function'] = 5, ['userdata'] = 6, ['thread'] = 7 -} - -local function sortKeys(a, b) - local ta, tb = type(a), type(b) - - -- strings and numbers are sorted numerically/alphabetically - if ta == tb and (ta == 'string' or ta == 'number') then return a < b end - - local dta, dtb = defaultTypeOrders[ta], defaultTypeOrders[tb] - -- Two default types are compared according to the defaultTypeOrders table - if dta and dtb then return defaultTypeOrders[ta] < defaultTypeOrders[tb] - elseif dta then return true -- default types before custom ones - elseif dtb then return false -- custom types after default ones - end - - -- custom types are sorted out alphabetically - return ta < tb -end - --- For implementation reasons, the behavior of rawlen & # is "undefined" when --- tables aren't pure sequences. So we implement our own # operator. -local function getSequenceLength(t) - local len = 1 - local v = rawget(t,len) - while v ~= nil do - len = len + 1 - v = rawget(t,len) - end - return len - 1 -end - -local function getNonSequentialKeys(t) - local keys = {} - local sequenceLength = getSequenceLength(t) - for k,_ in pairs(t) do - if not isSequenceKey(k, sequenceLength) then table.insert(keys, k) end - end - table.sort(keys, sortKeys) - return keys, sequenceLength -end - -local function getToStringResultSafely(t, mt) - local __tostring = type(mt) == 'table' and rawget(mt, '__tostring') - local str, ok - if type(__tostring) == 'function' then - ok, str = pcall(__tostring, t) - str = ok and str or 'error: ' .. tostring(str) - end - if type(str) == 'string' and #str > 0 then return str end -end - -local function countTableAppearances(t, tableAppearances) - tableAppearances = tableAppearances or {} - - if type(t) == 'table' then - if not tableAppearances[t] then - tableAppearances[t] = 1 - for k,v in pairs(t) do - countTableAppearances(k, tableAppearances) - countTableAppearances(v, tableAppearances) - end - countTableAppearances(getmetatable(t), tableAppearances) - else - tableAppearances[t] = tableAppearances[t] + 1 - end - end - - return tableAppearances -end - -local copySequence = function(s) - local copy, len = {}, #s - for i=1, len do copy[i] = s[i] end - return copy, len -end - -local function makePath(path, ...) - local keys = {...} - local newPath, len = copySequence(path) - for i=1, #keys do - newPath[len + i] = keys[i] - end - return newPath -end - -local function processRecursive(process, item, path, visited) - - if item == nil then return nil end - if visited[item] then return visited[item] end - - local processed = process(item, path) - if type(processed) == 'table' then - local processedCopy = {} - visited[item] = processedCopy - local processedKey - - for k,v in pairs(processed) do - processedKey = processRecursive(process, k, makePath(path, k, inspect.KEY), visited) - if processedKey ~= nil then - processedCopy[processedKey] = processRecursive(process, v, makePath(path, processedKey), visited) - end - end - - local mt = processRecursive(process, getmetatable(processed), makePath(path, inspect.METATABLE), visited) - setmetatable(processedCopy, mt) - processed = processedCopy - end - return processed -end - - - -------------------------------------------------------------------- - -local Inspector = {} -local Inspector_mt = {__index = Inspector} - -function Inspector:puts(...) - local args = {...} - local buffer = self.buffer - local len = #buffer - for i=1, #args do - len = len + 1 - buffer[len] = args[i] - end -end - -function Inspector:down(f) - self.level = self.level + 1 - f() - self.level = self.level - 1 -end - -function Inspector:tabify() - self:puts(self.newline, string.rep(self.indent, self.level)) -end - -function Inspector:alreadyVisited(v) - return self.ids[v] ~= nil -end - -function Inspector:getId(v) - local id = self.ids[v] - if not id then - local tv = type(v) - id = (self.maxIds[tv] or 0) + 1 - self.maxIds[tv] = id - self.ids[v] = id - end - return tostring(id) -end - -function Inspector:putKey(k) - if isIdentifier(k) then return self:puts(k) end - self:puts("[") - self:putValue(k) - self:puts("]") -end - -function Inspector:putTable(t) - if t == inspect.KEY or t == inspect.METATABLE then - self:puts(tostring(t)) - elseif self:alreadyVisited(t) then - self:puts('