1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2024-12-14 10:23:17 +02:00
FactorioScenarioMultiplayer.../regrowth_map.lua

253 lines
9.0 KiB
Lua

-- 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.
REGROWTH_TIMEOUT_TICKS = 60*20 -- 1 hour
-- Init globals and set player join area to be off limits.
function OarcRegrowthInit()
global.chunk_regrow = {}
global.chunk_regrow.map = {}
global.chunk_regrow.removal_list = {}
global.chunk_regrow.rso_region_roll_counter = 0
global.chunk_regrow.player_refresh_index = 1
global.chunk_regrow.min_x = 0
global.chunk_regrow.max_x = 0
global.chunk_regrow.x_index = 0
global.chunk_regrow.min_y = 0
global.chunk_regrow.max_y = 0
global.chunk_regrow.y_index = 0
OarcRegrowthOffLimits({x=0,y=0}, 15)
end
function GetChunkTopLeft(pos)
return {x=pos.x-(pos.x % 32), y=pos.y-(pos.y % 32)}
end
function GetChunkFromPos(pos)
return {x=pos.x-(pos.x % 32), y=pos.y-(pos.y % 32)}
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(pos)
-- If this is the first chunk in that row:
if (global.chunk_regrow.map[pos.x] == nil) then
global.chunk_regrow.map[pos.x] = {}
end
-- Confirm the chunk doesn't already have a value set:
if (global.chunk_regrow.map[pos.x][pos.y] == nil) then
global.chunk_regrow.map[pos.x][pos.y] = game.tick
end
-- Store min/max values for x/y dimensions:
if (pos.x < global.chunk_regrow.min_x) then
global.chunk_regrow.min_x = pos.x
end
if (pos.x > global.chunk_regrow.max_x) then
global.chunk_regrow.max_x = pos.x
end
if (pos.y < global.chunk_regrow.min_y) then
global.chunk_regrow.min_y = pos.y
end
if (pos.y > global.chunk_regrow.max_y) then
global.chunk_regrow.max_y = pos.y
end
end
-- Mark an area for immediate forced removal
function OarcRegrowthMarkForRemoval(pos, chunk_radius)
local c_pos = GetChunkTopLeft(pos)
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] = nil
table.insert(global.chunk_regrow.removal_list, {x=x,y=y})
end
end
end
-- Marks a chunk a position that won't ever be deleted.
function OarcRegrowthOffLimitsChunk(pos)
local c_pos = GetChunkTopLeft(pos)
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.y] = {}
end
global.chunk_regrow.map[c_pos.x][c_pos.y] = -1
end
-- Marks a safe area around a position that won't ever be deleted.
function OarcRegrowthOffLimits(pos, chunk_radius)
local c_pos = GetChunkTopLeft(pos)
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 a chunk containing position
function OarcRegrowthRefreshChunk(pos, bonus_time)
local c_pos = GetChunkTopLeft(pos)
if (global.chunk_regrow.map[c_pos.x] == nil) then
global.chunk_regrow.map[c_pos.y] = {}
end
if (global.chunk_regrow.map[c_pos.x][c_pos.y] ~= -1) then
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick + bonus_time
end
end
-- Refreshes timers on all chunks around a certain area
function OarcRegrowthRefreshArea(pos, chunk_radius, bonus_time)
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
if (global.chunk_regrow.map[x][y] ~= -1) then
global.chunk_regrow.map[x][y] = game.tick + bonus_time
end
end
end
end
-- Refreshes timers on all chunks near an ACTIVE radar
function OarcRegrowthSectorScan(event)
OarcRegrowthRefreshArea(event.radar.position, 4, 0)
OarcRegrowthRefreshChunk(chunk_position)
end
-- Refresh all chunks near a single player. Cyles through all connected players.
function OarcRegrowthRefreshPlayerArea()
global.chunk_regrow.player_refresh_index = global.chunk_regrow.player_refresh_index + 1
if (global.chunk_regrow.player_refresh_index > #game.connected_players) then
global.chunk_regrow.player_refresh_index = 1
end
if (game.connected_players[global.chunk_regrow.player_refresh_index]) then
OarcRegrowthRefreshArea(game.connected_players[global.chunk_regrow.player_refresh_index].position, 4, 0)
end
end
-- Check each chunk in the 2d array for a timeout value
function OarcRegrowthCheckArray()
-- Increment X
if (global.chunk_regrow.x_index > global.chunk_regrow.max_x) then
global.chunk_regrow.x_index = global.chunk_regrow.min_x
-- Increment Y
if (global.chunk_regrow.y_index > global.chunk_regrow.max_y) then
global.chunk_regrow.y_index = global.chunk_regrow.min_y
else
global.chunk_regrow.y_index = global.chunk_regrow.y_index + 32
end
else
global.chunk_regrow.x_index = global.chunk_regrow.x_index + 32
end
-- Check row exists, otherwise make one.
if (global.chunk_regrow.map[global.chunk_regrow.x_index] == nil) then
global.chunk_regrow.map[global.chunk_regrow.x_index] = {}
end
-- If the chunk has timed out, add it to the removal list
local c_timer = global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index]
if ((c_timer ~= nil) and (c_timer ~= -1) and ((c_timer+REGROWTH_TIMEOUT_TICKS) < game.tick)) then
-- Check chunk actually exists
if (game.surfaces[GAME_SURFACE_NAME].is_chunk_generated({x=(global.chunk_regrow.x_index/32),
y=(global.chunk_regrow.y_index/32)})) then
table.insert(global.chunk_regrow.removal_list, {x=global.chunk_regrow.x_index,
y=global.chunk_regrow.y_index})
global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index] = nil
end
end
end
-- Remove entries from the removal list
function OarcRegrowthRemoveChunk()
-- Next chunk to remove
if (#global.chunk_regrow.removal_list > 0) then
local c_pos = table.remove(global.chunk_regrow.removal_list)
local c_timer = global.chunk_regrow.map[c_pos.x][c_pos.y]
-- Confirm chunk is still expired
if (c_timer == nil) then
-- Check for pollution
if (game.surfaces[GAME_SURFACE_NAME].get_pollution(c_pos) > 0) then
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick
-- Else delete the chunk
else
game.surfaces[GAME_SURFACE_NAME].delete_chunk({c_pos.x/32,c_pos.y/32})
global.chunk_regrow.map[c_pos.x][c_pos.y] = nil
-- DebugPrint("Deleting Chunk: X="..c_pos.x..",Y="..c_pos.y)
end
else
-- DebugPrint("Chunk no longer expired: X="..c_pos.x..",Y="..c_pos.y)
end
end
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)
-- Every half a second, refresh all chunks near a single player
-- Cyles through all players. Tick is offset by 2
if ((game.tick % (30)) == 2) then
OarcRegrowthRefreshPlayerArea()
end
-- Every tick, check a few points in the 2d array
for i=1,3 do
OarcRegrowthCheckArray()
end
-- Every 30 ticks, remove a chunk from the removal list.
if ((game.tick % 30) == 15) then
OarcRegrowthRemoveChunk()
end
end