map_gen/shared/ent_functions.lua
-- luacheck: ignore
-- This file contains many linting warnings and needs an overhaul
local RS = require 'map_gen.shared.redmew_surface'
--allows any gen to access these functions

local Public = {}

function Public.place_entities(surface, entity_list)
    local directions = {defines.direction.north, defines.direction.east, defines.direction.south, defines.direction.west}
    for _, entity in pairs(entity_list) do
        local r = math.random(1,entity.chance)
        if r == 1 then
            if not entity.force then entity.force = "player" end
            local r = math.random(1,4)
            if surface.can_place_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force} then
                local e = surface.create_entity {name=entity.name, position=entity.pos, direction=directions[r], force=entity.force}
                if entity.health then
                    if entity.health == "low" then e.health = ((e.health / 1000) * math.random(33,330)) end
                    if entity.health == "medium" then e.health = ((e.health / 1000) * math.random(333,666)) end
                    if entity.health == "high" then e.health = ((e.health / 1000) * math.random(666,999)) end
                    if entity.health == "random" then e.health = ((e.health / 1000) * math.random(1,1000)) end
                end
                return true, e
            end
        end
    end
    return false
end

function Public.auto_place_entity_around_target(entity, scan_radius, mode, density, surface)
    local x = entity.pos.x
    local y = entity.pos.y
    if not surface then surface = RS.get_surface() end
    if not scan_radius then scan_radius = 6 end
    if not entity then return end
    if not mode then mode = "ball" end
    if not density then density = 1 end

    if surface.can_place_entity {name=entity.name, position={x,y}} then
        local e = surface.create_entity {name=entity.name, position={x,y}}
        return true, e
    end

    local i = 2
    local r = 1

    if mode == "ball" then
        if math.random(1,2) == 1 then
            density = density * -1
        end
        r = math.random(1,4)
    end
    if mode == "line" then
        density = 1
        r = math.random(1,4)
    end
    if mode == "line_down" then
        density = density * -1
        r = math.random(1,4)
    end
    if mode == "line_up" then
        density = 1
        r = math.random(1,4)
    end
    if mode == "block" then
        r = 1
        density = 1
    end

    if r == 1 then
        --start placing at -1,-1
        while i <= scan_radius do
            y = y - density
            x = x - density
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                x = x + density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                y = y + density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                x = x - density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                y = y - density
            end
            i = i + 2
        end
    end

    if r == 2 then
        --start placing at 0,-1
        while i <= scan_radius do
            y = y - density
            x = x - density
            for a = 1, i, 1 do
                x = x + density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                y = y + density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                x = x - density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                y = y - density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            i = i + 2
        end
    end

    if r == 3 then
        --start placing at 1,-1
        while i <= scan_radius do
            y = y - density
            x = x + density
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                y = y + density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                x = x - density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                y = y - density
            end
            for a = 1, i, 1 do
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
                x = x + density
            end
            i = i + 2
        end
    end

    if r == 4 then
        --start placing at 1,0
        while i <= scan_radius do
            y = y - density
            x = x + density
            for a = 1, i, 1 do
                y = y + density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                x = x - density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                y = y - density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            for a = 1, i, 1 do
                x = x + density
                if surface.can_place_entity {name=entity.name, position={x,y}} then
                    local e = surface.create_entity {name=entity.name, position={x,y}}
                    return true, e
                end
            end
            i = i + 2
        end
    end

    return false
end

function Public.create_entitie_cluster(name, pos, amount)
    local surface = RS.get_surface()
    local entity = {}
    entity.pos = pos
    entity.name = name
    local mode = "ball"

    for i = 1, amount, 1 do
        local b, e = auto_place_entity_around_target(entity, 30, mode)
        if b == true then
            if 1 == math.random(1,40) then
                entity.pos = e.position
            end
            if e.type == "resource" then
                e.amount = math.random(500,1500)
            end
        end
    end
    return b, e
end

function Public.create_rock_cluster(pos, amount)
    if not pos then return false end
    if amount == nil then amount = 7 end
    local scan_radius = amount * 2
    local mode = "line_down"
    if math.random(1,2) == 1 then mode = "line_up" end
    local entity = {}
    entity.pos = pos
    for i = 1, amount, 1 do
        if 1 == math.random(1,3) then
            entity.name = "big-rock"
        else
            entity.name = "big-rock"
        end
        local b, e = auto_place_entity_around_target(entity, scan_radius, mode)
        if b == true then
            if 1 ~= math.random(1,20) then
                entity.pos = e.position
            end
        end
    end
    return b, e
end

function Public.create_tree_cluster(pos, amount)
    if not pos then return false end
    if amount == nil then amount = 7 end
    local scan_radius = amount * 2
    --local mode = "line_down"
    --if math.random(1,2) == 1 then mode = "line_up" end
    local mode = "ball"
    local entity = {}
    entity.pos = pos
    for i = 1, amount, 1 do
        entity.name = "tree-06"
        local density = 2
        if 1 == math.random(1,20) then entity.name = "tree-07" end
        if 1 == math.random(1,70) then entity.name = "tree-09" end
        if 1 == math.random(1,10) then entity.name = "tree-04" end
        if 1 == math.random(1,9) then density = 1 end
        if 1 == math.random(1,3) then density = 3 end
        if 1 == math.random(1,3) then density = 4 end

        local b, e = auto_place_entity_around_target(entity, scan_radius, mode, density)
        if b == true then
            if 1 == math.random(1,3) then
                entity.pos = e.position
            end
        end
    end
    return b, e
end

function Public.find_tile_placement_spot_around_target_position(tilename, position, mode, density)
    local x = position.x
    local y = position.y
    if not surface then surface = RS.get_surface() end
    local scan_radius = 50
    if not tilename then return end
    if not mode then mode = "ball" end
    if not density then density = 1 end
    local cluster_tiles = {}
    local auto_correct = false

    local scanned_tile = surface.get_tile(x,y)
    if scanned_tile.name ~= tilename then
        table.insert(cluster_tiles, {name = tilename, position = {x,y}})
        surface.set_tiles(cluster_tiles,false)
        return true, x, y
    end

    local i = 2
    local r = 1

    if mode == "ball" then
        if math.random(1,2) == 1 then
            density = density * -1
        end
        r = math.random(1,4)
    end
    if mode == "line" then
        density = 1
        r = math.random(1,4)
    end
    if mode == "line_down" then
        density = density * -1
        r = math.random(1,4)
    end
    if mode == "line_up" then
        density = 1
        r = math.random(1,4)
    end
    if mode == "block" then
        r = 1
        density = 1
    end

    if r == 1 then
        --start placing at -1,-1
        while i <= scan_radius do
            y = y - density
            x = x - density
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                x = x + density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                y = y + density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                x = x - density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                y = y - density
            end
            i = i + 2
        end
    end

    if r == 2 then
        --start placing at 0,-1
        while i <= scan_radius do
            y = y - density
            x = x - density
            for a = 1, i, 1 do
                x = x + density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                y = y + density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                x = x - density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                y = y - density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            i = i + 2
        end
    end

    if r == 3 then
        --start placing at 1,-1
        while i <= scan_radius do
            y = y - density
            x = x + density
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                y = y + density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                x = x - density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                y = y - density
            end
            for a = 1, i, 1 do
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
                x = x + density
            end
            i = i + 2
        end
    end

    if r == 4 then
        --start placing at 1,0
        while i <= scan_radius do
            y = y - density
            x = x + density
            for a = 1, i, 1 do
                y = y + density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                x = x - density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                y = y - density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            for a = 1, i, 1 do
                x = x + density
                local scanned_tile = surface.get_tile(x,y)
                if scanned_tile.name ~= tilename then
                    table.insert(cluster_tiles, {name = tilename, position = {x,y}})
                    surface.set_tiles(cluster_tiles,auto_correct)
                    return true, x, y
                end
            end
            i = i + 2
        end
    end
    return false
end

function Public.create_tile_cluster(tilename,position,amount)
    local mode = "ball"
    local cluster_tiles = {}
    local surface = RS.get_surface()
    local pos = position
    local x = pos.x
    local y = pos.y
    for i = 1, amount, 1 do
        local b,x,y = Public.find_tile_placement_spot_around_target_position(tilename, pos, mode)
        if b == true then
            if 1 == math.random(1,2) then
                pos.x = x
                pos.y = y
            end
        end
        if b == false then return false,x,y end
        if i >= amount then return true,x,y end
    end
end

return Public
