2019-01-16 20:44:55 +02:00
|
|
|
local Event = require 'utils.event'
|
|
|
|
local RS = require 'map_gen.shared.redmew_surface'
|
|
|
|
local Global = require 'utils.global'
|
2017-07-30 23:46:15 +02:00
|
|
|
--Author: Hexicube
|
2017-07-30 18:06:33 +02:00
|
|
|
--The size of each individual maze, in cells.
|
2017-07-30 23:46:15 +02:00
|
|
|
local maze_width = 17
|
|
|
|
local maze_height = 17
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
--The size of each cell within a maze, in tiles. This includes the border.
|
|
|
|
--This is also the thickness of passages between mazes.
|
2017-07-30 23:46:15 +02:00
|
|
|
local maze_tile_size = 80
|
2017-07-30 18:06:33 +02:00
|
|
|
--The thickness of cell borders (walls), in tiles.
|
|
|
|
local maze_tile_border = 2
|
|
|
|
--These two values are specifically chosen to only just allow train loops.
|
|
|
|
--If tile size is reduced or border size is increased, players will be forced to use 4-way crossings instead.
|
|
|
|
|
|
|
|
--Number of ore cells per maze, for each type.
|
2017-07-30 21:23:44 +02:00
|
|
|
local iron_ore_count = 8
|
|
|
|
local copper_ore_count = 6
|
|
|
|
local coal_ore_count = 4
|
|
|
|
local stone_ore_count = 2
|
2017-07-30 18:06:33 +02:00
|
|
|
local uranium_ore_count = 1
|
2017-07-30 21:23:44 +02:00
|
|
|
|
2017-07-30 23:46:15 +02:00
|
|
|
local resource_density_factor = 500
|
2017-07-30 21:23:44 +02:00
|
|
|
|
2017-07-30 18:06:33 +02:00
|
|
|
--Warning: Do not exceed the total number of cells in the maze, or it will break!
|
|
|
|
|
|
|
|
--DO NOT TOUCH BELOW THIS LINE--
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local bor = bit32.bor
|
|
|
|
local bxor = bit32.bxor
|
|
|
|
local band = bit32.band
|
|
|
|
local rshift = bit32.rshift
|
|
|
|
|
|
|
|
local global_ore_data = {}
|
|
|
|
local global_maze_data = {}
|
|
|
|
local primitives = {
|
|
|
|
maze_seed = 0,
|
|
|
|
}
|
|
|
|
|
|
|
|
Global.register(
|
|
|
|
{
|
|
|
|
primitives = primitives,
|
|
|
|
global_ore_data = global_ore_data,
|
|
|
|
},
|
|
|
|
function(tbl)
|
|
|
|
primitives = tbl.primitives
|
|
|
|
global_ore_data = tbl.global_ore_data
|
|
|
|
end
|
|
|
|
)
|
|
|
|
|
2017-07-30 18:06:33 +02:00
|
|
|
local function get_random_maze_val(cur_seed)
|
2019-01-16 20:44:55 +02:00
|
|
|
local new_seed = bor(cur_seed + 0x9E3779B9, 0)
|
|
|
|
local return_val = bor(new_seed * 0xBF58476D, 0)
|
|
|
|
return_val = bor(return_val * 0x94D049BB, 0)
|
|
|
|
return new_seed, bor(return_val, 0)
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local last_maze_x, last_maze_y, last_maze
|
2017-07-30 18:06:33 +02:00
|
|
|
local function get_maze(x, y, seed, width, height)
|
2019-01-16 20:44:55 +02:00
|
|
|
if last_maze and last_maze_x == x and last_maze_y == y then
|
|
|
|
return last_maze
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
if not global_maze_data[x] then
|
|
|
|
global_maze_data[x] = {}
|
|
|
|
end
|
|
|
|
if global_maze_data[x][y] then
|
|
|
|
last_maze = global_maze_data[x][y]
|
2017-07-30 18:06:33 +02:00
|
|
|
last_maze_x = x
|
|
|
|
last_maze_y = y
|
|
|
|
return last_maze
|
|
|
|
end
|
|
|
|
|
|
|
|
local maze_data = {}
|
|
|
|
local grid = {}
|
2019-01-16 20:44:55 +02:00
|
|
|
for tx = 1, width do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_data[tx] = {}
|
|
|
|
grid[tx] = {}
|
2019-01-16 20:44:55 +02:00
|
|
|
for ty = 1, height do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_data[tx][ty] = 15
|
|
|
|
grid[tx][ty] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local maze_seed = bxor(bit32.lshift(x, 16) + band(y, 65535), seed)
|
|
|
|
local value
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
local queue = {}
|
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = {0, 0}
|
2019-01-16 20:44:55 +02:00
|
|
|
pos[1] = value % width + 1
|
|
|
|
value = rshift(value, 16)
|
2017-07-30 18:06:33 +02:00
|
|
|
pos[2] = value % height + 1
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
queue[#queue + 1] = {pos[1], pos[2], pos[1] - 1, pos[2]}
|
|
|
|
queue[#queue + 1] = {pos[1], pos[2], pos[1] + 1, pos[2]}
|
|
|
|
queue[#queue + 1] = {pos[1], pos[2], pos[1], pos[2] - 1}
|
|
|
|
queue[#queue + 1] = {pos[1], pos[2], pos[1], pos[2] + 1}
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
while #queue > 0 do
|
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local connection = table.remove(queue, value % #queue + 1)
|
|
|
|
local sx, sy = connection[1], connection[2]
|
|
|
|
local tx, ty = connection[3], connection[4]
|
|
|
|
if tx > 0 and ty > 0 and tx <= width and ty <= height and grid[tx][ty] then
|
|
|
|
local dx, dy = sx - tx, sy - ty
|
|
|
|
local mod_s, mod_t = 3, 3
|
|
|
|
if dy == 1 then
|
|
|
|
mod_s = 1
|
|
|
|
elseif dy == -1 then
|
|
|
|
mod_t = 1
|
|
|
|
elseif dx == 1 then
|
|
|
|
mod_s = 2
|
|
|
|
else
|
|
|
|
mod_t = 2
|
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[sx][sy] = band(maze_data[sx][sy], mod_s)
|
|
|
|
maze_data[tx][ty] = band(maze_data[tx][ty], mod_t)
|
2017-07-30 18:06:33 +02:00
|
|
|
grid[sx][sy] = false
|
|
|
|
grid[tx][ty] = false
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
queue[#queue + 1] = {tx, ty, tx - 1, ty}
|
|
|
|
queue[#queue + 1] = {tx, ty, tx + 1, ty}
|
|
|
|
queue[#queue + 1] = {tx, ty, tx, ty - 1}
|
|
|
|
queue[#queue + 1] = {tx, ty, tx, ty + 1}
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[value % width + 1][1] = band(maze_data[value % width + 1][1], 1)
|
|
|
|
value = rshift(value, 16)
|
|
|
|
maze_data[1][value % height + 1] = band(maze_data[1][value % height + 1], 2)
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[width + 1] = {0, 0}
|
|
|
|
maze_data[width + 1][1] = value % width + 1
|
|
|
|
value = rshift(value, 16)
|
|
|
|
maze_data[width + 1][2] = value % height + 1
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
global_maze_data[x][y] = maze_data
|
2017-07-30 18:06:33 +02:00
|
|
|
last_maze = maze_data
|
|
|
|
last_maze_x = x
|
|
|
|
last_maze_y = y
|
|
|
|
return maze_data
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local last_maze_ore_x, last_maze_ore_y, last_maze_ore
|
2017-07-30 18:06:33 +02:00
|
|
|
local function get_maze_ore(x, y, seed, width, height)
|
2019-01-16 20:44:55 +02:00
|
|
|
if last_maze_ore and last_maze_ore_x == x and last_maze_ore_y == y then
|
|
|
|
return last_maze_ore
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
if not global_ore_data[x] then
|
|
|
|
global_ore_data[x] = {}
|
|
|
|
end
|
|
|
|
if global_ore_data[x][y] then
|
|
|
|
last_maze_ore = global_ore_data[x][y]
|
2017-07-30 18:06:33 +02:00
|
|
|
last_maze_ore_x = x
|
|
|
|
last_maze_ore_y = y
|
|
|
|
return last_maze_ore
|
|
|
|
end
|
|
|
|
|
|
|
|
local coord_list = {}
|
|
|
|
local maze_data = {}
|
2019-01-16 20:44:55 +02:00
|
|
|
for tx = 1, width do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_data[tx] = {}
|
2019-01-16 20:44:55 +02:00
|
|
|
for ty = 1, height do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_data[tx][ty] = nil
|
2019-01-16 20:44:55 +02:00
|
|
|
coord_list[#coord_list + 1] = {tx, ty}
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local maze_seed = bxor(bit32.lshift(x, 16) + band(y, 65535), seed)
|
|
|
|
local value
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
for _ = 1, iron_ore_count do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = table.remove(coord_list, value % #coord_list + 1)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[pos[1]][pos[2]] = 'iron-ore'
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
for _ = 1, copper_ore_count do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = table.remove(coord_list, value % #coord_list + 1)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[pos[1]][pos[2]] = 'copper-ore'
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
for _ = 1, coal_ore_count do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = table.remove(coord_list, value % #coord_list + 1)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[pos[1]][pos[2]] = 'coal'
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
for _ = 1, stone_ore_count do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = table.remove(coord_list, value % #coord_list + 1)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[pos[1]][pos[2]] = 'stone'
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
for _ = 1, uranium_ore_count do
|
2017-07-30 18:06:33 +02:00
|
|
|
maze_seed, value = get_random_maze_val(maze_seed)
|
|
|
|
local pos = table.remove(coord_list, value % #coord_list + 1)
|
2019-01-16 20:44:55 +02:00
|
|
|
maze_data[pos[1]][pos[2]] = 'uranium-ore'
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
global_ore_data[x][y] = maze_data
|
2017-07-30 18:06:33 +02:00
|
|
|
last_maze_ore = maze_data
|
|
|
|
last_maze_ore_x = x
|
|
|
|
last_maze_ore_y = y
|
|
|
|
return maze_data
|
|
|
|
end
|
|
|
|
|
|
|
|
local function global_to_maze_pos(x, y)
|
|
|
|
--Ensures we start in the middle of a tile.
|
2019-01-16 20:44:55 +02:00
|
|
|
x = x + maze_tile_size / 2
|
|
|
|
y = y + maze_tile_size / 2
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local maze_width_raw = (maze_width + 1) * maze_tile_size
|
|
|
|
local maze_height_raw = (maze_height + 1) * maze_tile_size
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
local global_maze_x = math.floor(x / maze_width_raw)
|
|
|
|
local global_maze_y = math.floor(y / maze_height_raw)
|
|
|
|
x = x - global_maze_x * maze_width_raw
|
|
|
|
y = y - global_maze_y * maze_height_raw
|
|
|
|
|
|
|
|
local local_maze_x = math.floor(x / maze_tile_size)
|
|
|
|
local local_maze_y = math.floor(y / maze_tile_size)
|
|
|
|
x = x - local_maze_x * maze_tile_size
|
|
|
|
y = y - local_maze_y * maze_tile_size
|
|
|
|
|
|
|
|
return global_maze_x, global_maze_y, local_maze_x, local_maze_y, x, y
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local function handle_maze_tile(x, y, _, seed)
|
2017-07-30 18:06:33 +02:00
|
|
|
local orig_x, orig_y = x, y
|
2019-01-16 20:44:55 +02:00
|
|
|
local global_maze_x, global_maze_y, local_maze_x, local_maze_y
|
2017-07-30 18:06:33 +02:00
|
|
|
global_maze_x, global_maze_y, local_maze_x, local_maze_y, x, y = global_to_maze_pos(x, y)
|
|
|
|
|
|
|
|
local maze_data = get_maze(global_maze_x, global_maze_y, seed, maze_width, maze_height)
|
|
|
|
local maze_value = 0
|
|
|
|
if local_maze_x == 0 or local_maze_y == 0 then
|
|
|
|
if local_maze_x == 0 then
|
|
|
|
if local_maze_y ~= 0 then
|
2019-01-16 20:44:55 +02:00
|
|
|
if maze_data[maze_width + 1][1] ~= local_maze_y then
|
|
|
|
maze_value = 1
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
else
|
2019-01-16 20:44:55 +02:00
|
|
|
if maze_data[maze_width + 1][2] ~= local_maze_x then
|
|
|
|
maze_value = 2
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
else
|
|
|
|
maze_value = maze_data[local_maze_x][local_maze_y]
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
if x < maze_tile_border and y < maze_tile_border then
|
|
|
|
return {name = 'out-of-map', position = {orig_x, orig_y}}
|
|
|
|
end
|
|
|
|
if x < maze_tile_border and bit32.btest(maze_value, 1) then
|
|
|
|
return {name = 'out-of-map', position = {orig_x, orig_y}}
|
|
|
|
end
|
|
|
|
if y < maze_tile_border and bit32.btest(maze_value, 2) then
|
|
|
|
return {name = 'out-of-map', position = {orig_x, orig_y}}
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
return nil
|
|
|
|
end
|
|
|
|
|
|
|
|
local function handle_maze_tile_ore(x, y, surf, seed)
|
|
|
|
local orig_x, orig_y = x, y
|
2019-01-16 20:44:55 +02:00
|
|
|
local spawn_distance_1k = math.sqrt(x * x + y * y) / 1000
|
|
|
|
local global_maze_x, global_maze_y, local_maze_x, local_maze_y
|
2017-07-30 18:06:33 +02:00
|
|
|
global_maze_x, global_maze_y, local_maze_x, local_maze_y, x, y = global_to_maze_pos(x, y)
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
if x < maze_tile_border or y < maze_tile_border then
|
|
|
|
return
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
local ore_name = nil
|
|
|
|
if local_maze_x == 0 or local_maze_y == 0 then
|
2019-01-16 20:44:55 +02:00
|
|
|
if global_maze_x == 0 and global_maze_y == 0 then
|
|
|
|
if local_maze_x == 1 and local_maze_y == 0 then
|
|
|
|
ore_name = 'iron-ore'
|
|
|
|
end
|
|
|
|
if local_maze_x == 0 and local_maze_y == 1 then
|
|
|
|
ore_name = 'stone'
|
|
|
|
end
|
|
|
|
elseif global_maze_x == -1 and global_maze_y == 0 and local_maze_x == maze_width and local_maze_y == 0 then
|
|
|
|
ore_name = 'copper-ore'
|
|
|
|
elseif global_maze_x == 0 and global_maze_y == -1 and local_maze_x == 0 and local_maze_y == maze_height then
|
|
|
|
ore_name = 'coal'
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
else
|
2019-01-16 20:44:55 +02:00
|
|
|
local ore_data = get_maze_ore(global_maze_x, global_maze_y, seed, maze_width, maze_height)
|
|
|
|
ore_name = ore_data[local_maze_x][local_maze_y]
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
|
|
|
|
if ore_name then
|
2019-01-16 20:44:55 +02:00
|
|
|
if surf.can_place_entity {name = ore_name, position = {orig_x, orig_y}} then
|
|
|
|
local dist = spawn_distance_1k
|
|
|
|
local resource_amount_max = math.floor(resource_density_factor * (dist * dist + 1))
|
2017-07-30 18:06:33 +02:00
|
|
|
local dist_x = maze_tile_size - x - 1
|
2019-01-16 20:44:55 +02:00
|
|
|
if (x - maze_tile_border) < dist_x then
|
|
|
|
dist_x = (x - maze_tile_border)
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
local dist_y = maze_tile_size - y - 1
|
2019-01-16 20:44:55 +02:00
|
|
|
if (y - maze_tile_border) < dist_y then
|
|
|
|
dist_y = (y - maze_tile_border)
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
|
|
|
|
dist = dist_x
|
2019-01-16 20:44:55 +02:00
|
|
|
if dist_y < dist then
|
|
|
|
dist = dist_y
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
dist = dist + 1
|
|
|
|
|
2017-07-30 21:23:44 +02:00
|
|
|
local resource_amount = resource_amount_max * dist / maze_tile_size * 2
|
|
|
|
if resource_amount > resource_amount_max / 2 then
|
2019-01-16 20:44:55 +02:00
|
|
|
surf.create_entity {name = ore_name, position = {orig_x, orig_y}, amount = resource_amount}
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local function on_chunk_generated_ore(event)
|
|
|
|
local entities = event.surface.find_entities(event.area)
|
|
|
|
for _, entity in pairs(entities) do
|
2019-01-16 20:44:55 +02:00
|
|
|
if entity.type == 'resource' and entity.name ~= 'crude-oil' then
|
2017-07-30 18:06:33 +02:00
|
|
|
entity.destroy()
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
local tx, ty = event.area.left_top.x, event.area.left_top.y
|
|
|
|
local ex, ey = event.area.right_bottom.x, event.area.right_bottom.y
|
2019-01-16 20:44:55 +02:00
|
|
|
local surface = event.surface
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
for x = tx, ex do
|
|
|
|
for y = ty, ey do
|
|
|
|
handle_maze_tile_ore(x, y, surface, primitives.maze_seed)
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
Event.on_init(
|
|
|
|
function()
|
|
|
|
primitives.maze_seed = math.random(0, 65536 * 65536 - 1)
|
|
|
|
end
|
|
|
|
)
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
Event.add(
|
|
|
|
defines.events.on_chunk_generated,
|
|
|
|
function(event)
|
|
|
|
if event.surface ~= RS.get_surface() then
|
|
|
|
return
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
local tiles = {}
|
|
|
|
local tx, ty = event.area.left_top.x, event.area.left_top.y
|
|
|
|
local ex, ey = event.area.right_bottom.x, event.area.right_bottom.y
|
|
|
|
local surface = event.surface
|
|
|
|
|
|
|
|
for x = tx, ex do
|
|
|
|
for y = ty, ey do
|
|
|
|
local new_tile = handle_maze_tile(x, y, surface, primitives.maze_seed)
|
|
|
|
if new_tile then
|
|
|
|
table.insert(tiles, new_tile)
|
|
|
|
end
|
|
|
|
end
|
2017-07-30 18:06:33 +02:00
|
|
|
end
|
2019-01-16 20:44:55 +02:00
|
|
|
surface.set_tiles(tiles, true)
|
2017-07-30 18:06:33 +02:00
|
|
|
|
2019-01-16 20:44:55 +02:00
|
|
|
on_chunk_generated_ore(event)
|
|
|
|
end
|
|
|
|
)
|