2017-07-29 00:02:45 +02:00
|
|
|
-- regrowth_map.lua
|
|
|
|
-- July 2017
|
|
|
|
--
|
|
|
|
-- Code tracks all chunks generated and allows for deleting inactive chunks
|
|
|
|
-- Relies on some changes to RSO to provide random resource locations the next
|
|
|
|
-- time the land is regenerated.
|
|
|
|
--
|
|
|
|
-- Basic rules of regrowth:
|
|
|
|
-- 1. Area around player is safe for quite a large distance.
|
|
|
|
-- 2. Rocket silo won't be deleted. - PERMANENT
|
|
|
|
-- 3. Chunks with pollution won't be deleted.
|
|
|
|
-- 4. Chunks with railways won't be deleted.
|
|
|
|
-- 5. Anything within radar range won't be deleted, but radar MUST be active.
|
|
|
|
-- -- This works by refreshing all chunk timers within radar range using
|
|
|
|
-- the on_sector_scanned event.
|
|
|
|
-- 6. Chunks timeout after 1 hour-ish, configurable
|
|
|
|
-- 7. For now, oarc spawns are deletion safe as well, but only immediate area.
|
|
|
|
|
|
|
|
|
2017-07-29 00:06:52 +02:00
|
|
|
REGROWTH_TIMEOUT_TICKS = 60*60*60 -- 1 hour
|
2017-07-29 00:02:45 +02:00
|
|
|
|
|
|
|
-- Init globals and set player join area to be off limits.
|
|
|
|
function OarcRegrowthInit()
|
|
|
|
global.chunk_regrow = {}
|
|
|
|
global.chunk_regrow.map = {}
|
|
|
|
global.chunk_regrow.list = {}
|
|
|
|
global.chunk_regrow.num_chunks = 0
|
|
|
|
global.chunk_regrow.chunk_index = 1
|
|
|
|
global.chunk_regrow.rso_region_roll_counter = 0
|
|
|
|
|
|
|
|
OarcRegrowthOffLimits({x=0,y=0}, 15)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Adds new chunks to the global table to track them.
|
|
|
|
-- This should always be called first in the chunk generate sequence
|
|
|
|
-- (Compared to other RSO & Oarc related functions...)
|
|
|
|
function OarcRegrowthChunkGenerate(event)
|
|
|
|
|
|
|
|
local x = event.area.left_top.x
|
|
|
|
local y = event.area.left_top.y
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
|
|
|
|
|
|
|
-- There are some chunks that might already be added to the table
|
|
|
|
-- before a chunk generate event happens for them.
|
|
|
|
if (global.chunk_regrow.map[x][y] == nil) then
|
|
|
|
global.chunk_regrow.map[x][y] = game.tick
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Always add new chunks to the list, they will be removed later
|
|
|
|
-- if they are offlimits.
|
|
|
|
table.insert(global.chunk_regrow.list, event.area.left_top)
|
|
|
|
global.chunk_regrow.num_chunks = global.chunk_regrow.num_chunks + 1
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Marks a safe area around around a position that won't ever be deleted.
|
|
|
|
function OarcRegrowthOffLimits(pos, chunk_radius)
|
|
|
|
local c_pos = {x=pos.x-(pos.x % 32),
|
|
|
|
y=pos.y-(pos.y % 32)}
|
|
|
|
for i=-chunk_radius,chunk_radius do
|
|
|
|
for k=-chunk_radius,chunk_radius do
|
|
|
|
local x = c_pos.x+(i*32)
|
|
|
|
local y = c_pos.y+(k*32)
|
|
|
|
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
|
|
|
global.chunk_regrow.map[x][y] = -1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Refreshes timers on all chunks around a certain area
|
|
|
|
function OarcRegrowthRefreshArea(pos, chunk_radius)
|
|
|
|
local c_pos = {x=pos.x-(pos.x % 32),
|
|
|
|
y=pos.y-(pos.y % 32)}
|
|
|
|
for i=-chunk_radius,chunk_radius do
|
|
|
|
for k=-chunk_radius,chunk_radius do
|
|
|
|
local x = c_pos.x+(i*32)
|
|
|
|
local y = c_pos.y+(k*32)
|
|
|
|
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
|
|
|
global.chunk_regrow.map[x][y] = game.tick
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Refreshes timers on all chunks near an ACTIVE radar
|
|
|
|
function OarcRegrowthSectorScan(event)
|
|
|
|
OarcRegrowthRefreshArea(event.radar.position, 17)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- This is the main work function, it checks a single chunk in the list
|
|
|
|
-- per tick. It works according to the rules listed in the header of this
|
|
|
|
-- file.
|
|
|
|
function OarcRegrowthOnTick(event)
|
|
|
|
|
|
|
|
-- We always check of value exists first... Due to the way events work,
|
|
|
|
-- this is a necessary check.
|
|
|
|
if (global.chunk_regrow.list[global.chunk_regrow.chunk_index]) then
|
|
|
|
|
|
|
|
-- Position of left_top of the chunk in the list.
|
|
|
|
local x = global.chunk_regrow.list[global.chunk_regrow.chunk_index].x
|
|
|
|
local y = global.chunk_regrow.list[global.chunk_regrow.chunk_index].y
|
|
|
|
local pos = {x=x,y=y}
|
|
|
|
|
|
|
|
-- Confirm we have a matching chunk in our map array
|
|
|
|
if (global.chunk_regrow.map[x][y] ~= nil) then
|
|
|
|
|
|
|
|
-- Check this chunk is NOT timed out, this should be the most common reason
|
|
|
|
-- to go to the next list item, so I put it first to optimize the logic
|
|
|
|
if ((global.chunk_regrow.map[x][y]+REGROWTH_TIMEOUT_TICKS) > game.tick) then
|
|
|
|
goto GO_NEXT_CHUNK
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Check if this chunk is off limits
|
|
|
|
if (global.chunk_regrow.map[x][y] == -1) then
|
|
|
|
global.chunk_regrow.num_chunks = global.chunk_regrow.num_chunks - 1
|
|
|
|
table.remove(global.chunk_regrow.list, global.chunk_regrow.chunk_index)
|
|
|
|
global.chunk_regrow.chunk_index = global.chunk_regrow.chunk_index - 1
|
|
|
|
goto GO_NEXT_CHUNK
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Check for pollution, refresh timer if found
|
|
|
|
if (game.surfaces[GAME_SURFACE_NAME].get_pollution(pos) > 0) then
|
|
|
|
global.chunk_regrow.map[x][y] = game.tick
|
|
|
|
goto GO_NEXT_CHUNK
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Check for players nearby, don't delete anything near players.
|
|
|
|
-- And refresh the area around them if they happen to be near.
|
|
|
|
local players_found = game.surfaces[GAME_SURFACE_NAME].find_entities_filtered{area = {{x-(32*2), y-(32*2)}, {x+(32*2), y+(32*2)}}, type= "player"}
|
|
|
|
if (next(players_found) ~= nil) then
|
|
|
|
OarcRegrowthRefreshArea(pos, 2)
|
|
|
|
goto GO_NEXT_CHUNK
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Check for railway lines
|
|
|
|
local railway_found = game.surfaces[GAME_SURFACE_NAME].find_entities_filtered{area = {{x-(32*2), y-(32*2)}, {x+(32*2), y+(32*2)}}, name= "railway"}
|
|
|
|
if (next(railway_found) ~= nil) then
|
|
|
|
OarcRegrowthRefreshArea(pos, 2)
|
|
|
|
goto GO_NEXT_CHUNK
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Else, let's see if we can delete the chunk.
|
|
|
|
local chunk_x = x/32
|
|
|
|
local chunk_y = y/32
|
|
|
|
|
|
|
|
-- Only delete chunks near map edges.
|
|
|
|
local ungenerate_chunk_count = 0
|
|
|
|
for i=-1,1 do
|
|
|
|
for k=-1,1 do
|
|
|
|
if (not game.surfaces[GAME_SURFACE_NAME].is_chunk_generated({chunk_x+i,chunk_y+k})) then
|
|
|
|
ungenerate_chunk_count = ungenerate_chunk_count +1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Delete the chunk and remove it from the list.
|
|
|
|
if (ungenerate_chunk_count >= 3) then
|
|
|
|
game.surfaces[GAME_SURFACE_NAME].delete_chunk({chunk_x,chunk_y})
|
|
|
|
global.chunk_regrow.num_chunks = global.chunk_regrow.num_chunks -1
|
|
|
|
table.remove(global.chunk_regrow.list, global.chunk_regrow.chunk_index)
|
|
|
|
global.chunk_regrow.chunk_index = global.chunk_regrow.chunk_index - 1
|
|
|
|
global.chunk_regrow.map[x][y] = nil
|
|
|
|
DebugPrint("Deleting Chunk: X="..x..",Y="..y)
|
|
|
|
end
|
|
|
|
else
|
|
|
|
DebugPrint("No matching map entry: X="..x..",Y="..y)
|
|
|
|
end
|
|
|
|
|
|
|
|
::GO_NEXT_CHUNK::
|
|
|
|
global.chunk_regrow.chunk_index = global.chunk_regrow.chunk_index + 1
|
|
|
|
if (global.chunk_regrow.chunk_index > global.chunk_regrow.num_chunks) then
|
|
|
|
global.chunk_regrow.chunk_index = 1
|
|
|
|
end
|
|
|
|
|
|
|
|
end
|
|
|
|
end
|