local Public = {} local Functions = require 'maps.biter_battles_v2.functions' local bb_config = require 'maps.biter_battles_v2.config' local table_remove = table.remove local table_insert = table.insert local direction_translation = { [0] = 4, [1] = 5, [2] = 6, [3] = 7, [4] = 0, [5] = 1, [6] = 2, [7] = 3 } local cliff_orientation_translation = { ['east-to-none'] = 'west-to-none', ['east-to-north'] = 'west-to-south', ['east-to-south'] = 'west-to-north', ['east-to-west'] = 'west-to-east', ['north-to-east'] = 'south-to-west', ['north-to-none'] = 'south-to-none', ['north-to-south'] = 'south-to-north', ['north-to-west'] = 'south-to-east', ['south-to-east'] = 'north-to-west', ['south-to-none'] = 'north-to-none', ['south-to-north'] = 'north-to-south', ['south-to-west'] = 'north-to-east', ['west-to-east'] = 'east-to-west', ['west-to-none'] = 'east-to-none', ['west-to-north'] = 'east-to-south', ['west-to-south'] = 'east-to-north', ['none-to-east'] = 'none-to-west', ['none-to-north'] = 'none-to-south', ['none-to-south'] = 'none-to-north', ['none-to-west'] = 'none-to-east' } local entity_copy_functions = { ['tree'] = function(surface, entity, target_position) if not surface.can_place_entity({name = entity.name, position = target_position}) then return end entity.clone({position = target_position, surface = surface, force = 'neutral'}) end, ['simple-entity'] = function(surface, entity, target_position) local mirror_entity = {name = entity.name, position = target_position, direction = direction_translation[entity.direction]} if not surface.can_place_entity(mirror_entity) then return end local mirror_entity2 = surface.create_entity(mirror_entity) mirror_entity2.graphics_variation = entity.graphics_variation end, ['cliff'] = function(surface, entity, target_position) local mirror_entity = {name = entity.name, position = target_position, cliff_orientation = cliff_orientation_translation[entity.cliff_orientation]} if not surface.can_place_entity(mirror_entity) then return end surface.create_entity(mirror_entity) return end, ['resource'] = function(surface, entity, target_position) surface.create_entity({name = entity.name, position = target_position, amount = entity.amount}) end, ['corpse'] = function(surface, entity, target_position) surface.create_entity({name = entity.name, position = target_position}) end, ['unit-spawner'] = function(surface, entity, target_position, force_name) local mirror_entity = {name = entity.name, position = target_position, direction = direction_translation[entity.direction], force = force_name .. '_biters'} if not surface.can_place_entity(mirror_entity) then return end table_insert(global.unit_spawners[force_name .. '_biters'], surface.create_entity(mirror_entity)) end, ['turret'] = function(surface, entity, target_position, force_name) local mirror_entity = {name = entity.name, position = target_position, direction = direction_translation[entity.direction], force = force_name .. '_biters'} if not surface.can_place_entity(mirror_entity) then return end surface.create_entity(mirror_entity) end, ['rocket-silo'] = function(surface, entity, target_position, force_name) if surface.count_entities_filtered({name = 'rocket-silo', area = {{target_position.x - 8, target_position.y - 8}, {target_position.x + 8, target_position.y + 8}}}) > 0 then return end global.rocket_silo[force_name] = surface.create_entity({name = entity.name, position = target_position, direction = direction_translation[entity.direction], force = force_name}) global.rocket_silo[force_name].minable = false Functions.add_target_entity(global.rocket_silo[force_name]) end, ['ammo-turret'] = function(surface, entity, target_position, force_name) local direction = 0 if force_name == 'south' then direction = 4 end local mirror_entity = {name = entity.name, position = target_position, force = force_name, direction = direction} if not surface.can_place_entity(mirror_entity) then return end local e = surface.create_entity(mirror_entity) Functions.add_target_entity(e) local inventory = entity.get_inventory(defines.inventory.turret_ammo) if inventory.is_empty() then return end for name, count in pairs(inventory.get_contents()) do e.insert({name = name, count = count}) end end, ['wall'] = function(surface, entity, target_position, force_name) local e = entity.clone({position = target_position, surface = surface, force = force_name}) e.active = true end, ['container'] = function(surface, entity, target_position, force_name) local e = entity.clone({position = target_position, surface = surface, force = force_name}) e.active = true end, ['fish'] = function(surface, entity, target_position) local mirror_entity = {name = entity.name, position = target_position} if not surface.can_place_entity(mirror_entity) then return end surface.create_entity(mirror_entity) end } local function process_entity(surface, entity, force_name) if not entity.valid then return end if not entity_copy_functions[entity.type] then return end local match_mirror = bb_config.match_mirror local target_position if force_name == 'north' then target_position = entity.position else if match_mirror then target_position = {x = entity.position.x, y = entity.position.y * -1} else target_position = {x = entity.position.x * -1, y = entity.position.y * -1} end end entity_copy_functions[entity.type](surface, entity, target_position, force_name) end local function copy_chunk(chunk) local target_surface = game.surfaces.biter_battles local source_surface = game.surfaces.bb_source local source_chunk_position = {chunk[1][1], chunk[1][2]} local source_left_top = {x = source_chunk_position[1] * 32, y = source_chunk_position[2] * 32} local source_area = {{source_left_top.x, source_left_top.y}, {source_left_top.x + 32, source_left_top.y + 32}} local target_chunk_position = chunk[1] local target_left_top = {x = target_chunk_position[1] * 32, y = target_chunk_position[2] * 32} local target_area = {{target_left_top.x, target_left_top.y}, {target_left_top.x + 32, target_left_top.y + 32}} if not source_surface.is_chunk_generated(source_chunk_position) then source_surface.request_to_generate_chunks({x = source_left_top.x + 16, y = source_left_top.y + 16}, 0) return end local match_mirror = bb_config.match_mirror if chunk[2] == 1 then source_surface.clone_area( { source_area = source_area, destination_area = target_area, destination_surface = target_surface, --destination_force = …, clone_tiles = true, clone_entities = false, clone_decoratives = false, clear_destination_entities = false, clear_destination_decoratives = false, expand_map = false } ) chunk[2] = chunk[2] + 1 return end if chunk[2] == 2 then for _, entity in pairs(source_surface.find_entities_filtered({area = source_area})) do process_entity(target_surface, entity, 'north') end chunk[2] = chunk[2] + 1 return end local decoratives = {} if match_mirror then for k, decorative in pairs(source_surface.find_decoratives_filtered {area = source_area}) do decoratives[k] = {name = decorative.decorative.name, position = {decorative.position.x, decorative.position.y}, amount = decorative.amount} end else for k, decorative in pairs(source_surface.find_decoratives_filtered {area = source_area}) do decoratives[k] = {name = decorative.decorative.name, position = {(decorative.position.x * -1) - 1, (decorative.position.y * -1) - 1}, amount = decorative.amount} end end target_surface.create_decoratives({check_collision = false, decoratives = decoratives}) return true end local function mirror_chunk(chunk) local target_surface = game.surfaces.biter_battles local match_mirror = bb_config.match_mirror local source_surface = game.surfaces.bb_source local source_chunk_position if match_mirror then source_chunk_position = {chunk[1][1], chunk[1][2] * -1 - 1} else source_chunk_position = {chunk[1][1] * -1 - 1, chunk[1][2] * -1 - 1} end local source_left_top = {x = source_chunk_position[1] * 32, y = source_chunk_position[2] * 32} local source_area = {{source_left_top.x, source_left_top.y}, {source_left_top.x + 32, source_left_top.y + 32}} if not source_surface.is_chunk_generated(source_chunk_position) then source_surface.request_to_generate_chunks({x = source_left_top.x + 16, y = source_left_top.y + 16}, 0) return end if chunk[2] == 1 then local tiles = {} if match_mirror then for k, tile in pairs(source_surface.find_tiles_filtered({area = source_area})) do tiles[k] = {name = tile.name, position = {tile.position.x, tile.position.y * -1 - 1}} end else for k, tile in pairs(source_surface.find_tiles_filtered({area = source_area})) do tiles[k] = {name = tile.name, position = {tile.position.x * -1 - 1, tile.position.y * -1 - 1}} end end target_surface.set_tiles(tiles, true) chunk[2] = chunk[2] + 1 return end if chunk[2] == 2 then for _, entity in pairs(source_surface.find_entities_filtered({area = source_area})) do process_entity(target_surface, entity, 'south') end chunk[2] = chunk[2] + 1 return end local decoratives = {} for k, decorative in pairs(source_surface.find_decoratives_filtered {area = source_area}) do decoratives[k] = {name = decorative.decorative.name, position = {decorative.position.x, decorative.position.y * -1}, amount = decorative.amount} end target_surface.create_decoratives({check_collision = false, decoratives = decoratives}) return true end local function reveal_chunk(chunk) local surface = game.surfaces.biter_battles local chunk_position = chunk[1] for _, force_name in pairs({'north', 'south'}) do local force = game.forces[force_name] if force.is_chunk_charted(surface, chunk_position) then force.chart(surface, {{chunk_position[1] * 32, chunk_position[2] * 32}, {chunk_position[1] * 32 + 31, chunk_position[2] * 32 + 31}}) end end end function Public.add_chunk(event) local surface = event.surface if surface.name ~= 'biter_battles' then return end local left_top = event.area.left_top local terrain_gen = global.terrain_gen if left_top.y < 0 then terrain_gen.size_of_chunk_copy = terrain_gen.size_of_chunk_copy + 1 terrain_gen.chunk_copy[terrain_gen.size_of_chunk_copy] = {{left_top.x / 32, left_top.y / 32}, 1} else terrain_gen.size_of_chunk_mirror = terrain_gen.size_of_chunk_mirror + 1 terrain_gen.chunk_mirror[terrain_gen.size_of_chunk_mirror] = {{left_top.x / 32, left_top.y / 32}, 1} end end local function clear_source_surface(terrain_gen) if terrain_gen.counter % 1024 == 1023 then terrain_gen.counter = terrain_gen.counter + 1 local surface = game.surfaces.bb_source local c = 0 for chunk in surface.get_chunks() do surface.delete_chunk({chunk.x, chunk.y}) c = c + 1 end print('Deleted ' .. c .. ' source surface chunks.') end end local function north_work() local terrain_gen = global.terrain_gen --luacheck: ignore 512 for k, chunk in pairs(terrain_gen.chunk_copy) do if copy_chunk(chunk) then reveal_chunk(chunk) table_remove(terrain_gen.chunk_copy, k) terrain_gen.size_of_chunk_copy = terrain_gen.size_of_chunk_copy - 1 terrain_gen.counter = terrain_gen.counter + 1 end break end clear_source_surface(terrain_gen) end local function south_work() local terrain_gen = global.terrain_gen --luacheck: ignore 512 for k, chunk in pairs(terrain_gen.chunk_mirror) do if mirror_chunk(chunk) then reveal_chunk(chunk) table_remove(terrain_gen.chunk_mirror, k) terrain_gen.size_of_chunk_mirror = terrain_gen.size_of_chunk_mirror - 1 terrain_gen.counter = terrain_gen.counter + 1 end break end clear_source_surface(terrain_gen) end local works = { [1] = north_work, [2] = south_work } function Public.ticking_work() local tick = game.ticks_played if tick < 4 then return end local work = works[tick % 2 + 1] if global.server_restart_timer then return end work() end return Public