174 lines
5.0 KiB
Lua
174 lines
5.0 KiB
Lua
local function direction_to_vector(direction)
|
|
if direction == defines.direction.north then
|
|
return { x = 0, y = -1 }
|
|
end
|
|
if direction == defines.direction.northeast then
|
|
return { x = 1, y = -1 }
|
|
end
|
|
if direction == defines.direction.east then
|
|
return { x = 1, y = 0 }
|
|
end
|
|
if direction == defines.direction.southeast then
|
|
return { x = 1, y = 1 }
|
|
end
|
|
if direction == defines.direction.south then
|
|
return { x = 0, y = 1 }
|
|
end
|
|
if direction == defines.direction.southwest then
|
|
return { x = -1, y = 1 }
|
|
end
|
|
if direction == defines.direction.west then
|
|
return { x = -1, y = 0 }
|
|
end
|
|
if direction == defines.direction.northwest then
|
|
return { x = -1, y = -1 }
|
|
end
|
|
return { x = 0, y = -1 } -- north
|
|
end
|
|
|
|
local function vector_to_direction(vector)
|
|
if vector.x == 0 and vector.y < 0 then
|
|
return defines.direction.north
|
|
end
|
|
if vector.x > 0 and vector.y < 0 then
|
|
return defines.direction.northeast
|
|
end
|
|
if vector.x > 0 and vector.y == 0 then
|
|
return defines.direction.east
|
|
end
|
|
if vector.x > 0 and vector.y > 0 then
|
|
return defines.direction.southeast
|
|
end
|
|
if vector.x == 0 and vector.y > 0 then
|
|
return defines.direction.south
|
|
end
|
|
if vector.x < 0 and vector.y > 0 then
|
|
return defines.direction.southwest
|
|
end
|
|
if vector.x < 0 and vector.y == 0 then
|
|
return defines.direction.west
|
|
end
|
|
if vector.x < 0 and vector.y < 0 then
|
|
return defines.direction.northwest
|
|
end
|
|
return defines.direction.north
|
|
end
|
|
|
|
local function multiply_matrix_vector(matrix, vector)
|
|
return {
|
|
x = matrix[1].x * vector.x + matrix[2].x * vector.y,
|
|
y = matrix[1].y * vector.x + matrix[2].y * vector.y,
|
|
}
|
|
end
|
|
|
|
local function multiply_matrix_matrix(matrix1, matrix2)
|
|
return {
|
|
multiply_matrix_vector(matrix1, matrix2[1]),
|
|
multiply_matrix_vector(matrix1, matrix2[2]),
|
|
}
|
|
end
|
|
|
|
return function(blueprint_entities, event)
|
|
local cursor_position = event.position
|
|
local rotation = event.direction or defines.direction.north
|
|
|
|
-- first, rotate (and/or flip) the blueprint and compute it's size
|
|
local rotated_entities = {}
|
|
|
|
-- column-major tranformation matrix
|
|
local location_tranform = {
|
|
{ x = 1, y = 0 },
|
|
{ x = 0, y = 1 },
|
|
}
|
|
|
|
if event.flip_horizontal then
|
|
location_tranform[1].x = -1
|
|
end
|
|
if event.flip_vertical then
|
|
location_tranform[2].y = -1
|
|
end
|
|
|
|
for _i=2,rotation,2 do
|
|
-- multiply by the rotation matrix from the left
|
|
local rotation_matrix = {
|
|
{ x = 0, y = 1 },
|
|
{ x = -1, y = 0 }
|
|
}
|
|
location_tranform = multiply_matrix_matrix(rotation_matrix, location_tranform)
|
|
end
|
|
|
|
local minX = 1000000000
|
|
local minY = 1000000000
|
|
local maxX = -1000000000
|
|
local maxY = -1000000000
|
|
|
|
for _,entity in pairs(blueprint_entities) do
|
|
local direction = defines.direction.north
|
|
if game.entity_prototypes[entity.name].supports_direction then
|
|
local direction_vector = direction_to_vector(entity.direction or defines.direction.north)
|
|
direction = vector_to_direction(multiply_matrix_vector(location_tranform, direction_vector))
|
|
end
|
|
|
|
local position = multiply_matrix_vector(location_tranform, entity.position)
|
|
|
|
table.insert(rotated_entities, {
|
|
name = entity.name,
|
|
position = position,
|
|
direction = direction,
|
|
items = entity.items
|
|
})
|
|
|
|
local collision_box = game.entity_prototypes[entity.name].collision_box
|
|
local width = (collision_box.right_bottom.x - collision_box.left_top.x)
|
|
local height = (collision_box.right_bottom.y - collision_box.left_top.y)
|
|
|
|
if direction == defines.direction.east or direction == defines.direction.west then
|
|
local swap = width
|
|
width = height
|
|
height = swap
|
|
end
|
|
|
|
minX = math.min(minX, math.floor(position.x - width / 2 + 0.5))
|
|
minY = math.min(minY, math.floor(position.y - height / 2 + 0.5))
|
|
maxX = math.max(maxX, math.floor(position.x + width / 2 + 0.5))
|
|
maxY = math.max(maxY, math.floor(position.y + height / 2 + 0.5))
|
|
end
|
|
|
|
local blueprint_width = maxX - minX
|
|
local blueprint_height = maxY - minY
|
|
|
|
-- then, calculate the "align" so that entity pos + aligh = real position
|
|
local alignX = math.floor(cursor_position.x - blueprint_width / 2 + 0.5) - minX
|
|
local alignY = math.floor(cursor_position.y - blueprint_height / 2 + 0.5) - minY
|
|
|
|
-- finally, add align to entity positions
|
|
local final_entities = {}
|
|
for _,entity in pairs(rotated_entities) do
|
|
if game.entity_prototypes[entity.name].module_inventory_size then
|
|
local modules = {}
|
|
for name,count in pairs(entity.items or {}) do
|
|
if game.item_prototypes[name].type == "module" then
|
|
for _i=1,count,1 do
|
|
table.insert(modules, {
|
|
valid_for_read = true,
|
|
name = name
|
|
})
|
|
end
|
|
end
|
|
end
|
|
|
|
table.insert(final_entities, {
|
|
name = entity.name,
|
|
position = {
|
|
x = entity.position.x + alignX,
|
|
y = entity.position.y + alignY,
|
|
},
|
|
direction = entity.direction,
|
|
modules = modules
|
|
})
|
|
end
|
|
end
|
|
|
|
return final_entities
|
|
end
|