The result after a few iterations looks like this:
I'm only adding water tiles to the table I'm passing to set_tiles() but land is appearing instead. In watching my script, water creeps outward but land also creeps inward.
Code: Select all
WATER_THRESHOLD = 5000
RAY_DISTANCE = 500
function runOnce()
if not global.lakes then
-- These are threshhold tiles.
global.shore = {}
updateLakes()
global.deserts = {}
updateDeserts()
end
end
function waterWorld(event)
if not global.lakes then
runOnce()
end
-- Run once every 5 minutes.
--if event.tick % (60 * 60 * 5) == 0 then
if event.tick % (120) == 0 then
local retries = 0
local pollution = getPollution()
--For minutes * pollution / WATER_THRESHHOLD, create a new water tile.
local tides = {}
for i = 1, pollution / WATER_THRESHOLD, 1 do
local shore = findShore()
if shore and shore.valid then
if checkTile(shore) then -- Is tile still valid? Check if a wall was built or landfill added.
table.insert(tides, {name = "water", position = {shore.position.x, shore.position.y}})
else
i = i-1 --Try again.
retries = retries + 1
end
if retries >= 10 then
game.print("Global Warming: Not enough tiles found to convert.")
return
end
end
end
-- Set tiles to water and add them to the list of candidates
-- TODO: look for anything that can die()
if #tides > 0 then
game.surfaces[1].set_tiles(tides)
for i, tide in pairs(tides) do
local tile = game.surfaces[1].get_tile(tide.position[1], tide.position[2])
-- table.insert(global.shore, tile)
game.print("Converted " .. #tides .. " tiles.")
end
end
end
end
function desertification()
return
end
function getPollution()
-- Iterate over all chunks and sum pollution.
--if event.tick % (60 * 60 *5+ 1) == 0 then
local pollution = 0
-- local surface = game.surfaces[1]
for chunk in game.surfaces[1].get_chunks() do
pollution = pollution + game.surfaces[1].get_pollution({chunk.x, chunk.y})
end
return pollution
--end
end
function findShore()
--Pick a random point and a random direction and travel for RAY_DISTANCE units checking for a transition from water_tile to ground_tile or vice versa.
local chunks = game.surfaces[1].get_chunks()
for n = 1, 20, 1 do --Make 20 attempts
--local chunk = chunks[math.random(1,#chunks)]
local chunk = {}
chunk.x = math.random(-50,50)
chunk.y = math.random(-50,50)
local tile = game.surfaces[1].get_tile(chunk.x + math.random(-15,15), chunk.y + math.random(-15,15))
if not tile then
game.print("Global Warming: Tile not valid.")
return nil
end
if not tile.valid then
game.print("Global Warming: Tile not valid.")
return nil
end
local dx = 0
local dy = 0
local direction = math.random(1, 4)
if direction == 1 then
dy = -1
end
if direction == 2 then
dx = 1
end
if direction == 3 then
dy = 1
end
if direction == 4 then
dx = -1
end
for i = 0, RAY_DISTANCE, 1 do
local tileNext = game.surfaces[1].get_tile(tile.position.x + dx, tile.position.y + dy)
if checkTile(tileNext, direction) then
return tileNext
else
if tileNext and tileNext.valid then
tile = tileNext
else
return nil
end
end
end
end
game.print("GlobalWarming: Failed to find a valid lake.")
return nil
end
function updateLakes()
-- Changing to a raycasting method
return
-- Iterate over entire map
-- Create an array of likely candidates.
-- Let's do this the expensive way and see what happens!
-- for chunk in game.surfaces[1].get_chunks() do
-- -- Chunk size assumed to be 32
-- local candidates = {}
-- for xx = -15, 16, 1 do
-- local breakloop = false
-- for yy = -15, 16, 1 do
-- local tile = game.surfaces[1].get_tile(chunk.x + xx, chunk.y + yy)
-- if checkTile(tile) then
-- table.insert(global.shore, tile)
-- end
-- -- if breakloop then
-- -- break
-- -- end
-- end
-- end
-- end
end
function updateDeserts()
return
end
function checkChunk(area)
return -- Changed to a raycasting method
-- local tiles = game.surfaces[1].find_entities_filtered{area = area, type = "tile"}
-- for i, tile in pairs(tiles) do
-- if checkTile(tile) then
-- table.insert(global.shore, tile)
-- end
-- end
end
--Check tile to see if it's a ground tile next to water with no wall on it. If so, return true
function checkTile(tile, dir)
if tile and tile.valid then
if tile.collides_with("ground-tile") then
if not checkWall(tile) then
local neigh
-- north
neigh = game.surfaces[1].get_tile(tile.position.x, tile.position.y -1)
if neigh and neigh.valid and neigh.collides_with("water-tile") then
return true
end
-- east
neigh = game.surfaces[1].get_tile(tile.position.x+1, tile.position.y )
if neigh and neigh.valid and neigh.collides_with("water-tile") then
return true
end
-- south
neigh = game.surfaces[1].get_tile(tile.position.x, tile.position.y +1)
if neigh and neigh.valid and neigh.collides_with("water-tile") then
return true
end
-- west
neigh = game.surfaces[1].get_tile(tile.position.x-1, tile.position.y)
if neigh and neigh.valid and neigh.collides_with("water-tile") then
return true
end
end
-- Still here? Not a candidate
end
end
return false
end
function checkWall(tile)
local walls = game.surfaces[1].find_entities_filtered{area = {{tile.position.x-0.49, tile.position.y-0.49}, {tile.position.x+0.49, tile.position.y+0.49}}, type = "wall"}
if #walls == 0 then
return false
else
return true
end
end
script.on_init(function()
runOnce()
end)
script.on_event(defines.events.on_tick, function(event)
waterWorld(event)
desertification(event)
end)
script.on_event(defines.events.on_chunk_generated, function(event)
checkChunk(event.area)
end)