Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- if not MergingChests then MergingChests = {} end
- if not MergingChests.Migrations then MergingChests.Migrations = {} end
- if not MergingChests.Migrations._1_3_0 then MergingChests.Migrations_1_3_0 = false end
- require("config")
- function sortByX(entityA, entityB)
- local xResult = entityA.position.x - entityB.position.x
- if xResult == 0 then
- return entityA.position.y < entityB.position.y
- else
- return xResult < 0
- end
- end
- function sortByY(entityA, entityB)
- local yResult = entityA.position.y - entityB.position.y
- if yResult == 0 then
- return entityA.position.x < entityB.position.x
- else
- return yResult < 0
- end
- end
- function string.starts(String,Start)
- return string.sub(String,1,string.len(Start))==Start
- end
- function math.round(num)
- if num >= 0 then
- return math.floor(num + 0.5)
- else
- return math.ceil(num - 0.5)
- end
- end
- function MergingChests.OnTick()
- if not MergingChests.Migrations._1_3_0 then
- for _, force in pairs(game.forces) do
- if force.technologies["steel-processing"] then
- if force.technologies["steel-processing"].researched then
- for __, size in pairs(MergingChests.ChestRecipes) do
- force.recipes["wide-chest-"..size].enabled = true
- force.recipes["high-chest-"..size].enabled = true
- end
- end
- end
- end
- MergingChests.Migrations._1_3_0 = true
- end
- --############################################# Apriori code start #############################################
- MergingChests.ProcessTasksToMerge()
- --############################################# Apriori code end #############################################
- end
- function MergingChests.GetChestSize(entity, ghost_mode)
- if entity.name == "steel-chest" then
- return 1
- elseif string.starts(entity.name, "wide-chest-") or string.starts(entity.name, "high-chest-") then
- -- skip "????-chest-" to get length
- return tonumber(string.sub(entity.name, 12))
- --############################################# Apriori code start #############################################
- elseif ghost_mode and entity.name == "entity-ghost" and (string.starts(entity.ghost_name, "wide-chest-") or string.starts(entity.ghost_name, "high-chest-")) then
- return tonumber(string.sub(entity.ghost_name, 12))
- --############################################# Apriori code end #############################################
- else
- return 0
- end
- end
- function MergingChests.FindBoundingBoxSize(entities)
- -- TODO calculate with wide chests
- local min = entities[1].position
- local max = entities[1].position
- for i = 2, #entities do
- --local size = MergingChests.GetChestSize(entities[i])
- if min.x > entities[i].position.x then min.x = entities[i].position.x end
- if min.y > entities[i].position.y then min.y = entities[i].position.y end
- if max.x < entities[i].position.x then max.x = entities[i].position.x end
- if max.y < entities[i].position.y then max.y = entities[i].position.y end
- end
- local width = math.ceil(max.x) - math.floor(min.x)
- local height = math.ceil(max.y) - math.floor(min.y)
- return width, height
- end
- function MergingChests.SortIntoGroups(entities, mergeHorizontaly)
- -- TODO calculate with wide chests
- local result = {}
- local maxXDiff = 0
- local maxYDiff = 0
- if mergeHorizontaly then
- table.sort(entities, sortByY)
- maxXDiff = 1.1
- maxYDiff = 0.1
- else
- table.sort(entities, sortByX)
- maxXDiff = 0.1
- maxYDiff = 1.1
- end
- local group = { entities[1] }
- local lastX = entities[1].position.x
- local lastY = entities[1].position.y
- for i = 2, #entities do
- if lastX + maxXDiff > entities[i].position.x and lastY + maxYDiff > entities[i].position.y then
- if #group == MergingChests.MaxSize then
- table.insert(result, group)
- group = { entities[i] }
- else
- table.insert(group, entities[i])
- end
- else
- -- if there was something to merge, add group
- if #group > 1 then
- table.insert(result, group)
- end
- group = { entities[i] }
- end
- lastX = entities[i].position.x
- lastY = entities[i].position.y
- end
- if #group > 1 then
- table.insert(result, group)
- end
- return result
- end
- -- merging of chests
- function MergingChests.OnPlayerSelectedArea(event)
- if event.item and event.item == "merge-chest-selector" then
- local player = game.players[event.player_index]
- if event.area.left_top.x ~= event.area.right_bottom.x and event.area.left_top.y ~= event.area.right_bottom.y then
- -- use event entities and remove everything but steel-chest
- local entities = event.entities
- for i = #entities, 1, -1 do
- if entities[i].name ~= "steel-chest" then
- table.remove(entities, i)
- end
- end
- if #entities > 1 then
- --############################################# Apriori moved this block of code lower: #############################################
- MergingChests.PerformMerging(entities, player)
- end
- end
- end
- end
- function MergingChests.PerformMerging(entities, player)
- -- find new bounding box
- local width, height = MergingChests.FindBoundingBoxSize(entities)
- if width ~= height then
- local mergeHorizontaly = width > height
- local entityGroups = MergingChests.SortIntoGroups(entities, mergeHorizontaly)
- for _, group in ipairs(entityGroups) do
- -- calculate new chest middle offset
- local offset = 0
- for j = 2, #group do
- offset = offset + MergingChests.GetChestSize(group[j]) / 2
- end
- if mergeHorizontaly then
- MergingChests.MergeHorizontal(group, player, offset)
- else
- MergingChests.MergeVertical(group, player, offset)
- end
- end
- else
- player.print("Merging of multiple lines of chests require selection width to be different from height.")
- end
- end
- function MergingChests.MergeHorizontal(entities, player, offset)
- local newChest = player.surface.create_entity{name = "wide-chest-"..#entities, position = {entities[1].position.x + offset, entities[1].position.y}, force = player.force}
- MergingChests.MoveToInventory(entities, newChest)
- end
- function MergingChests.MergeVertical(entities, player, offset)
- local newChest = player.surface.create_entity{name = "high-chest-"..#entities, position = {entities[1].position.x, entities[1].position.y + offset}, force = player.force}
- MergingChests.MoveToInventory(entities, newChest)
- end
- function MergingChests.MoveToInventory(fromEntities, toEntity)
- local toInventory = toEntity.get_inventory(1)
- local destinationStack = 1
- for i, entity in ipairs(fromEntities) do
- local oldInventory = entity.get_inventory(1)
- for j = 1, #oldInventory do
- if destinationStack > #toInventory then
- break
- elseif oldInventory[j].valid_for_read then
- toInventory[destinationStack].set_stack(oldInventory[j])
- destinationStack = destinationStack + 1
- end
- end
- entity.destroy()
- end
- end
- -- splitting of chests
- function MergingChests.OnPlayerAltSelectedArea(event)
- if event.item and event.item == "merge-chest-selector" then
- local player = game.players[event.player_index]
- if event.area.left_top.x ~= event.area.right_bottom.x and event.area.left_top.y ~= event.area.right_bottom.y then
- -- use event entities and remove everything but wide-chests and high-chests
- local entities = event.entities
- for i = #entities, 1, -1 do
- if not string.starts(entities[i].name, "wide-chest-") and not string.starts(entities[i].name, "high-chest-") then
- table.remove(entities, i)
- end
- end
- if #entities > 0 then
- for i, entity in ipairs(entities) do
- local size = MergingChests.GetChestSize(entity)
- if string.starts(entities[i].name, "wide-chest-") then
- MergingChests.SplitHorizontaly(entity, player, size)
- elseif string.starts(entities[i].name, "high-chest-") then
- MergingChests.SplitVerticaly(entity, player, size)
- end
- end
- end
- end
- end
- end
- function MergingChests.SplitHorizontaly(entity, player, count)
- local newEntities = { }
- for i = 1, count do
- table.insert(newEntities, player.surface.create_entity{name = "steel-chest", position = {entity.position.x - (count + 1) / 2 + i, entity.position.y}, force = player.force})
- end
- MergingChests.MoveToInventories(entity, newEntities)
- end
- function MergingChests.SplitVerticaly(entity, player, count)
- local newEntities = { }
- for i = 1, count do
- table.insert(newEntities, player.surface.create_entity{name = "steel-chest", position = {entity.position.x, entity.position.y - (count + 1) / 2 + i}, force = player.force})
- end
- MergingChests.MoveToInventories(entity, newEntities)
- end
- --############################################# Apriori code start #############################################
- function MergingChests.SplitGhostHorizontaly(entity, player, count)
- for i = 1, count do
- player.surface.create_entity{name = "entity-ghost", inner_name = "steel-chest", expires = false, position = {entity.position.x - (count + 1) / 2 + i, entity.position.y}, force = player.force}
- end
- entity.destroy()
- end
- function MergingChests.SplitGhostVerticaly(entity, player, count)
- for i = 1, count do
- player.surface.create_entity{name = "entity-ghost", inner_name = "steel-chest", expires = false, position = {entity.position.x, entity.position.y - (count + 1) / 2 + i}, force = player.force}
- end
- entity.destroy()
- end
- --############################################# Apriori code end #############################################
- function MergingChests.MoveToInventories(fromEntity, toEntities)
- local oldInventory = fromEntity.get_inventory(1)
- local destinationStack = 1
- local j = 1
- local toInventory = toEntities[j].get_inventory(1)
- for i = 1, #oldInventory do
- if oldInventory[i].valid_for_read then
- toInventory[destinationStack].set_stack(oldInventory[i])
- destinationStack = destinationStack + 1
- end
- if destinationStack > #toInventory then
- j = j + 1
- if j > #toEntities then
- break
- end
- toInventory = toEntities[j].get_inventory(1)
- destinationStack = 1
- end
- end
- fromEntity.destroy()
- end
- --############################################# Apriori code start #############################################
- function MergingChests.OnBuilt(event)
- local player = game.players[event.player_index]
- local entity = event.created_entity
- if entity and entity.valid and entity.name == "entity-ghost" and (string.starts(entity.ghost_name, "wide-chest-") or string.starts(entity.ghost_name, "high-chest-")) then
- local size = MergingChests.GetChestSize(entity, true)
- local task_to_merge = {
- surface_index = entity.surface.index,
- bounding_box = entity.bounding_box,
- chest_size = size,
- player_index = event.player_index,
- created_at = event.tick
- }
- if string.starts(entity.ghost_name, "wide-chest-") then
- MergingChests.SplitGhostHorizontaly(entity, player, size)
- elseif string.starts(entity.ghost_name, "high-chest-") then
- MergingChests.SplitGhostVerticaly(entity, player, size)
- end
- if not global.tasks_to_merge then
- global.tasks_to_merge = {}
- end
- table.insert(global.tasks_to_merge, task_to_merge)
- end
- end
- function MergingChests.ProcessTasksToMerge()
- if not global.tasks_to_merge then return end
- for counter = #global.tasks_to_merge, 1, -1 do
- local task = global.tasks_to_merge[counter]
- if game.tick - task.created_at > 18000 then -- 5*60*60 = 5 minutes
- table.remove(global.tasks_to_merge, counter)
- else
- local entities = game.surfaces[task.surface_index].find_entities(task.bounding_box)
- for i = #entities, 1, -1 do
- if entities[i].name ~= "steel-chest" then
- table.remove(entities, i)
- end
- end
- if #entities == task.chest_size then
- MergingChests.PerformMerging(entities, game.players[task.player_index])
- table.remove(global.tasks_to_merge, counter)
- end
- end
- end
- if #global.tasks_to_merge < 1 then global.tasks_to_merge = nil end
- end
- script.on_event(defines.events.on_built_entity, MergingChests.OnBuilt)
- --############################################# Apriori code end #############################################
- script.on_event(defines.events.on_player_selected_area, MergingChests.OnPlayerSelectedArea)
- script.on_event(defines.events.on_player_alt_selected_area, MergingChests.OnPlayerAltSelectedArea)
- script.on_event(defines.events.on_tick, MergingChests.OnTick)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement