1
0
mirror of https://github.com/Refactorio/RedMew.git synced 2024-12-12 10:04:40 +02:00
This commit is contained in:
grilledham 2018-07-13 16:36:43 +01:00
parent 7199cfa497
commit e4cf31a6fb

View File

@ -4,6 +4,45 @@ local Token = require 'utils.global_token'
local direction_bit_mask = 0xc0000000
local section_bit_mask = 0x30000000
local level_bit_mask = 0x0fffffff
local not_level_bit_mask = 0xf0000000
local direction_bit_shift = 30
local section_bit_shift = 28
local section_straight = 0
local section_outer_corner = 1
local section_inner_corner = 2
local wall_north_straight = 0x00000001
local wall_east_straight = 0x40000001
local wall_south_straight = 0x80000001
local wall_west_straight = 0xc0000001
local wall_north_outer = 0x10000001
local wall_east_outer = 0x50000001
local wall_south_outer = 0x90000001
local wall_west_outer = 0xd0000001
local wall_north_inner = 0x20000001
local wall_east_inner = 0x60000001
local wall_south_inner = 0xa0000001
local wall_west_inner = 0xe0000001
local function get_direction(part)
local dir = bit32.band(part, direction_bit_mask)
return bit32.rshift(dir, direction_bit_shift - 1)
end
local function get_section(part)
local sec = bit32.band(part, section_bit_mask)
return bit32.rshift(sec, section_bit_shift)
end
local function get_level(part)
return bit32.band(part, level_bit_mask)
end
local function set_level(part, level)
local not_level = bit32.band(part)
return not_level + level
end
local function set_block(tbl, x, y, value)
tbl[(y - 1) * tbl.size + x] = value
@ -26,79 +65,6 @@ function Public.new(seed)
return setmetatable(obj, Public)
end
local function set_wall_block(blocks, x, y)
set_block(blocks, x, y, 1)
table.insert(blocks.stack, {x = x, y = y})
end
local function goto_point_top(blocks, x, y, tx, ty)
while x < tx do
x = x + 1
set_wall_block(blocks, x, y)
end
while y > ty do
y = y - 1
set_wall_block(blocks, x, y)
end
while y < ty do
y = y + 1
set_wall_block(blocks, x, y)
end
end
local function goto_point_bottom(blocks, x, y, tx, ty)
while x > tx do
x = x - 1
set_wall_block(blocks, x, y)
end
while y > ty do
y = y - 1
set_wall_block(blocks, x, y)
end
while y < ty do
y = y + 1
set_wall_block(blocks, x, y)
end
end
local function goto_point_left(blocks, x, y, tx, ty)
while y > ty do
y = y - 1
set_wall_block(blocks, x, y)
end
while x > tx do
x = x - 1
set_wall_block(blocks, x, y)
end
while x < tx do
x = x + 1
set_wall_block(blocks, x, y)
end
end
local function goto_point_right(blocks, x, y, tx, ty)
while y < ty do
y = y + 1
set_wall_block(blocks, x, y)
end
while x > tx do
x = x - 1
set_wall_block(blocks, x, y)
end
while x < tx do
x = x + 1
set_wall_block(blocks, x, y)
end
end
local function do_walls(self, blocks, outpost_variance, outpost_min_step)
local size = blocks.size
local random = self.random
@ -109,86 +75,282 @@ local function do_walls(self, blocks, outpost_variance, outpost_min_step)
local x = random:next_int(1, outpost_variance)
local y = random:next_int(1, outpost_variance)
set_block(blocks, x, y, 1)
table.insert(blocks.stack, {x = x, y = y})
local start_x, start_y = x, y
local i = (y - 1) * size + x
local pv = -1
-- top
while x < size do
local tx = x + random:next_int(outpost_min_step, variance_step)
tx = math.min(size, tx)
local ty = random:next_int(1, outpost_variance)
tx = math.min(tx, size)
goto_point_top(blocks, x, y, tx, ty)
if pv == 0 then
blocks[i] = wall_north_straight
elseif pv == -1 then
blocks[i] = wall_north_outer
else
blocks[i] = wall_north_inner
end
x, y = tx, ty
x = x + 1
i = i + 1
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
if x < size - outpost_min_step then
local ty = random:next_int(1, outpost_variance)
if y == ty then
pv = 0
elseif y < ty then
pv = 1
blocks[i] = wall_north_outer
y = y + 1
i = i + size
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
else
pv = -1
blocks[i] = wall_north_inner
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
else
pv = 0
end
end
pv = 1
-- right
while y < size do
local tx = random:next_int(max_variance, size)
local ty = y + random:next_int(outpost_min_step, variance_step)
ty = math.min(size, ty)
ty = math.min(ty, size)
goto_point_right(blocks, x, y, tx, ty)
if pv == 0 then
blocks[i] = wall_east_straight
elseif pv == -1 then
blocks[i] = wall_east_inner
else
blocks[i] = wall_east_outer
end
x, y = tx, ty
y = y + 1
i = i + size
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
if y < size - outpost_min_step then
local tx = random:next_int(max_variance, size)
if x == tx then
pv = 0
elseif x < tx then
pv = 1
blocks[i] = wall_east_inner
x = x + 1
i = i + 1
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
else
pv = -1
blocks[i] = wall_east_outer
x = x - 1
i = i - 1
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
end
else
pv = 0
end
end
pv = 1
-- bottom
while x > 1 do
local tx = x - random:next_int(outpost_min_step, variance_step)
tx = math.max(1, tx)
local ty = random:next_int(max_variance, size)
tx = math.max(tx, 1)
goto_point_bottom(blocks, x, y, tx, ty)
if pv == 0 then
blocks[i] = wall_south_straight
elseif pv == -1 then
blocks[i] = wall_south_inner
else
blocks[i] = wall_south_outer
end
x, y = tx, ty
x = x - 1
i = i - 1
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
if x > outpost_min_step + 1 then
local ty = random:next_int(max_variance, size)
if y == ty then
pv = 0
elseif y < ty then
pv = 1
blocks[i] = wall_south_inner
y = y + 1
i = i + size
while y < ty do
blocks[i] = wall_east_straight
y = y + 1
i = i + size
end
else
pv = -1
blocks[i] = wall_south_outer
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
else
pv = 0
end
end
pv = -1
-- left
local bottom_left_y = y
while y > start_y + variance_step do
local ty = y - random:next_int(outpost_min_step, variance_step)
ty = math.max(ty, start_y)
if pv == 0 then
blocks[i] = wall_west_straight
elseif pv == -1 then
blocks[i] = wall_west_outer
else
blocks[i] = wall_west_inner
end
y = y - 1
i = i - size
while y > ty do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
if y > start_y + variance_step + outpost_min_step then
local tx = random:next_int(1, outpost_variance)
if x == tx then
pv = 0
elseif x < tx then
pv = 1
blocks[i] = wall_west_outer
x = x + 1
i = i + 1
while x < tx do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
else
pv = -1
blocks[i] = wall_west_inner
x = x - 1
i = i - 1
while x > tx do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
end
else
pv = 0
end
end
-- final connection
if y == bottom_left_y then
blocks[i] = wall_west_outer
y = y - 1
i = i - size
while y > bottom_left_y - outpost_min_step do
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
if x == start_x then
pv = 0
elseif x < start_x then
pv = 1
blocks[i] = wall_west_outer
x = x + 1
i = i + 1
while x < start_x do
blocks[i] = wall_north_straight
x = x + 1
i = i + 1
end
else
pv = -1
blocks[i] = wall_west_inner
x = x - 1
i = i - 1
while x > start_x do
blocks[i] = wall_south_straight
x = x - 1
i = i - 1
end
end
if pv == 0 then
blocks[i] = wall_west_straight
elseif pv == -1 then
blocks[i] = wall_west_outer
else
blocks[i] = wall_west_inner
end
y = y - 1
i = i - size
while y > start_y do
local tx = random:next_int(1, outpost_variance)
local ty = y - random:next_int(outpost_min_step, variance_step)
if ty <= start_y then
ty = start_y
tx = start_x
end
goto_point_left(blocks, x, y, tx, ty)
x, y = tx, ty
end
end
local function remove_surplus_walls(blocks)
local stack = blocks.stack
local size = blocks.size
while #stack > 0 do
local count = 0
local nx, ny
local point = table.remove(stack)
local x, y = point.x, point.y
if x > 1 and get_block(blocks, x - 1, y) == 1 then
nx, ny = x - 1, y
count = count + 1
end
if x < size and get_block(blocks, x + 1, y) == 1 then
nx, ny = x + 1, y
count = count + 1
end
if y > 1 and get_block(blocks, x, y - 1) == 1 then
nx, ny = x, y - 1
count = count + 1
end
if y < size and get_block(blocks, x, y + 1) == 1 then
nx, ny = x, y + 1
count = count + 1
end
if count == 1 then
set_block(blocks, x, y, 0)
table.insert(stack, {x = nx, y = ny})
end
blocks[i] = wall_west_straight
y = y - 1
i = i - size
end
end
@ -199,22 +361,22 @@ local function fill(blocks)
local y_offset = (size - 1) * size
for x = 1, size do
if blocks[x] ~= 1 then
if blocks[x] == nil then
table.insert(anti_stack, {x = x, y = 1})
end
if blocks[x + y_offset] ~= 1 then
if blocks[x + y_offset] == nil then
table.insert(anti_stack, {x = x, y = size})
end
end
for y = 2, size do
y_offset = (y - 1) * size
if blocks[y_offset + 1] ~= 1 then
if blocks[y_offset + 1] == nil then
table.insert(anti_stack, {x = 1, y = y})
end
if blocks[y_offset + size] ~= 1 then
if blocks[y_offset + size] == nil then
table.insert(anti_stack, {x = size, y = y})
end
end
@ -225,13 +387,13 @@ local function fill(blocks)
local offset = (y - 1) * size + x
anti_set[offset] = 1
anti_set[offset] = true
if x > 1 then
local x2 = x - 1
local offset2 = offset - 1
if anti_set[offset2] ~= 1 and blocks[offset2] ~= 1 then
if not anti_set[offset2] and not blocks[offset2] then
table.insert(anti_stack, {x = x2, y = y})
end
end
@ -239,7 +401,7 @@ local function fill(blocks)
local x2 = x + 1
local offset2 = offset + 1
if anti_set[offset2] ~= 1 and blocks[offset2] ~= 1 then
if not anti_set[offset2] and not blocks[offset2] then
table.insert(anti_stack, {x = x2, y = y})
end
end
@ -247,7 +409,7 @@ local function fill(blocks)
local y2 = y - 1
local offset2 = offset - size
if anti_set[offset2] ~= 1 and blocks[offset2] ~= 1 then
if not anti_set[offset2] and not blocks[offset2] then
table.insert(anti_stack, {x = x, y = y2})
end
end
@ -255,7 +417,7 @@ local function fill(blocks)
local y2 = y + 1
local offset2 = offset + size
if anti_set[offset2] ~= 1 and blocks[offset2] ~= 1 then
if not anti_set[offset2] and not blocks[offset2] then
table.insert(anti_stack, {x = x, y = y2})
end
end
@ -265,49 +427,41 @@ local function fill(blocks)
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
if anti_set[i] ~= 1 then
blocks[i] = 1
if not anti_set[i] and not blocks[i] then
blocks[i] = 2
end
end
end
end
local function do_levels(blocks, max_level)
if max_level < 2 then
if max_level < 3 then
return
end
local size = blocks.size
--[[ for y = 1, size do
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
end
end ]]
local level = 1
local next_level = 2
local level = 2
repeat
local next_level = level + 1
for y = 1, size do
local offset = (y - 1) * size
for x = 1, size do
local i = offset + x
if (blocks[i] or 0) >= level then
if get_level(blocks[i] or 0) >= level then
local count = 0
if x > 1 and (blocks[i - 1] or 0) >= level then
if x > 1 and get_level(blocks[i - 1] or 0) >= level then
count = count + 1
end
if x < size and (blocks[i + 1] or 0) >= level then
if x < size and get_level(blocks[i + 1] or 0) >= level then
count = count + 1
end
if y > 1 and (blocks[i - size] or 0) >= level then
if y > 1 and get_level(blocks[i - size] or 0) >= level then
count = count + 1
end
if y < size and (blocks[i + size] or 0) >= level then
if y < size and get_level(blocks[i + size] or 0) >= level then
count = count + 1
end
@ -319,8 +473,7 @@ local function do_levels(blocks, max_level)
end
level = level + 1
next_level = next_level + 1
until next_level == max_level + 1
until level == max_level
end
local callback =
@ -331,25 +484,50 @@ local callback =
)
function Public:do_outpost(outpost_blocks, outpost_variance, outpost_min_step, max_level)
local blocks = {size = outpost_blocks, stack = {}}
local blocks = {size = outpost_blocks}
do_walls(self, blocks, outpost_variance, outpost_min_step)
remove_surplus_walls(blocks)
fill(blocks)
do_levels(blocks, max_level)
local size = blocks.size
return function(x, y)
x, y = math.floor(x), math.floor(y)
local level = get_block(blocks, x, y)
if x < 1 or x > size or y < 1 or y > size then
return
end
if level == 1 then
return {name = 'stone-wall', force = 'player'}
elseif level == 2 then
return {name = 'transport-belt', force = 'player'}
elseif level == 3 then
return {name = 'pipe', force = 'player', callback = callback}
elseif level == 4 then
return {name = 'iron-chest', force = 'player'}
local part = blocks[(y - 1) * blocks.size + x]
if part then
local direction = get_direction(part)
local section = get_section(part)
local level = get_level(part)
local name
if level == 2 then
name = 'wooden-chest'
elseif level == 3 then
name = 'iron-chest'
elseif level == 4 then
name = 'steel-chest'
elseif level > 4 then
name = 'pipe'
elseif level < 1 then
name = 'small-electric-pole'
else
if section == section_straight then
name = 'stone-wall'
elseif section == section_outer_corner then
name = 'inserter'
elseif section == section_inner_corner then
name = 'transport-belt'
else
name = 'pipe'
end
end
return {name = name, force = 'player', direction = direction, callback = callback}
end
end
end