mirror of
https://github.com/Refactorio/RedMew.git
synced 2024-12-16 10:19:27 +02:00
3b72c497cb
No one likes or uses the pollution multiplier feature I added. Feedback suggests that it spawning at outposts makes the cause too obvious, so people complain about it. And it requires that outposts have to be defended. Yet, people still complain crash site is too easy. By moving the pollution spawning to the centre of the base the effect of more outposts is spread over the whole base and will trigger more attacks, but will challenge the whole base defences rather than just a single outpost.
1968 lines
52 KiB
Lua
1968 lines
52 KiB
Lua
--local Random = require 'map_gen.shared.random'
|
|
local Command = require 'utils.command'
|
|
local Ranks = require 'resources.ranks'
|
|
local Token = require 'utils.token'
|
|
local Global = require 'utils.global'
|
|
local Event = require 'utils.event'
|
|
local Task = require 'utils.task'
|
|
local Retailer = require 'features.retailer'
|
|
local Donator = require 'features.donator'
|
|
local RS = require 'map_gen.shared.redmew_surface'
|
|
local Server = require 'features.server'
|
|
local CrashSiteToast = require 'map_gen.maps.crash_site.crash_site_toast'
|
|
|
|
local table = require 'utils.table'
|
|
--local next = next
|
|
local pairs = pairs
|
|
local concat = table.concat
|
|
local floor = math.floor
|
|
local format = string.format
|
|
local tostring = tostring
|
|
local draw_text = rendering.draw_text
|
|
local render_mode_game = defines.render_mode.game
|
|
|
|
local b = require 'map_gen.shared.builders'
|
|
|
|
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 default_part_size = 6
|
|
|
|
local magic_crafters_per_tick = 3
|
|
local magic_fluid_crafters_per_tick = 8
|
|
|
|
local refill_turrets = {index = 1}
|
|
local power_sources = {}
|
|
local turret_to_outpost = {}
|
|
local magic_crafters = {index = 1}
|
|
local magic_fluid_crafters = {index = 1}
|
|
local outposts = {}
|
|
local artillery_outposts = {index = 1}
|
|
local outpost_count = 0
|
|
local pollution_multiplier = {value = 0}
|
|
|
|
Global.register(
|
|
{
|
|
refil_turrets = refill_turrets,
|
|
power_sources = power_sources,
|
|
turret_to_outpost = turret_to_outpost,
|
|
magic_crafters = magic_crafters,
|
|
magic_fluid_crafters = magic_fluid_crafters,
|
|
outposts = outposts,
|
|
artillery_outposts = artillery_outposts,
|
|
pollution_multiplier = pollution_multiplier
|
|
|
|
},
|
|
function(tbl)
|
|
refill_turrets = tbl.refil_turrets
|
|
power_sources = tbl.power_sources
|
|
turret_to_outpost = tbl.turret_to_outpost
|
|
magic_crafters = tbl.magic_crafters
|
|
magic_fluid_crafters = tbl.magic_fluid_crafters
|
|
outposts = tbl.outposts
|
|
artillery_outposts = tbl.artillery_outposts
|
|
pollution_multiplier = tbl.pollution_multiplier
|
|
end
|
|
)
|
|
|
|
--[[ 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_4_way_direction(part)
|
|
local dir = bit32.band(part, direction_bit_mask)
|
|
return bit32.rshift(dir, direction_bit_shift)
|
|
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
|
|
end
|
|
|
|
local function get_block(tbl, x, y)
|
|
local size = tbl.size
|
|
if x < 1 or x > size or y < 1 or y > size then
|
|
return 0
|
|
end
|
|
return tbl[(y - 1) * size + x] or 0
|
|
end ]]
|
|
local function fast_remove(tbl, index)
|
|
local count = #tbl
|
|
if index > count then
|
|
return
|
|
elseif index < count then
|
|
tbl[index] = tbl[count]
|
|
end
|
|
|
|
tbl[count] = nil
|
|
end
|
|
|
|
local Public = {}
|
|
Public.__index = Public
|
|
|
|
Public.empty_template = {}
|
|
|
|
function Public.new(random)
|
|
local obj = {random = random}
|
|
|
|
return setmetatable(obj, Public)
|
|
end
|
|
|
|
local function do_walls(self, blocks, outpost_variance, outpost_min_step)
|
|
local size = blocks.size
|
|
local random = self.random
|
|
|
|
local max_variance = size - outpost_variance + 1
|
|
local variance_step = outpost_variance + outpost_min_step
|
|
|
|
local x = random:next_int(1, outpost_variance)
|
|
local y = random:next_int(1, outpost_variance)
|
|
|
|
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(tx, size)
|
|
|
|
if pv == 0 then
|
|
blocks[i] = wall_north_straight
|
|
elseif pv == -1 then
|
|
blocks[i] = wall_north_outer
|
|
else
|
|
blocks[i] = wall_east_inner
|
|
end
|
|
|
|
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_east_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 ty = y + random:next_int(outpost_min_step, variance_step)
|
|
ty = math.min(ty, size)
|
|
|
|
if pv == 0 then
|
|
blocks[i] = wall_east_straight
|
|
elseif pv == -1 then
|
|
blocks[i] = wall_south_inner
|
|
else
|
|
blocks[i] = wall_east_outer
|
|
end
|
|
|
|
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_south_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(tx, 1)
|
|
|
|
if pv == 0 then
|
|
blocks[i] = wall_south_straight
|
|
elseif pv == -1 then
|
|
blocks[i] = wall_west_inner
|
|
else
|
|
blocks[i] = wall_south_outer
|
|
end
|
|
|
|
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_west_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_north_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
|
|
blocks[i] = wall_north_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_north_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_north_inner
|
|
end
|
|
|
|
y = y - 1
|
|
i = i - size
|
|
|
|
while y > start_y do
|
|
blocks[i] = wall_west_straight
|
|
y = y - 1
|
|
i = i - size
|
|
end
|
|
end
|
|
|
|
local function fill(blocks)
|
|
local size = blocks.size
|
|
local anti_set = {size = size}
|
|
local anti_stack = {}
|
|
|
|
local y_offset = (size - 1) * size
|
|
for x = 1, size do
|
|
if blocks[x] == nil then
|
|
anti_stack[#anti_stack + 1] = {x = x, y = 1}
|
|
end
|
|
|
|
if blocks[x + y_offset] == nil then
|
|
anti_stack[#anti_stack + 1] = {x = x, y = size}
|
|
end
|
|
end
|
|
|
|
for y = 2, size do
|
|
y_offset = (y - 1) * size
|
|
if blocks[y_offset + 1] == nil then
|
|
anti_stack[#anti_stack + 1] = {x = 1, y = y}
|
|
end
|
|
|
|
if blocks[y_offset + size] == nil then
|
|
anti_stack[#anti_stack + 1] = {x = size, y = y}
|
|
end
|
|
end
|
|
|
|
while #anti_stack > 0 do
|
|
local point = table.remove(anti_stack)
|
|
local x, y = point.x, point.y
|
|
|
|
local offset = (y - 1) * size + x
|
|
|
|
anti_set[offset] = true
|
|
|
|
if x > 1 then
|
|
local x2 = x - 1
|
|
local offset2 = offset - 1
|
|
|
|
if not anti_set[offset2] and not blocks[offset2] then
|
|
anti_stack[#anti_stack + 1] = {x = x2, y = y}
|
|
end
|
|
end
|
|
if x < size then
|
|
local x2 = x + 1
|
|
local offset2 = offset + 1
|
|
|
|
if not anti_set[offset2] and not blocks[offset2] then
|
|
anti_stack[#anti_stack + 1] = {x = x2, y = y}
|
|
end
|
|
end
|
|
if y > 1 then
|
|
local y2 = y - 1
|
|
local offset2 = offset - size
|
|
|
|
if not anti_set[offset2] and not blocks[offset2] then
|
|
anti_stack[#anti_stack + 1] = {x = x, y = y2}
|
|
end
|
|
end
|
|
if y < size then
|
|
local y2 = y + 1
|
|
local offset2 = offset + size
|
|
|
|
if not anti_set[offset2] and not blocks[offset2] then
|
|
anti_stack[#anti_stack + 1] = {x = x, y = y2}
|
|
end
|
|
end
|
|
end
|
|
|
|
for y = 1, size do
|
|
local offset = (y - 1) * size
|
|
for x = 1, size do
|
|
local i = offset + x
|
|
if not anti_set[i] and not blocks[i] then
|
|
blocks[i] = 2
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function do_levels(blocks, max_level)
|
|
local size = blocks.size
|
|
local level = 2
|
|
|
|
while level < max_level do
|
|
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 get_level(blocks[i] or 0) >= level then
|
|
local count = 0
|
|
|
|
if x > 1 and get_level(blocks[i - 1] or 0) >= level then
|
|
count = count + 1
|
|
end
|
|
if x < size and get_level(blocks[i + 1] or 0) >= level then
|
|
count = count + 1
|
|
end
|
|
if y > 1 and get_level(blocks[i - size] or 0) >= level then
|
|
count = count + 1
|
|
end
|
|
if y < size and get_level(blocks[i + size] or 0) >= level then
|
|
count = count + 1
|
|
end
|
|
|
|
if count == 4 then
|
|
blocks[i] = next_level
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
level = level + 1
|
|
end
|
|
|
|
local levels = {}
|
|
blocks.levels = levels
|
|
|
|
for i = 1, max_level do
|
|
levels[i] = {}
|
|
end
|
|
|
|
for y = 1, size do
|
|
local offset = (y - 1) * size
|
|
for x = 1, size do
|
|
local i = offset + x
|
|
local block = blocks[i]
|
|
if block then
|
|
local l = get_level(block)
|
|
|
|
local lvl = levels[l]
|
|
lvl[#lvl + 1] = i
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_template(random, templates, templates_count, counts)
|
|
local template
|
|
if templates_count == 0 then
|
|
return nil
|
|
elseif templates_count == 1 then
|
|
template = templates[1]
|
|
else
|
|
local ti = random:next_int(1, templates_count)
|
|
template = templates[ti]
|
|
end
|
|
|
|
if template == Public.empty_template then
|
|
return nil
|
|
end
|
|
|
|
local count = counts[template] or 0
|
|
local max_count = template.max_count
|
|
|
|
while count == max_count do
|
|
template = template.fallback
|
|
if template == nil then
|
|
return nil
|
|
end
|
|
count = counts[template] or 0
|
|
max_count = template.max_count
|
|
end
|
|
|
|
counts[template] = count + 1
|
|
|
|
return template
|
|
end
|
|
|
|
local function make_blocks(self, blocks, template)
|
|
local random = self.random
|
|
local counts = {}
|
|
|
|
local levels = blocks.levels
|
|
local wall_level = levels[1]
|
|
|
|
local walls = template.walls
|
|
local wall_template_count = #walls
|
|
|
|
while #wall_level > 0 do
|
|
local index = random:next_int(1, #wall_level)
|
|
local i = wall_level[index]
|
|
|
|
fast_remove(wall_level, index)
|
|
|
|
local block = get_template(random, walls, wall_template_count, counts)
|
|
|
|
if block == Public.empty_template then
|
|
blocks[i] = nil
|
|
else
|
|
local block_data = blocks[i]
|
|
|
|
local section = get_section(block_data)
|
|
local dir = get_4_way_direction(block_data)
|
|
|
|
local new_block = block[section + 1][dir + 1]
|
|
blocks[i] = new_block
|
|
end
|
|
end
|
|
|
|
local bases = template.bases
|
|
|
|
for l = 2, #levels do
|
|
local level = levels[l]
|
|
local base_templates = bases[l - 1]
|
|
|
|
if base_templates then
|
|
local base_template_count = #base_templates
|
|
|
|
while #level > 0 do
|
|
local index = random:next_int(1, #level)
|
|
local i = level[index]
|
|
|
|
fast_remove(level, index)
|
|
|
|
blocks[i] = get_template(random, base_templates, base_template_count, counts)
|
|
end
|
|
else
|
|
for index = 1, #level do
|
|
local i = level[index]
|
|
blocks[i] = nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local remove_entity_types = {'tree', 'simple-entity'}
|
|
|
|
local function to_shape(blocks, part_size, on_init)
|
|
part_size = part_size or default_part_size
|
|
local inv_part_size = 1 / part_size
|
|
local size = blocks.size
|
|
local t_size = size * part_size
|
|
local half_t_size = t_size * 0.5
|
|
|
|
local outpost_id = outpost_count + 1
|
|
outpost_count = outpost_id
|
|
|
|
if on_init then
|
|
outposts[outpost_id] = {
|
|
outpost_id = outpost_id,
|
|
magic_crafters = {},
|
|
--magic_fluid_crafters = {},
|
|
market = nil,
|
|
turret_count = 0,
|
|
top_left = {nil, nil},
|
|
bottom_right = {nil, nil},
|
|
level = 1,
|
|
upgrade_rate = nil,
|
|
upgrade_base_cost = nil,
|
|
upgrade_cost_base = nil,
|
|
artillery_area = nil,
|
|
artillery_turrets = nil,
|
|
last_fire_tick = nil
|
|
}
|
|
end
|
|
|
|
local function shape(x, y, world)
|
|
x, y = floor(x + half_t_size), floor(y + half_t_size)
|
|
if x < 0 or y < 0 or x >= t_size or y >= t_size then
|
|
return false
|
|
end
|
|
|
|
local x2, y2 = floor(x * inv_part_size), floor(y * inv_part_size)
|
|
|
|
local template = blocks[y2 * size + x2 + 1]
|
|
if not template then
|
|
return false
|
|
end
|
|
|
|
local wx, wy = world.x, world.y
|
|
|
|
local entities =
|
|
world.surface.find_entities_filtered {
|
|
area = {{wx, wy}, {wx + 1, wy + 1}},
|
|
type = remove_entity_types
|
|
}
|
|
for i = 1, #entities do
|
|
local e = entities[i]
|
|
e.destroy()
|
|
end
|
|
|
|
local x3, y3 = x - x2 * part_size, y - y2 * part_size
|
|
|
|
local i = y3 * part_size + x3 + 1
|
|
|
|
local entry = template[i]
|
|
if not entry then
|
|
return false
|
|
end
|
|
|
|
local entity = entry.entity
|
|
local tile = entry.tile or true
|
|
if entity then
|
|
local data
|
|
local callback = entity.callback
|
|
if callback then
|
|
data = {outpost_id = outpost_id}
|
|
local cd = template[callback]
|
|
|
|
callback = cd.callback
|
|
data.callback_data = cd.data
|
|
end
|
|
|
|
return {
|
|
tile = tile,
|
|
entities = {
|
|
{
|
|
name = entity.name,
|
|
direction = entity.direction,
|
|
force = entity.force or template.force,
|
|
callback = callback,
|
|
data = data,
|
|
always_place = true
|
|
}
|
|
}
|
|
}
|
|
end
|
|
return tile
|
|
end
|
|
|
|
return b.change_map_gen_collision_hidden_tile(shape, 'water-tile', 'grass-1')
|
|
end
|
|
|
|
Public.to_shape = to_shape
|
|
|
|
function Public:do_outpost(template, on_init)
|
|
local settings = template.settings
|
|
local blocks = {size = settings.blocks}
|
|
|
|
do_walls(self, blocks, settings.variance, settings.min_step)
|
|
fill(blocks)
|
|
do_levels(blocks, settings.max_level)
|
|
make_blocks(self, blocks, template)
|
|
|
|
return to_shape(blocks, settings.part_size, on_init)
|
|
end
|
|
|
|
local function change_direction(entity, new_dir)
|
|
local copy = {}
|
|
|
|
for k, v in pairs(entity) do
|
|
copy[k] = v
|
|
end
|
|
copy.direction = new_dir
|
|
|
|
return copy
|
|
end
|
|
|
|
function Public.make_1_way(data)
|
|
data.__index = data
|
|
return data
|
|
end
|
|
|
|
local function set_tile(tbl, index, tile)
|
|
local entry = tbl[index]
|
|
if entry then
|
|
entry.tile = tile
|
|
else
|
|
tbl[index] = {tile = tile}
|
|
end
|
|
end
|
|
|
|
local function set_entity(tbl, index, entity)
|
|
local entry = tbl[index]
|
|
|
|
if entry then
|
|
entry.entity = entity
|
|
else
|
|
tbl[index] = {entity = entity}
|
|
end
|
|
end
|
|
|
|
function Public.make_4_way(data)
|
|
local part_size = data.part_size or default_part_size
|
|
local inv_part_size = 1 / part_size
|
|
|
|
local props = {}
|
|
|
|
local north = {}
|
|
local east = {}
|
|
local south = {}
|
|
local west = {}
|
|
local res = {north, east, south, west}
|
|
|
|
for i, entry in pairs(data) do
|
|
if type(i) == 'string' then
|
|
props[i] = entry
|
|
else
|
|
local y = math.ceil(i * inv_part_size)
|
|
local x = i - (y - 1) * part_size
|
|
|
|
local x2 = part_size - y + 1
|
|
local y2 = x
|
|
local x3 = part_size - x + 1
|
|
local y3 = part_size - y + 1
|
|
local x4 = y
|
|
local y4 = part_size - x + 1
|
|
|
|
local i2 = (y2 - 1) * part_size + x2
|
|
local i3 = (y3 - 1) * part_size + x3
|
|
local i4 = (y4 - 1) * part_size + x4
|
|
|
|
local tile = entry.tile
|
|
if tile then
|
|
set_tile(north, i, tile)
|
|
set_tile(east, i2, tile)
|
|
set_tile(south, i3, tile)
|
|
set_tile(west, i4, tile)
|
|
end
|
|
|
|
local entity = entry.entity
|
|
|
|
if entity then
|
|
local offset = entity.offset
|
|
|
|
if offset == 3 then
|
|
i = i + part_size + 1
|
|
i2 = i2 + part_size
|
|
i4 = i4 + 1
|
|
elseif offset == 1 then
|
|
i = i + 1
|
|
i2 = i2 + part_size
|
|
elseif offset == 2 then
|
|
i = i + part_size
|
|
i4 = i4 + 1
|
|
end
|
|
|
|
local dir = entity.direction or 0
|
|
|
|
set_entity(north, i, entity)
|
|
set_entity(east, i2, change_direction(entity, (dir + 2) % 8))
|
|
set_entity(south, i3, change_direction(entity, (dir + 4) % 8))
|
|
set_entity(west, i4, change_direction(entity, (dir + 6) % 8))
|
|
end
|
|
end
|
|
end
|
|
|
|
north.__index = north
|
|
east.__index = east
|
|
south.__index = south
|
|
west.__index = west
|
|
|
|
for k, v in pairs(props) do
|
|
north[k] = v
|
|
east[k] = v
|
|
south[k] = v
|
|
west[k] = v
|
|
end
|
|
|
|
return res
|
|
end
|
|
|
|
function Public.make_walls(data)
|
|
data.__index = data
|
|
return data
|
|
end
|
|
|
|
local function shallow_copy(tbl)
|
|
local copy = {}
|
|
for k, v in pairs(tbl) do
|
|
copy[k] = v
|
|
end
|
|
return copy
|
|
end
|
|
|
|
function Public.extend_1_way(data, tbl)
|
|
return setmetatable(shallow_copy(tbl), data)
|
|
end
|
|
|
|
function Public.extend_4_way(data, tbl)
|
|
return {
|
|
setmetatable(shallow_copy(tbl), data[1]),
|
|
setmetatable(shallow_copy(tbl), data[2]),
|
|
setmetatable(shallow_copy(tbl), data[3]),
|
|
setmetatable(shallow_copy(tbl), data[4])
|
|
}
|
|
end
|
|
|
|
function Public.extend_walls(data, tbl)
|
|
local copy = shallow_copy(tbl)
|
|
|
|
local base = {
|
|
Public.extend_4_way(data[1], copy),
|
|
Public.extend_4_way(data[2], copy),
|
|
Public.extend_4_way(data[3], copy)
|
|
}
|
|
base.__index = base
|
|
|
|
return setmetatable(copy, base)
|
|
end
|
|
|
|
local function update_market_upgrade_description(outpost_data)
|
|
local outpost_id = outpost_data.outpost_id
|
|
|
|
local upgrade_rate = outpost_data.upgrade_rate
|
|
local upgrade_base_cost = outpost_data.upgrade_base_cost
|
|
local upgrade_cost_base = outpost_data.upgrade_cost_base
|
|
local level = outpost_data.level
|
|
local base_outputs = outpost_data.base_outputs
|
|
local outpost_magic_crafters = outpost_data.magic_crafters
|
|
local prototype = Retailer.get_items(outpost_id)['upgrade']
|
|
|
|
prototype.price = upgrade_base_cost * #outpost_magic_crafters * upgrade_cost_base ^ (level - 1)
|
|
prototype.name_label = 'Upgrade Outpost to level ' .. tostring(level + 1)
|
|
|
|
local tooltip_str = {''}
|
|
local mapview_str = {''}
|
|
local count = 2
|
|
for k, v in pairs(base_outputs) do
|
|
local base_rate = v * 60
|
|
local upgrade_per_level = base_rate * upgrade_rate
|
|
local current_rate = base_rate + (level - 1) * upgrade_per_level
|
|
local next_rate = current_rate + upgrade_per_level
|
|
|
|
local name = game.item_prototypes[k]
|
|
if name then
|
|
tooltip_str[count] = concat {'[item=', k, ']'}
|
|
mapview_str[count] = name.localised_name
|
|
else
|
|
name = game.fluid_prototypes[k]
|
|
if name then
|
|
tooltip_str[count] = concat {'[fluid=', k, ']'}
|
|
mapview_str[count] = name.localised_name
|
|
else
|
|
tooltip_str[count] = k
|
|
mapview_str[count] = k
|
|
end
|
|
end
|
|
count = count + 1
|
|
|
|
local str = concat {': ', format('%.2f', current_rate), ' -> ', format('%.2f / sec', next_rate)}
|
|
|
|
tooltip_str[count] = str
|
|
tooltip_str[count + 1] = '\n'
|
|
|
|
mapview_str[count] = str
|
|
mapview_str[count + 1] = ', '
|
|
|
|
count = count + 2
|
|
end
|
|
tooltip_str[count - 1] = nil
|
|
mapview_str[count - 1] = nil
|
|
|
|
prototype.description = tooltip_str
|
|
prototype.disabled = false
|
|
|
|
prototype.mapview_description = mapview_str
|
|
|
|
Retailer.set_item(outpost_id, prototype)
|
|
end
|
|
|
|
local function do_outpost_upgrade(event)
|
|
if event.item.type ~= 'upgrade' then
|
|
return
|
|
end
|
|
|
|
local outpost_id = event.group_name
|
|
local outpost_data = outposts[outpost_id]
|
|
|
|
local outpost_magic_crafters = outpost_data.magic_crafters
|
|
local upgrade_rate = outpost_data.upgrade_rate
|
|
|
|
local level = outpost_data.level + 1
|
|
outpost_data.level = level
|
|
|
|
|
|
local player_name = event.player.name
|
|
local outpost_name = Retailer.get_market_group_label(outpost_id)
|
|
local message = concat {player_name, ' has upgraded ', outpost_name, ' to level ', level}
|
|
|
|
CrashSiteToast.do_outpost_toast(outpost_data.market, message)
|
|
Server.to_discord_bold(concat {'*** ', message, ' ***'})
|
|
|
|
for i = 1, #outpost_magic_crafters do
|
|
local crafter = outpost_magic_crafters[i]
|
|
|
|
local rate = crafter.rate
|
|
local upgrade_amount = upgrade_rate * crafter.base_rate
|
|
|
|
crafter.rate = rate + upgrade_amount
|
|
end
|
|
|
|
update_market_upgrade_description(outpost_data)
|
|
end
|
|
|
|
local function activate_market_upgrade(outpost_data)
|
|
local outpost_magic_crafters = outpost_data.magic_crafters
|
|
|
|
if #outpost_magic_crafters == 0 then
|
|
local outpost_id = outpost_data.outpost_id
|
|
|
|
local prototype = Retailer.get_items(outpost_id)['upgrade']
|
|
prototype.disabled_reason = 'No machines to upgrade.'
|
|
|
|
Retailer.set_item(outpost_id, prototype)
|
|
|
|
return
|
|
end
|
|
|
|
local base_outputs = {}
|
|
|
|
for i = 1, #outpost_magic_crafters do
|
|
local crafter = outpost_magic_crafters[i]
|
|
local item = crafter.item
|
|
|
|
local count = base_outputs[item] or 0
|
|
count = count + crafter.rate
|
|
|
|
base_outputs[item] = count
|
|
end
|
|
|
|
outpost_data.base_outputs = base_outputs
|
|
|
|
update_market_upgrade_description(outpost_data)
|
|
end
|
|
|
|
function Public.activate_market_upgrade(outpost_id)
|
|
local outpost_data = outposts[outpost_id]
|
|
activate_market_upgrade(outpost_data)
|
|
end
|
|
|
|
local function do_capture_outpost(outpost_data)
|
|
local area = {top_left = outpost_data.top_left, bottom_right = outpost_data.bottom_right}
|
|
local walls = RS.get_surface().find_entities_filtered {area = area, force = 'enemy', name = 'stone-wall'}
|
|
|
|
for i = 1, #walls do
|
|
walls[i].force = 'player'
|
|
end
|
|
|
|
local outpost_id = outpost_data.outpost_id
|
|
|
|
local name = Retailer.get_market_group_label(outpost_id)
|
|
if name == 'Market' then
|
|
return
|
|
end
|
|
|
|
local donators = Donator.get_donators_table()
|
|
if next(donators) then
|
|
local donator = table.get_random_dictionary_entry(donators, true)
|
|
if donator then
|
|
name = concat({donator, "'s ", name})
|
|
Retailer.set_market_group_label(outpost_id, name)
|
|
end
|
|
end
|
|
|
|
local message = 'Outpost captured: ' .. name
|
|
CrashSiteToast.do_outpost_toast(outpost_data.market, message)
|
|
Server.to_discord_bold(concat {'*** ', message, ' ***'})
|
|
|
|
activate_market_upgrade(outpost_data)
|
|
end
|
|
|
|
local function do_refill_turrets()
|
|
local index = refill_turrets.index
|
|
|
|
if index > #refill_turrets then
|
|
refill_turrets.index = 1
|
|
return
|
|
end
|
|
|
|
local turret_data = refill_turrets[index]
|
|
local turret = turret_data.turret
|
|
|
|
if not turret.valid then
|
|
fast_remove(refill_turrets, index)
|
|
return
|
|
end
|
|
|
|
refill_turrets.index = index + 1
|
|
|
|
local data = turret_data.data
|
|
if data.liquid then
|
|
turret.fluidbox[1] = data
|
|
elseif data then
|
|
turret.insert(data)
|
|
end
|
|
end
|
|
|
|
local artillery_target_entities = {
|
|
'character',
|
|
'tank',
|
|
'car',
|
|
'locomotive',
|
|
'cargo-wagon',
|
|
'fluid-wagon',
|
|
'artillery-wagon',
|
|
'spidertron'
|
|
}
|
|
|
|
local artillery_target_callback =
|
|
Token.register(
|
|
function(data)
|
|
local position = data.position
|
|
local entity = data.entity
|
|
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
local tx, ty = position.x, position.y
|
|
|
|
local pos = entity.position
|
|
local x, y = pos.x, pos.y
|
|
local dx, dy = tx - x, ty - y
|
|
local d = dx * dx + dy * dy
|
|
if d >= 1024 then -- 32 ^ 2
|
|
entity.surface.create_entity {
|
|
name = 'artillery-projectile',
|
|
position = position,
|
|
target = entity,
|
|
speed = 1.5
|
|
}
|
|
if entity.name == "spidertron" then
|
|
-- fire a rocket as well as artillery-projectile since artillery-projectile doesn't damage spidertrons
|
|
-- Balance note: 1 rocket per artillery kills spidertron shield fast but takes ~ 1 minute to kill the spidertron
|
|
entity.surface.create_entity {
|
|
name = 'rocket',
|
|
position = position,
|
|
target = entity,
|
|
speed = 1.5
|
|
}
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
local function do_artillery_turrets_targets()
|
|
local index = artillery_outposts.index
|
|
|
|
if index > #artillery_outposts then
|
|
artillery_outposts.index = 1
|
|
return
|
|
end
|
|
|
|
artillery_outposts.index = index + 1
|
|
|
|
local outpost = artillery_outposts[index]
|
|
|
|
local now = game.tick
|
|
if now - outpost.last_fire_tick < 480 then
|
|
return
|
|
end
|
|
|
|
local turrets = outpost.artillery_turrets
|
|
for i = #turrets, 1, -1 do
|
|
local turret = turrets[i]
|
|
if not turret.valid then
|
|
fast_remove(turrets, i)
|
|
end
|
|
end
|
|
|
|
local count = #turrets
|
|
if count == 0 then
|
|
fast_remove(artillery_outposts, index)
|
|
return
|
|
end
|
|
|
|
outpost.last_fire_tick = now
|
|
|
|
local turret = turrets[1]
|
|
local area = outpost.artillery_area
|
|
local surface = turret.surface
|
|
|
|
local entities = surface.find_entities_filtered {area = area, name = artillery_target_entities}
|
|
|
|
if #entities == 0 then
|
|
return
|
|
end
|
|
|
|
local position = turret.position
|
|
|
|
for i = 1, count do
|
|
local entity = entities[math.random(#entities)]
|
|
if entity and entity.valid then
|
|
local data = {position = position, entity = entity}
|
|
Task.set_timeout_in_ticks(i * 60, artillery_target_callback, data)
|
|
end
|
|
end
|
|
end
|
|
|
|
local server_player = {name = '<server>', print = print}
|
|
|
|
local function set_pollution_multiplier(args, player)
|
|
local multiplier = tonumber(args.multiplier)
|
|
player = player or server_player
|
|
|
|
if not multiplier then
|
|
player.print("Fail")
|
|
return
|
|
end
|
|
|
|
local old_multiplier = pollution_multiplier.value
|
|
pollution_multiplier.value = multiplier
|
|
local message = player.name..' changed magic crafter pollution multiplier from '..old_multiplier..' to '..pollution_multiplier.value
|
|
for _, p in pairs(game.players) do
|
|
if p.admin then
|
|
p.print(message)
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_pollution_multiplier(_, player)
|
|
player = player or server_player
|
|
player.print('Current pollution multiplier is: '..pollution_multiplier.value)
|
|
end
|
|
|
|
local function do_magic_crafters()
|
|
local limit = #magic_crafters
|
|
if limit == 0 then
|
|
return
|
|
end
|
|
|
|
local index = magic_crafters.index
|
|
|
|
for i = 1, magic_crafters_per_tick do
|
|
if index > limit then
|
|
index = 1
|
|
end
|
|
|
|
local data = magic_crafters[index]
|
|
|
|
local entity = data.entity
|
|
if not entity.valid then
|
|
fast_remove(magic_crafters, index)
|
|
limit = limit - 1
|
|
if limit == 0 then
|
|
return
|
|
end
|
|
else
|
|
index = index + 1
|
|
|
|
local tick = game.tick
|
|
local last_tick = data.last_tick
|
|
local rate = data.rate
|
|
|
|
local count = (tick - last_tick) * rate
|
|
|
|
local fcount = floor(count)
|
|
|
|
if fcount > 0 then
|
|
local output_inv = entity.get_output_inventory()
|
|
if output_inv.can_insert(data.item) then -- No pollution if full. Taking items out of crafters makes pollution
|
|
local pollution_amount = pollution_multiplier.value * 0.01
|
|
local pollution_position = {0,0}
|
|
entity.surface.pollute(pollution_position, pollution_amount)
|
|
output_inv.insert {name = data.item, count = fcount}
|
|
end
|
|
data.last_tick = tick - (count - fcount) / rate
|
|
end
|
|
end
|
|
end
|
|
|
|
magic_crafters.index = index
|
|
end
|
|
|
|
local function do_magic_fluid_crafters()
|
|
local limit = #magic_fluid_crafters
|
|
|
|
if limit == 0 then
|
|
return
|
|
end
|
|
|
|
local index = magic_fluid_crafters.index
|
|
|
|
for i = 1, magic_fluid_crafters_per_tick do
|
|
if index > limit then
|
|
index = 1
|
|
end
|
|
|
|
local data = magic_fluid_crafters[index]
|
|
|
|
local entity = data.entity
|
|
if not entity.valid then
|
|
fast_remove(magic_fluid_crafters, index)
|
|
limit = limit - 1
|
|
if limit == 0 then
|
|
return
|
|
end
|
|
else
|
|
index = index + 1
|
|
|
|
local tick = game.tick
|
|
local last_tick = data.last_tick
|
|
local rate = data.rate
|
|
|
|
local count = (tick - last_tick) * rate
|
|
|
|
local fcount = floor(count)
|
|
|
|
if fcount > 0 then
|
|
local fluidbox_index = data.fluidbox_index
|
|
local fb = entity.fluidbox
|
|
|
|
local fb_data = fb[fluidbox_index] or {name = data.item, amount = 0}
|
|
fb_data.amount = fb_data.amount + fcount
|
|
fb[fluidbox_index] = fb_data
|
|
|
|
data.last_tick = tick - (count - fcount) / rate
|
|
end
|
|
end
|
|
end
|
|
|
|
magic_fluid_crafters.index = index
|
|
end
|
|
|
|
local function tick()
|
|
do_refill_turrets()
|
|
do_artillery_turrets_targets()
|
|
do_magic_crafters()
|
|
do_magic_fluid_crafters()
|
|
end
|
|
|
|
Public.refill_turret_callback =
|
|
Token.register(
|
|
function(turret, data)
|
|
local outpost_id = data.outpost_id
|
|
|
|
refill_turrets[#refill_turrets + 1] = {turret = turret, data = data.callback_data}
|
|
turret_to_outpost[turret.unit_number] = outpost_id
|
|
|
|
local outpost_data = outposts[outpost_id]
|
|
outpost_data.turret_count = outpost_data.turret_count + 1
|
|
end
|
|
)
|
|
|
|
Public.refill_liquid_turret_callback =
|
|
Token.register(
|
|
function(turret, data)
|
|
local callback_data = data.callback_data
|
|
callback_data.liquid = true
|
|
|
|
local outpost_id = data.outpost_id
|
|
|
|
refill_turrets[#refill_turrets + 1] = {turret = turret, data = callback_data}
|
|
turret_to_outpost[turret.unit_number] = outpost_id
|
|
|
|
local outpost_data = outposts[outpost_id]
|
|
outpost_data.turret_count = outpost_data.turret_count + 1
|
|
end
|
|
)
|
|
|
|
Public.refill_artillery_turret_callback =
|
|
Token.register(
|
|
function(turret, data)
|
|
local outpost_id = data.outpost_id
|
|
|
|
refill_turrets[#refill_turrets + 1] = {turret = turret, data = data.callback_data}
|
|
turret_to_outpost[turret.unit_number] = outpost_id
|
|
|
|
local outpost_data = outposts[outpost_id]
|
|
outpost_data.turret_count = outpost_data.turret_count + 1
|
|
|
|
local artillery_turrets = outpost_data.artillery_turrets
|
|
if not artillery_turrets then
|
|
artillery_turrets = {}
|
|
outpost_data.artillery_turrets = artillery_turrets
|
|
|
|
local pos = turret.position
|
|
local x, y = pos.x, pos.y
|
|
outpost_data.artillery_area = {{x - 112, y - 112}, {x + 112, y + 112}}
|
|
outpost_data.last_fire_tick = 0
|
|
|
|
artillery_outposts[#artillery_outposts + 1] = outpost_data
|
|
end
|
|
|
|
artillery_turrets[#artillery_turrets + 1] = turret
|
|
end
|
|
)
|
|
|
|
Public.power_source_callback =
|
|
Token.register(
|
|
function(turret, data)
|
|
local outpost_id = data.outpost_id
|
|
local callback_data = data.callback_data
|
|
|
|
local power_source =
|
|
turret.surface.create_entity {name = 'hidden-electric-energy-interface', position = turret.position}
|
|
power_source.electric_buffer_size = callback_data.buffer_size
|
|
power_source.power_production = callback_data.power_production
|
|
power_source.destructible = false
|
|
|
|
power_sources[turret.unit_number] = {entity = power_source}
|
|
turret_to_outpost[turret.unit_number] = outpost_id
|
|
|
|
local outpost_data = outposts[outpost_id]
|
|
outpost_data.turret_count = outpost_data.turret_count + 1
|
|
end
|
|
)
|
|
|
|
Public.worm_turret_callback =
|
|
Token.register(
|
|
function(turret, data)
|
|
local outpost_id = data.outpost_id
|
|
|
|
turret_to_outpost[turret.unit_number] = outpost_id
|
|
|
|
local outpost_data = outposts[outpost_id]
|
|
outpost_data.turret_count = outpost_data.turret_count + 1
|
|
end
|
|
)
|
|
|
|
local function add_magic_crafter_output(entity, output, distance, outpost_id)
|
|
local rate = output.min_rate + output.distance_factor * distance
|
|
|
|
local fluidbox_index = output.fluidbox_index
|
|
local data = {
|
|
entity = entity,
|
|
last_tick = game.tick,
|
|
base_rate = rate,
|
|
rate = rate,
|
|
item = output.item,
|
|
fluidbox_index = fluidbox_index
|
|
}
|
|
|
|
if fluidbox_index then
|
|
magic_fluid_crafters[#magic_fluid_crafters + 1] = data
|
|
else
|
|
magic_crafters[#magic_crafters + 1] = data
|
|
end
|
|
|
|
local outpost_magic_crafters = outposts[outpost_id].magic_crafters
|
|
outpost_magic_crafters[#outpost_magic_crafters + 1] = data
|
|
end
|
|
|
|
local set_inactive_token =
|
|
Token.register(
|
|
function(entity)
|
|
if entity.valid then
|
|
entity.active = false
|
|
end
|
|
end
|
|
)
|
|
|
|
local change_to_player_force_callback = Token.register(function(entity)
|
|
if entity.valid then
|
|
entity.force = 'player'
|
|
end
|
|
end)
|
|
|
|
Public.magic_item_crafting_callback =
|
|
Token.register(
|
|
function(entity, data)
|
|
local outpost_id = data.outpost_id
|
|
local callback_data = data.callback_data
|
|
|
|
entity.minable = false
|
|
entity.destructible = false
|
|
entity.operable = false
|
|
|
|
-- This is so the recipe is set for furnaces even if the player force hasn't unlocked them yet.
|
|
entity.force = 'neutral'
|
|
Task.set_timeout_in_ticks(1, change_to_player_force_callback, entity)
|
|
|
|
local recipe = callback_data.recipe
|
|
if recipe then
|
|
entity.set_recipe(recipe)
|
|
if not callback_data.has_fluid_output then -- to avoid trying to put an item into a fluid inventory
|
|
entity.get_output_inventory().insert(callback_data.output.item)
|
|
end
|
|
else
|
|
local furnace_item = callback_data.furnace_item
|
|
if furnace_item then
|
|
local inv = entity.get_inventory(2) -- defines.inventory.furnace_source
|
|
inv.insert(furnace_item)
|
|
entity.get_output_inventory().insert(callback_data.output.item)
|
|
end
|
|
end
|
|
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local distance = math.sqrt(x * x + y * y)
|
|
|
|
local output = callback_data.output
|
|
if #output == 0 then
|
|
add_magic_crafter_output(entity, output, distance, outpost_id)
|
|
else
|
|
for i = 1, #output do
|
|
local o = output[i]
|
|
add_magic_crafter_output(entity, o, distance, outpost_id)
|
|
end
|
|
end
|
|
|
|
if not callback_data.has_fluid_output then
|
|
Task.set_timeout_in_ticks(2, set_inactive_token, entity) -- causes problems with refineries.
|
|
end
|
|
end
|
|
)
|
|
|
|
Public.magic_item_crafting_callback_weighted =
|
|
Token.register(
|
|
function(entity, data)
|
|
local outpost_id = data.outpost_id
|
|
local callback_data = data.callback_data
|
|
|
|
entity.minable = false
|
|
entity.destructible = false
|
|
entity.operable = false
|
|
|
|
-- This is so the recipe is set for furnaces even if the player force hasn't unlocked them yet.
|
|
entity.force = 'neutral'
|
|
Task.set_timeout_in_ticks(1, change_to_player_force_callback, entity)
|
|
|
|
local weights = callback_data.weights
|
|
local loot = callback_data.loot
|
|
|
|
local i = math.random() * weights.total
|
|
|
|
local index = table.binary_search(weights, i)
|
|
if (index < 0) then
|
|
index = bit32.bnot(index)
|
|
end
|
|
|
|
local stack = loot[index].stack
|
|
if not stack then
|
|
return
|
|
end
|
|
|
|
local recipe = stack.recipe
|
|
if recipe then
|
|
entity.set_recipe(recipe)
|
|
local output_inv = entity.get_output_inventory()
|
|
output_inv.insert {name = stack.output.item, count = 200}
|
|
else
|
|
local furnace_item = stack.furnace_item
|
|
if furnace_item then
|
|
local inv = entity.get_inventory(2) -- defines.inventory.furnace_source
|
|
inv.insert {name = furnace_item, count = 200}
|
|
local output_inv = entity.get_output_inventory()
|
|
output_inv.insert {name = stack.output.item, count = 200 }
|
|
end
|
|
end
|
|
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local distance = math.sqrt(x * x + y * y)
|
|
|
|
local output = stack.output
|
|
if #output == 0 then
|
|
add_magic_crafter_output(entity, output, distance, outpost_id)
|
|
else
|
|
for o_i = 1, #output do
|
|
local o = output[o_i]
|
|
add_magic_crafter_output(entity, o, distance, outpost_id)
|
|
end
|
|
end
|
|
|
|
if not callback_data.has_fluid_output then
|
|
Task.set_timeout_in_ticks(2, set_inactive_token, entity) -- causes problems with refineries.
|
|
end
|
|
end
|
|
)
|
|
|
|
Public.wall_callback =
|
|
Token.register(
|
|
function(entity, data)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
local position = entity.position
|
|
local px, py = position.x, position.y
|
|
|
|
local outpost_id = data.outpost_id
|
|
local outpost_data = outposts[outpost_id]
|
|
local top_left = outpost_data.top_left
|
|
local bottom_right = outpost_data.bottom_right
|
|
local tx, ty = top_left.x, top_left.y
|
|
local bx, by = bottom_right.x, bottom_right.y
|
|
|
|
if not tx or px < tx then
|
|
top_left.x = px
|
|
end
|
|
if not ty or py < ty then
|
|
top_left.y = py
|
|
end
|
|
|
|
if not bx or px > bx then
|
|
bottom_right.x = px
|
|
end
|
|
if not by or py > by then
|
|
bottom_right.y = py
|
|
end
|
|
end
|
|
)
|
|
|
|
Public.deactivate_callback =
|
|
Token.register(
|
|
function(entity)
|
|
entity.active = false
|
|
entity.operable = false
|
|
entity.destructible = false
|
|
end
|
|
)
|
|
|
|
|
|
Public.scenario_chest_callback = Token.register(function(chest)
|
|
if not chest or not chest.valid then
|
|
return
|
|
end
|
|
|
|
chest.destructible = false
|
|
chest.minable = false
|
|
end)
|
|
|
|
local function turret_died(event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid then
|
|
return
|
|
end
|
|
|
|
local number = entity.unit_number
|
|
if not number then
|
|
return
|
|
end
|
|
|
|
local ps_data = power_sources[number]
|
|
if ps_data then
|
|
power_sources[number] = nil
|
|
|
|
local ps_entity = ps_data.entity
|
|
|
|
if ps_entity and ps_entity.valid then
|
|
ps_entity.destroy()
|
|
end
|
|
end
|
|
|
|
local outpost_id = turret_to_outpost[number]
|
|
if outpost_id then
|
|
local outpost_data = outposts[outpost_id]
|
|
|
|
local turret_count = outpost_data.turret_count - 1
|
|
outpost_data.turret_count = turret_count
|
|
|
|
if turret_count == 0 then
|
|
do_capture_outpost(outpost_data)
|
|
end
|
|
end
|
|
end
|
|
|
|
Public.market_set_items_callback =
|
|
Token.register(
|
|
function(entity, data)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
local callback_data = data.callback_data
|
|
|
|
entity.destructible = false
|
|
|
|
local market_id = data.outpost_id
|
|
local outpost_data = outposts[market_id]
|
|
local upgrade_base_cost = callback_data.upgrade_base_cost or 0
|
|
|
|
outpost_data.market = entity
|
|
outpost_data.upgrade_rate = callback_data.upgrade_rate
|
|
outpost_data.upgrade_base_cost = upgrade_base_cost
|
|
outpost_data.upgrade_cost_base = callback_data.upgrade_cost_base
|
|
|
|
Retailer.add_market(market_id, entity)
|
|
Retailer.set_market_group_label(market_id, callback_data.market_name)
|
|
|
|
Retailer.set_item(
|
|
market_id,
|
|
{
|
|
name = 'upgrade',
|
|
type = 'upgrade',
|
|
name_label = 'Upgrade Outpost',
|
|
sprite = 'item-group/production',
|
|
price = 0,
|
|
stack_limit = 1,
|
|
disabled = true,
|
|
disabled_reason = 'Outpost must be captured first.',
|
|
description = 'Increases output.'
|
|
}
|
|
)
|
|
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local d = math.sqrt(x * x + y * y)
|
|
|
|
for i = 1, #callback_data do
|
|
local item = callback_data[i]
|
|
local price = item.price
|
|
|
|
local df = item.distance_factor
|
|
if df then
|
|
local min_price = item.min_price or 1
|
|
|
|
price = item.price - d * df
|
|
price = math.max(price, min_price)
|
|
end
|
|
|
|
Retailer.set_item(
|
|
market_id,
|
|
{
|
|
name = item.name,
|
|
type = item.type,
|
|
price = price,
|
|
stack_limit = item.stack_limit,
|
|
name_label = item.name_label,
|
|
sprite = item.sprite,
|
|
disabled = item.disabled,
|
|
disabled_reason = item.disabled_reason,
|
|
description = item.description}
|
|
)
|
|
end
|
|
end
|
|
)
|
|
|
|
Public.firearm_magazine_ammo = {name = 'firearm-magazine', count = 200}
|
|
Public.piercing_rounds_magazine_ammo = {name = 'piercing-rounds-magazine', count = 200}
|
|
Public.uranium_rounds_magazine_ammo = {name = 'uranium-rounds-magazine', count = 200}
|
|
Public.artillery_shell_ammo = {name = 'artillery-shell', count = 15}
|
|
Public.light_oil_ammo = {name = 'light-oil', amount = 100}
|
|
|
|
Public.laser_turrent_power_source = {buffer_size = 2400000, power_production = 40000}
|
|
|
|
function Public.prepare_weighted_loot(loot)
|
|
local total = 0
|
|
local weights = {}
|
|
|
|
for i = 1, #loot do
|
|
local v = loot[i]
|
|
total = total + v.weight
|
|
weights[#weights + 1] = total
|
|
end
|
|
|
|
weights.total = total
|
|
|
|
return weights
|
|
end
|
|
|
|
function Public.do_random_loot(entity, weights, loot)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
entity.operable = false
|
|
--entity.destructible = false
|
|
|
|
local i = math.random() * weights.total
|
|
|
|
local index = table.binary_search(weights, i)
|
|
if (index < 0) then
|
|
index = bit32.bnot(index)
|
|
end
|
|
|
|
local stack = loot[index].stack
|
|
if not stack then
|
|
return
|
|
end
|
|
|
|
local df = stack.distance_factor
|
|
local count
|
|
if df then
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local d = math.sqrt(x * x + y * y)
|
|
|
|
count = stack.count + d * df
|
|
else
|
|
count = stack.count
|
|
end
|
|
|
|
entity.insert {name = stack.name, count = count}
|
|
end
|
|
|
|
function Public.do_random_fluid_loot(entity, weights, loot)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
entity.operable = false
|
|
entity.destructible = false
|
|
entity.force = 'player'
|
|
|
|
local i = math.random() * weights.total
|
|
|
|
local index = table.binary_search(weights, i)
|
|
if (index < 0) then
|
|
index = bit32.bnot(index)
|
|
end
|
|
|
|
local stack = loot[index].stack
|
|
if not stack then
|
|
return
|
|
end
|
|
|
|
local df = stack.distance_factor
|
|
local count
|
|
if df then
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local d = math.sqrt(x * x + y * y)
|
|
|
|
count = stack.count + d * df
|
|
else
|
|
count = stack.count
|
|
end
|
|
|
|
entity.fluidbox[1] = {name = stack.name, amount = count}
|
|
end
|
|
|
|
function Public.do_factory_loot(entity, weights, loot)
|
|
if not entity.valid then
|
|
return
|
|
end
|
|
|
|
entity.operable = false
|
|
entity.destructible = false
|
|
entity.force = 'player'
|
|
|
|
local i = math.random() * weights.total
|
|
|
|
local index = table.binary_search(weights, i)
|
|
if (index < 0) then
|
|
index = bit32.bnot(index)
|
|
end
|
|
|
|
local stack = loot[index].stack
|
|
if not stack then
|
|
return
|
|
end
|
|
|
|
local df = stack.distance_factor
|
|
local count
|
|
if df then
|
|
local p = entity.position
|
|
local x, y = p.x, p.y
|
|
local d = math.sqrt(x * x + y * y)
|
|
|
|
count = stack.count + d * df
|
|
else
|
|
count = stack.count
|
|
end
|
|
|
|
local name = stack.name
|
|
|
|
entity.set_recipe(name)
|
|
entity.get_output_inventory().insert {name = name, count = count}
|
|
end
|
|
|
|
local function market_selected(event)
|
|
local player = game.get_player(event.player_index)
|
|
if not player or not player.valid then
|
|
return
|
|
end
|
|
|
|
if player.render_mode == render_mode_game then
|
|
return
|
|
end
|
|
|
|
local selected = player.selected
|
|
|
|
if not selected or not selected.valid or selected.name ~= 'market' then
|
|
return
|
|
end
|
|
|
|
local group = Retailer.get_market_group_name(selected)
|
|
local prototype = Retailer.get_items(group)['upgrade']
|
|
|
|
if prototype.disabled then
|
|
return
|
|
end
|
|
|
|
local args = {
|
|
text = nil,
|
|
target = selected,
|
|
target_offset = nil,
|
|
alignment = 'center',
|
|
surface = selected.surface,
|
|
color = {1, 1, 1},
|
|
players = {player},
|
|
scale = 1.5,
|
|
scale_with_zoom = true,
|
|
time_to_live = 180
|
|
}
|
|
|
|
args.text = prototype.name_label
|
|
args.target_offset = {0, -6.5}
|
|
draw_text(args)
|
|
|
|
args.text = 'Price: ' .. prototype.price
|
|
args.target_offset = {0, -5}
|
|
draw_text(args)
|
|
|
|
args.text = prototype.mapview_description
|
|
args.target_offset = {0, -3.5}
|
|
draw_text(args)
|
|
end
|
|
|
|
Event.add(defines.events.on_tick, tick)
|
|
Event.add(defines.events.on_entity_died, turret_died)
|
|
|
|
Event.on_init(
|
|
function()
|
|
game.forces.neutral.recipes['steel-plate'].enabled = true
|
|
end
|
|
)
|
|
|
|
Event.add(Retailer.events.on_market_purchase, do_outpost_upgrade)
|
|
|
|
Event.add(defines.events.on_selected_entity_changed, market_selected)
|
|
|
|
Command.add(
|
|
'set-pollution-multiplier',
|
|
{
|
|
description = {'command_description.set_pollution_multiplier'},
|
|
arguments = {'multiplier'},
|
|
required_rank = Ranks.admin,
|
|
capture_excess_arguments = true,
|
|
allowed_by_server = true
|
|
},
|
|
set_pollution_multiplier
|
|
)
|
|
|
|
Command.add(
|
|
'get-pollution-multiplier',
|
|
{
|
|
description = {'command_description.get_pollution_multiplier'},
|
|
required_rank = Ranks.guest,
|
|
capture_excess_arguments = true,
|
|
allowed_by_server = true
|
|
},
|
|
get_pollution_multiplier
|
|
)
|
|
|
|
return Public
|